From 250f4ec3dddca92853463ec291d786ded4a06ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Feb 2020 14:00:41 +0100 Subject: [PATCH 001/453] [apps/statistics] Clean code --- apps/statistics/histogram_controller.cpp | 25 ++++--- apps/statistics/histogram_controller.h | 2 +- .../histogram_parameter_controller.cpp | 68 ++++++++++--------- apps/statistics/store.cpp | 4 +- 4 files changed, 53 insertions(+), 46 deletions(-) diff --git a/apps/statistics/histogram_controller.cpp b/apps/statistics/histogram_controller.cpp index 42d5c52a3..e4f762bf1 100644 --- a/apps/statistics/histogram_controller.cpp +++ b/apps/statistics/histogram_controller.cpp @@ -180,31 +180,33 @@ bool HistogramController::moveSelectionHorizontally(int deltaIndex) { return false; } -void HistogramController::preinitXRangeParameters() { +void HistogramController::preinitXRangeParameters(double * xMin) { /* Compute m_store's min and max values, hold them temporarily in the * CurveViewRange, for later use by initRangeParameters and * initBarParameters. Indeed, initRangeParameters will anyway alter the * CurveViewRange. The CurveViewRange setter methods take care of the case * where minValue >= maxValue. Moreover they compute the xGridUnit, which is * used by initBarParameters. */ - float minValue = FLT_MAX; - float maxValue = -FLT_MAX; + double minValue = DBL_MAX; + double maxValue = -DBL_MAX; for (int i = 0; i < Store::k_numberOfSeries; i ++) { if (!m_store->seriesIsEmpty(i)) { - minValue = std::min(minValue, m_store->minValue(i)); - maxValue = std::max(maxValue, m_store->maxValue(i)); + minValue = std::min(minValue, m_store->minValue(i)); + maxValue = std::max(maxValue, m_store->maxValue(i)); } } + assert(xMin != nullptr); + *xMin = minValue; m_store->setXMin(minValue); m_store->setXMax(maxValue); } void HistogramController::initRangeParameters() { assert(selectedSeriesIndex() >= 0 && m_store->sumOfOccurrences(selectedSeriesIndex()) > 0); - float barWidth = m_store->barWidth(); - preinitXRangeParameters(); - float xMin = m_store->firstDrawnBarAbscissa(); - float xMax = m_store->xMax() + barWidth; + double barWidth = m_store->barWidth(); + double xMin; + preinitXRangeParameters(&xMin); + double xMax = m_store->xMax() + barWidth; /* if a bar is represented by less than one pixel, we cap xMax */ if ((xMax - xMin)/barWidth > k_maxNumberOfBarsPerWindow) { xMax = xMin + k_maxNumberOfBarsPerWindow*barWidth; @@ -244,8 +246,9 @@ void HistogramController::initYRangeParameters(int series) { void HistogramController::initBarParameters() { assert(selectedSeriesIndex() >= 0 && m_store->sumOfOccurrences(selectedSeriesIndex()) > 0); - preinitXRangeParameters(); - m_store->setFirstDrawnBarAbscissa(m_store->xMin()); + double xMin; + preinitXRangeParameters(&xMin); + m_store->setFirstDrawnBarAbscissa(xMin); double barWidth = m_store->xGridUnit(); if (barWidth <= 0.0) { barWidth = 1.0; diff --git a/apps/statistics/histogram_controller.h b/apps/statistics/histogram_controller.h index a64006a3d..813964345 100644 --- a/apps/statistics/histogram_controller.h +++ b/apps/statistics/histogram_controller.h @@ -34,7 +34,7 @@ private: void highlightSelection() override; Responder * tabController() const override; void reloadBannerView() override; - void preinitXRangeParameters(); + void preinitXRangeParameters(double * xMin); void initRangeParameters(); void initYRangeParameters(int series); void initBarParameters(); diff --git a/apps/statistics/histogram_parameter_controller.cpp b/apps/statistics/histogram_parameter_controller.cpp index 6e58a2d8e..5fb02e7b7 100644 --- a/apps/statistics/histogram_parameter_controller.cpp +++ b/apps/statistics/histogram_parameter_controller.cpp @@ -37,18 +37,20 @@ double HistogramParameterController::parameterAtIndex(int index) { return index == 0 ? m_store->barWidth() : m_store->firstDrawnBarAbscissa(); } -bool HistogramParameterController::setParameterAtIndex(int parameterIndex, double f) { +bool HistogramParameterController::setParameterAtIndex(int parameterIndex, double value) { assert(parameterIndex >= 0 && parameterIndex < k_numberOfCells); if (parameterIndex == 0) { + // Bar width + // The bar width cannot be negative - if (f <= 0.0f) { + if (value <= 0.0) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } // There should be at least one value in the drawn bin for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { - if (m_store->firstDrawnBarAbscissa() <= m_store->maxValue(i)+f) { + if (m_store->firstDrawnBarAbscissa() <= m_store->maxValue(i)+value) { break; } else if (i == DoublePairStore::k_numberOfSeries - 1) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); @@ -58,9 +60,9 @@ bool HistogramParameterController::setParameterAtIndex(int parameterIndex, doubl // The number of bars cannot be above the max assert(DoublePairStore::k_numberOfSeries > 0); - double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - m_store->minValue(0))/f); + double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - m_store->minValue(0))/value); for (int i = 1; i < DoublePairStore::k_numberOfSeries; i++) { - double numberOfBars = std::ceil((m_store->maxValue(i) - m_store->minValue(i))/f); + double numberOfBars = std::ceil((m_store->maxValue(i) - m_store->minValue(i))/value); if (maxNewNumberOfBars < numberOfBars) { maxNewNumberOfBars = numberOfBars; } @@ -71,34 +73,36 @@ bool HistogramParameterController::setParameterAtIndex(int parameterIndex, doubl } // Set the bar width - m_store->setBarWidth(f); - } else { - // The number of bars cannot be above the max - assert(DoublePairStore::k_numberOfSeries > 0); - double maxNewNumberOfBars = ceilf((m_store->maxValue(0) - f)/m_store->barWidth()); - for (int i = 1; i < DoublePairStore::k_numberOfSeries; i++) { - double numberOfBars = ceilf((m_store->maxValue(i) - f)/m_store->barWidth()); - if (maxNewNumberOfBars < numberOfBars) { - maxNewNumberOfBars = numberOfBars; - } - } - if (maxNewNumberOfBars > Store::k_maxNumberOfBars) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } - // There should be at least one value in the drawn bin - for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { - if (f <= m_store->maxValue(i)+m_store->barWidth()) { - break; - } else if (i == DoublePairStore::k_numberOfSeries - 1) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } - } - // Set the first drawn bar abscissa - m_store->setFirstDrawnBarAbscissa(f); + m_store->setBarWidth(value); + return true; } - return true; + assert(parameterIndex == 1); + // The number of bars cannot be above the max + assert(DoublePairStore::k_numberOfSeries > 0); + const double barWidth = m_store->barWidth(); + double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - value)/barWidth); + for (int i = 1; i < DoublePairStore::k_numberOfSeries; i++) { + double numberOfBars = std::ceil((m_store->maxValue(i) - value)/barWidth); + if (maxNewNumberOfBars < numberOfBars) { + maxNewNumberOfBars = numberOfBars; + } + } + if (maxNewNumberOfBars > Store::k_maxNumberOfBars) { + Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); + return false; + } + // There should be at least one value in the drawn bin + for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { + if (value <= m_store->maxValue(i) + barWidth) { + break; + } else if (i == DoublePairStore::k_numberOfSeries - 1) { + Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); + return false; + } + } + // Set the first drawn bar abscissa + m_store->setFirstDrawnBarAbscissa(value); + return true; } HighlightCell * HistogramParameterController::reusableParameterCell(int index, int type) { diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index dd9e07b6d..e7d6aec32 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -43,8 +43,8 @@ double Store::heightOfBarAtIndex(int series, int index) const { double Store::heightOfBarAtValue(int series, double value) const { double width = barWidth(); int barNumber = std::floor((value - m_firstDrawnBarAbscissa)/width); - double lowerBound = m_firstDrawnBarAbscissa + barNumber*width; - double upperBound = m_firstDrawnBarAbscissa + (barNumber+1)*width; + double lowerBound = m_firstDrawnBarAbscissa + ((double)barNumber)*width; + double upperBound = m_firstDrawnBarAbscissa + ((double)(barNumber+1))*width; return sumOfValuesBetween(series, lowerBound, upperBound); } From 59aea9ca8355d69a828508e22128931cfefe9cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Feb 2020 14:24:54 +0100 Subject: [PATCH 002/453] [apps/statistics] Factorize HistogramParamCtrlr::setParamAtIdx --- .../histogram_parameter_controller.cpp | 80 +++++++------------ apps/statistics/store.cpp | 5 +- 2 files changed, 32 insertions(+), 53 deletions(-) diff --git a/apps/statistics/histogram_parameter_controller.cpp b/apps/statistics/histogram_parameter_controller.cpp index 5fb02e7b7..0f932299e 100644 --- a/apps/statistics/histogram_parameter_controller.cpp +++ b/apps/statistics/histogram_parameter_controller.cpp @@ -38,71 +38,51 @@ double HistogramParameterController::parameterAtIndex(int index) { } bool HistogramParameterController::setParameterAtIndex(int parameterIndex, double value) { - assert(parameterIndex >= 0 && parameterIndex < k_numberOfCells); - if (parameterIndex == 0) { - // Bar width + assert(parameterIndex == 0 || parameterIndex == 1); + const bool setBarWidth = parameterIndex == 0; + if (setBarWidth && value <= 0.0) { // The bar width cannot be negative - if (value <= 0.0) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } + Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); + return false; + } + const double nextFirstDrawnBarAbscissa = setBarWidth ? m_store->firstDrawnBarAbscissa() : value; + const double nextBarWidth = setBarWidth ? value : m_store->barWidth(); + + { // There should be at least one value in the drawn bin + bool foundOneDrawnValue = false; for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { - if (m_store->firstDrawnBarAbscissa() <= m_store->maxValue(i)+value) { + if (nextFirstDrawnBarAbscissa <= m_store->maxValue(i) + nextBarWidth) { + foundOneDrawnValue = true; break; - } else if (i == DoublePairStore::k_numberOfSeries - 1) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; } } - - // The number of bars cannot be above the max - assert(DoublePairStore::k_numberOfSeries > 0); - double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - m_store->minValue(0))/value); - for (int i = 1; i < DoublePairStore::k_numberOfSeries; i++) { - double numberOfBars = std::ceil((m_store->maxValue(i) - m_store->minValue(i))/value); - if (maxNewNumberOfBars < numberOfBars) { - maxNewNumberOfBars = numberOfBars; - } - } - if (maxNewNumberOfBars > Store::k_maxNumberOfBars) { + if (!foundOneDrawnValue) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } + } + // The number of bars cannot be above the max + assert(DoublePairStore::k_numberOfSeries > 0); + for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { + const double min = setBarWidth ? m_store->minValue(i) : nextFirstDrawnBarAbscissa; + double numberOfBars = std::ceil((m_store->maxValue(i) - min)/nextBarWidth); + if (numberOfBars > Store::k_maxNumberOfBars) { + Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); + return false; + } + } + + if (setBarWidth) { // Set the bar width m_store->setBarWidth(value); - return true; + } else { + m_store->setFirstDrawnBarAbscissa(value); } - assert(parameterIndex == 1); - // The number of bars cannot be above the max - assert(DoublePairStore::k_numberOfSeries > 0); - const double barWidth = m_store->barWidth(); - double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - value)/barWidth); - for (int i = 1; i < DoublePairStore::k_numberOfSeries; i++) { - double numberOfBars = std::ceil((m_store->maxValue(i) - value)/barWidth); - if (maxNewNumberOfBars < numberOfBars) { - maxNewNumberOfBars = numberOfBars; - } - } - if (maxNewNumberOfBars > Store::k_maxNumberOfBars) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } - // There should be at least one value in the drawn bin - for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { - if (value <= m_store->maxValue(i) + barWidth) { - break; - } else if (i == DoublePairStore::k_numberOfSeries - 1) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } - } - // Set the first drawn bar abscissa - m_store->setFirstDrawnBarAbscissa(value); - return true; + return true; } HighlightCell * HistogramParameterController::reusableParameterCell(int index, int type) { diff --git a/apps/statistics/store.cpp b/apps/statistics/store.cpp index e7d6aec32..059467a97 100644 --- a/apps/statistics/store.cpp +++ b/apps/statistics/store.cpp @@ -31,9 +31,8 @@ uint32_t Store::barChecksum() const { /* Histogram bars */ void Store::setBarWidth(double barWidth) { - if (barWidth > 0.0) { - m_barWidth = barWidth; - } + assert(barWidth > 0.0); + m_barWidth = barWidth; } double Store::heightOfBarAtIndex(int series, int index) const { From 51b5edbe69189940006347a516196c26e6e2ce07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Feb 2020 14:26:19 +0100 Subject: [PATCH 003/453] [apps/statistics] Remove too strict condition One could not set the bin with / x start to a value that would not show any data -> The condition was asymetrical, as nextFirstDrawnBarAbscissa could not be higher to the biggest data, but could have been too small to display any data -> We restricted the user --- .../statistics/histogram_parameter_controller.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/apps/statistics/histogram_parameter_controller.cpp b/apps/statistics/histogram_parameter_controller.cpp index 0f932299e..c9e3a8b45 100644 --- a/apps/statistics/histogram_parameter_controller.cpp +++ b/apps/statistics/histogram_parameter_controller.cpp @@ -50,21 +50,6 @@ bool HistogramParameterController::setParameterAtIndex(int parameterIndex, doubl const double nextFirstDrawnBarAbscissa = setBarWidth ? m_store->firstDrawnBarAbscissa() : value; const double nextBarWidth = setBarWidth ? value : m_store->barWidth(); - { - // There should be at least one value in the drawn bin - bool foundOneDrawnValue = false; - for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { - if (nextFirstDrawnBarAbscissa <= m_store->maxValue(i) + nextBarWidth) { - foundOneDrawnValue = true; - break; - } - } - if (!foundOneDrawnValue) { - Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); - return false; - } - } - // The number of bars cannot be above the max assert(DoublePairStore::k_numberOfSeries > 0); for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { From ed753b793be6b8a60f4be3d9f04c35e92aace734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Feb 2020 15:12:16 +0100 Subject: [PATCH 004/453] [apps/statistics] Do not initRangeParameters too often --- apps/statistics/histogram_controller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/statistics/histogram_controller.cpp b/apps/statistics/histogram_controller.cpp index e4f762bf1..47638f57a 100644 --- a/apps/statistics/histogram_controller.cpp +++ b/apps/statistics/histogram_controller.cpp @@ -50,15 +50,19 @@ bool HistogramController::handleEvent(Ion::Events::Event event) { void HistogramController::viewWillAppear() { MultipleDataViewController::viewWillAppear(); uint32_t storeChecksum = m_store->storeChecksum(); + bool initedRangeParameters = false; if (*m_storeVersion != storeChecksum) { *m_storeVersion = storeChecksum; initBarParameters(); initRangeParameters(); + initedRangeParameters = true; } uint32_t barChecksum = m_store->barChecksum(); if (*m_barVersion != barChecksum) { *m_barVersion = barChecksum; - initRangeParameters(); + if (!initedRangeParameters) { + initRangeParameters(); + } } uint32_t rangeChecksum = m_store->rangeChecksum(); if (*m_rangeVersion != rangeChecksum) { From 068ed96d79d175831b1fc8fac59ca4931bab82b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 10 Feb 2020 16:26:20 +0100 Subject: [PATCH 005/453] [apps/range_1D] Add comment abour k_minFloat --- apps/shared/range_1D.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/shared/range_1D.h b/apps/shared/range_1D.h index a528540f0..1557e82b6 100644 --- a/apps/shared/range_1D.h +++ b/apps/shared/range_1D.h @@ -16,6 +16,8 @@ namespace Shared { class __attribute__((packed)) Range1D final { public: + /* If m_min and m_max are too close, we cannot divide properly the range by + * the number of pixels, which creates a drawing problem. */ constexpr static float k_minFloat = 1E-4f; constexpr static float k_default = 10.0f; Range1D(float min = -k_default, float max = k_default) : From bc0b21463ee291fd0fc6d6203586d24e55b566d0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 14 Feb 2020 16:32:21 +0100 Subject: [PATCH 006/453] [quiz][ion/test] Move time measurements to quiz to be able to do measurements in any test --- ion/test/device/n0110/Makefile | 2 - .../device/n0110/external_flash_helper.cpp | 26 ------------- ion/test/device/n0110/external_flash_helper.h | 3 -- ion/test/device/n0110/external_flash_read.cpp | 39 +++++++++---------- .../device/n0110/external_flash_write.cpp | 11 +++--- quiz/Makefile | 1 + quiz/include/quiz/stopwatch.h | 17 ++++++++ quiz/src/runner.cpp | 2 - quiz/src/stopwatch.cpp | 36 +++++++++++++++++ 9 files changed, 78 insertions(+), 59 deletions(-) delete mode 100644 ion/test/device/n0110/external_flash_helper.cpp create mode 100644 quiz/include/quiz/stopwatch.h create mode 100644 quiz/src/stopwatch.cpp diff --git a/ion/test/device/n0110/Makefile b/ion/test/device/n0110/Makefile index 3acf290d9..d379f0fb2 100644 --- a/ion/test/device/n0110/Makefile +++ b/ion/test/device/n0110/Makefile @@ -1,10 +1,8 @@ test_ion_external_flash_read_src += $(addprefix ion/test/$(PLATFORM)/$(MODEL)/, \ - external_flash_helper.cpp \ external_flash_read.cpp \ ) test_ion_external_flash_write_src += $(addprefix ion/test/$(PLATFORM)/$(MODEL)/, \ - external_flash_helper.cpp \ external_flash_write.cpp \ ) diff --git a/ion/test/device/n0110/external_flash_helper.cpp b/ion/test/device/n0110/external_flash_helper.cpp deleted file mode 100644 index 11d776784..000000000 --- a/ion/test/device/n0110/external_flash_helper.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ion/include/ion/timing.h" -#include -#include - -size_t uint64ToString(uint64_t n, char buffer[]) { - size_t len = 0; - do { - buffer[len++] = (n % 10) + '0'; - } while ((n /= 10) > 0); - int i = 0; - int j = len - 1; - while (i < j) { - char c = buffer[i]; - buffer[i++] = buffer[j]; - buffer[j--] = c; - } - return len; -} - -void printElapsedTime(uint64_t startTime) { - char buffer[7+26+2] = " time: "; - size_t len = uint64ToString((Ion::Timing::millis() - startTime)/1000, buffer+7); - buffer[7+len] = 's'; - buffer[7+len+1] = 0; - quiz_print(buffer); -} diff --git a/ion/test/device/n0110/external_flash_helper.h b/ion/test/device/n0110/external_flash_helper.h index de84d3d0d..11350ce9b 100644 --- a/ion/test/device/n0110/external_flash_helper.h +++ b/ion/test/device/n0110/external_flash_helper.h @@ -17,6 +17,3 @@ inline uint32_t expected_value_at(uint32_t * ptr) { uint16_t * ptr16 = reinterpret_cast(ptr); return (static_cast(expected_value_at(ptr16+1)) << 16) + static_cast(expected_value_at(ptr16)); } - -size_t uint64ToString(uint64_t n, char buffer[]); -void printElapsedTime(uint64_t startTime); diff --git a/ion/test/device/n0110/external_flash_read.cpp b/ion/test/device/n0110/external_flash_read.cpp index 3b234f14c..4a2417c6e 100644 --- a/ion/test/device/n0110/external_flash_read.cpp +++ b/ion/test/device/n0110/external_flash_read.cpp @@ -1,7 +1,6 @@ #include +#include #include -#include -#include #include #include "external_flash_helper.h" @@ -47,56 +46,56 @@ void test(int accessType, int repeat) { } QUIZ_CASE(ion_extflash_read_byte_fwd) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(0, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_byte_bck) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(1, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_byte_rand) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(2, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_half_fwd) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(0, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_half_bck) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(1, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_half_rand) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(2, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_word_fwd) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(0, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_word_bck) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(1, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_extflash_read_word_rand) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); test(2, 1); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); Ion::Timing::msleep(3000); } diff --git a/ion/test/device/n0110/external_flash_write.cpp b/ion/test/device/n0110/external_flash_write.cpp index 0585abd96..a9097117a 100644 --- a/ion/test/device/n0110/external_flash_write.cpp +++ b/ion/test/device/n0110/external_flash_write.cpp @@ -1,20 +1,19 @@ #include -#include +#include #include -#include "ion/include/ion/timing.h" #include "external_flash_helper.h" // Choose some not too uniform data to program the external flash memory with. QUIZ_CASE(ion_ext_flash_erase) { - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); Ion::Device::ExternalFlash::MassErase(); - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } QUIZ_CASE(ion_ext_flash_program) { // Program separately each page of the flash memory - uint64_t startTime = Ion::Timing::millis(); + uint64_t startTime = quiz_stopwatch_start(); for (int page = 0; page < (1<<15); page++) { uint8_t buffer[256]; for (int byte = 0; byte < 256; byte++) { @@ -22,5 +21,5 @@ QUIZ_CASE(ion_ext_flash_program) { } Ion::Device::ExternalFlash::WriteMemory(reinterpret_cast(page * 256), buffer, 256); } - printElapsedTime(startTime); + quiz_stopwatch_print_lap(startTime); } diff --git a/quiz/Makefile b/quiz/Makefile index 25ddd96b1..10ffb7e9f 100644 --- a/quiz/Makefile +++ b/quiz/Makefile @@ -14,6 +14,7 @@ runner_src += $(addprefix quiz/src/, \ assertions.cpp \ i18n.cpp \ runner.cpp \ + stopwatch.cpp \ ) runner_src += $(BUILD_DIR)/quiz/src/tests_symbols.c diff --git a/quiz/include/quiz/stopwatch.h b/quiz/include/quiz/stopwatch.h new file mode 100644 index 000000000..53a582b08 --- /dev/null +++ b/quiz/include/quiz/stopwatch.h @@ -0,0 +1,17 @@ +#ifndef QUIZ_STOPWATCH_H +#define QUIZ_STOPWATCH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint64_t quiz_stopwatch_start(); +void quiz_stopwatch_print_lap(uint64_t startTime); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/quiz/src/runner.cpp b/quiz/src/runner.cpp index dae22605a..ef4b883c3 100644 --- a/quiz/src/runner.cpp +++ b/quiz/src/runner.cpp @@ -1,8 +1,6 @@ #include "quiz.h" #include "symbols.h" -#include #include -#include #include #include #include diff --git a/quiz/src/stopwatch.cpp b/quiz/src/stopwatch.cpp new file mode 100644 index 000000000..f4dafac16 --- /dev/null +++ b/quiz/src/stopwatch.cpp @@ -0,0 +1,36 @@ +#include +#include "quiz.h" +#include +#include + +uint64_t quiz_stopwatch_start() { + return Ion::Timing::millis(); +} + +static size_t uint64ToString(uint64_t n, char buffer[]) { + size_t len = 0; + do { + buffer[len++] = (n % 10) + '0'; + } while ((n /= 10) > 0); + int i = 0; + int j = len - 1; + while (i < j) { + char c = buffer[i]; + buffer[i++] = buffer[j]; + buffer[j--] = c; + } + return len; +} + +void quiz_stopwatch_print_lap(uint64_t startTime) { + constexpr char Time[] = " time: "; + constexpr char Ms[] = "ms"; + constexpr size_t uint64ToStringMaxLength = 20; + constexpr size_t MaxLength = sizeof(Time) + uint64ToStringMaxLength + sizeof(Ms) + 1; + char buffer[MaxLength]; + char * position = buffer; + position += strlcpy(position, Time, sizeof(Time)); + position += uint64ToString(Ion::Timing::millis() - startTime, position); + position += strlcpy(position, Ms, sizeof(Ms)); + quiz_print(buffer); +} From f01f91d0000b42e5024a719655b5094027a364e8 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 11 Feb 2020 14:14:27 +0100 Subject: [PATCH 007/453] [poincare/unit] Clean serialize The prefix should be correct at that point and it should not be necessary to check whether the prefix is allowed. --- poincare/src/unit.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index cc30b9daf..230ae615a 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -44,12 +44,11 @@ bool UnitNode::Representative::canParse(const char * symbol, size_t length, int UnitNode::Representative::serialize(char * buffer, int bufferSize, const Prefix * prefix) const { int length = 0; - if (isPrefixable()) { - length += prefix->serialize(buffer, bufferSize); - assert(length < bufferSize); - buffer += length; - bufferSize -= length; - } + length += prefix->serialize(buffer, bufferSize); + assert(length == 0 || isPrefixable()); + assert(length < bufferSize); + buffer += length; + bufferSize -= length; assert(bufferSize >= 0); length += std::min(strlcpy(buffer, m_rootSymbol, bufferSize), bufferSize - 1); return length; From 157d74c0da5e63df451a722775a08f6f17409b5d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 12 Feb 2020 11:09:30 +0100 Subject: [PATCH 008/453] [poincare/unit] Coding style --- poincare/src/unit.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 230ae615a..c94c3abc6 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -55,22 +55,23 @@ int UnitNode::Representative::serialize(char * buffer, int bufferSize, const Pre } const UnitNode::Prefix * UnitNode::Representative::bestPrefixForValue(double & value, const int exponent) const { - const Prefix * bestPre = &Unit::EmptyPrefix; - if (isPrefixable()) { - unsigned int diff = -1; - /* Find the 'Prefix' with the most adequate 'exponent' for the order of - * magnitude of 'value'. - */ - const int orderOfMagnitude = IEEE754::exponentBase10(std::fabs(value)); - for (const Prefix * pre = m_outputPrefixes; pre < m_outputPrefixesUpperBound; pre++) { - unsigned int newDiff = absInt(orderOfMagnitude - pre->exponent() * exponent); - if (newDiff < diff) { - diff = newDiff; - bestPre = pre; - } - } - value *= std::pow(10.0, -bestPre->exponent() * exponent); + if (!isPrefixable()) { + return &Unit::EmptyPrefix; } + const Prefix * bestPre = nullptr; + unsigned int diff = -1; + /* Find the 'Prefix' with the most adequate 'exponent' for the order of + * magnitude of 'value'. + */ + const int orderOfMagnitude = IEEE754::exponentBase10(std::fabs(value)); + for (const Prefix * pre = m_outputPrefixes; pre < m_outputPrefixesUpperBound; pre++) { + unsigned int newDiff = absInt(orderOfMagnitude - pre->exponent() * exponent); + if (newDiff < diff) { + diff = newDiff; + bestPre = pre; + } + } + value *= std::pow(10.0, -bestPre->exponent() * exponent); return bestPre; } From be2892eae50d9041ecd1a20a333567f98da9a3e0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 10:23:50 +0100 Subject: [PATCH 009/453] [poincare] Define Unit::Dimension::Vector type --- poincare/include/poincare/unit.h | 2 ++ poincare/src/multiplication.cpp | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index d1938008f..2c06c898a 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -73,6 +73,8 @@ public: class Dimension { public: + template + using Vector = T[7]; template constexpr Dimension(const Representative (&representatives)[N], const Prefix * stdRepresentativePrefix) : m_representatives(representatives), diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 382b9e2e9..af16b61ff 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -302,13 +302,13 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct return privateShallowReduce(reductionContext, true, true); } -static void ExponentsCopy(Integer (&dst)[7], const Integer (&src)[7]) { +static void ExponentsCopy(Unit::Dimension::Vector &dst, const Unit::Dimension::Vector &src) { for (int i = 0; i < 7; i++) { dst[i] = src[i]; } } -static void ExponentsMetrics(const Integer (&exponents)[7], size_t & supportSize, Integer & norm) { +static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, size_t & supportSize, Integer & norm) { assert(supportSize == 0 && norm.isZero()); for (int i = 0; i < 7; i++) { Integer unsignedExponent = exponents[i]; @@ -320,7 +320,7 @@ static void ExponentsMetrics(const Integer (&exponents)[7], size_t & supportSize } } -static void ExponentsOfBaseUnits(const Expression units, Integer (&exponents)[7]) { +static void ExponentsOfBaseUnits(const Expression units, Unit::Dimension::Vector &exponents) { // Make sure the provided Expression is a Multiplication Expression u = units; if (u.type() == ExpressionNode::Type::Unit || u.type() == ExpressionNode::Type::Power) { @@ -352,14 +352,14 @@ static void ExponentsOfBaseUnits(const Expression units, Integer (&exponents)[7] } static bool CanSimplifyUnitProduct( - const Integer (&unitsExponents)[7], const Integer (&entryUnitExponents)[7], const Integer entryUnitNorm, const Expression entryUnit, + const Unit::Dimension::Vector &unitsExponents, const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), - Expression & bestUnit, Integer & bestUnitNorm, Integer (&bestRemainderExponents)[7], size_t & bestRemainderSupportSize, Integer & bestRemainderNorm) { + Expression & bestUnit, Integer & bestUnitNorm, Unit::Dimension::Vector &bestRemainderExponents, size_t & bestRemainderSupportSize, Integer & bestRemainderNorm) { /* This function tries to simplify a Unit product (given as the * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and * 'bestRemainder' are updated accordingly. */ - Integer simplifiedExponents[7] = { + Unit::Dimension::Vector simplifiedExponents = { Integer(0), Integer(0), Integer(0), @@ -418,7 +418,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * - Repeat those steps until no more simplification is possible. */ Multiplication unitsAccu = Multiplication::Builder(); - Integer unitsExponents[7] = { + Unit::Dimension::Vector unitsExponents = { Integer(0), Integer(0), Integer(0), @@ -431,7 +431,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu size_t unitsSupportSize = 0; Integer unitsNorm(0); ExponentsMetrics(unitsExponents, unitsSupportSize, unitsNorm); - Integer bestRemainderExponents[7] = { + Unit::Dimension::Vector bestRemainderExponents = { Integer(0), Integer(0), Integer(0), @@ -447,7 +447,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Integer bestRemainderNorm = unitsNorm; for (const Unit::Dimension * dim = Unit::DimensionTable + 7; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); - Integer entryUnitExponents[7] = { + Unit::Dimension::Vector entryUnitExponents = { Integer(0), Integer(0), Integer(0), From 2fa71e435083b9e5ab6ebaf553e61bb7092ec77b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 11:06:37 +0100 Subject: [PATCH 010/453] [poincare] Define and use Unit::NumberOfBaseUnits instead of magic number --- poincare/include/poincare/unit.h | 9 +++++---- poincare/src/multiplication.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 2c06c898a..2f2340074 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -11,9 +11,6 @@ public: /* The units having the same physical dimension are grouped together. * Each such group has a standard representative with a standard prefix. * - * A standard unit is a derived unit, when defined from base units - * or otherwise a base unit (if no definition is provided). - * * Each representative has * - a root symbol * - a definition @@ -22,6 +19,9 @@ public: * allowed for that representative, one may get a symbol and an Expression. */ + // There are 7 base units from which all other units are derived. + static constexpr size_t NumberOfBaseUnits = 7; + class Prefix { public: constexpr Prefix(const char * symbol, int8_t exponent) : @@ -74,7 +74,7 @@ public: class Dimension { public: template - using Vector = T[7]; + using Vector = T[NumberOfBaseUnits]; template constexpr Dimension(const Representative (&representatives)[N], const Prefix * stdRepresentativePrefix) : m_representatives(representatives), @@ -220,6 +220,7 @@ public: GigaPrefix, TeraPrefix, }; + static constexpr size_t NumberOfBaseUnits = UnitNode::NumberOfBaseUnits; static constexpr const Representative TimeRepresentatives[] = { Representative("s", nullptr, diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index af16b61ff..6292243cc 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -303,14 +303,14 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct } static void ExponentsCopy(Unit::Dimension::Vector &dst, const Unit::Dimension::Vector &src) { - for (int i = 0; i < 7; i++) { + for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { dst[i] = src[i]; } } static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, size_t & supportSize, Integer & norm) { assert(supportSize == 0 && norm.isZero()); - for (int i = 0; i < 7; i++) { + for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { Integer unsignedExponent = exponents[i]; unsignedExponent.setNegative(false); if (!unsignedExponent.isZero()) { @@ -346,7 +346,7 @@ static void ExponentsOfBaseUnits(const Expression units, Unit::Dimension::Vector // Fill the exponents array with the unit's exponent const int indexInTable = static_cast(factor).dimension() - Unit::DimensionTable; - assert(0 <= indexInTable && indexInTable < 7); + assert(0 <= indexInTable && indexInTable < Unit::NumberOfBaseUnits); exponents[indexInTable] = exponent; } } @@ -368,7 +368,7 @@ static bool CanSimplifyUnitProduct( Integer(0), Integer(0), }; - for (int i = 0; i < 7; i++) { + for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { simplifiedExponents[i] = operationOnExponents(unitsExponents[i], entryUnitExponents[i]); } size_t simplifiedSupportSize = 0; @@ -445,7 +445,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Integer bestUnitNorm(0); size_t bestRemainderSupportSize = unitsSupportSize - 1; Integer bestRemainderNorm = unitsNorm; - for (const Unit::Dimension * dim = Unit::DimensionTable + 7; dim < Unit::DimensionTableUpperBound; dim++) { + for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); Unit::Dimension::Vector entryUnitExponents = { Integer(0), From 202beb3b13ac5a5da7f8e57d57769ae1e0cd3380 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 11:39:02 +0100 Subject: [PATCH 011/453] [poincare/unit] Add comment about namespace and scope usage --- poincare/include/poincare/unit.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 2f2340074..486ab91df 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -17,6 +17,16 @@ public: * - a list of allowed output prefixes * Given a Dimension, a representative in that Dimension and a Prefix * allowed for that representative, one may get a symbol and an Expression. + * + * FIXME ? + * The UnitNode class holds as members pointers to a Dimension, a + * Representative, a Prefix. Those nested classes may not be forward + * declared and must be defined in UnitNode and then aliased in Unit so as + * to be used outside. That technical limitation could have been avoided if + * UnitNode were itself a nested class of Unit, say Unit::Node. More + * generally, turning all the Poincare::...Node classes into nested + * Poincare::...::Node classes might be a more clever usage of namespaces + * and scopes. */ // There are 7 base units from which all other units are derived. From 0eb6df27dc041eafe70befbcb77136a898beb53c Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 12:20:49 +0100 Subject: [PATCH 012/453] [poincare] Turn Unit::Dimension::Vector type into a struct --- poincare/include/poincare/unit.h | 18 +++++++++- poincare/src/multiplication.cpp | 56 +++++--------------------------- 2 files changed, 26 insertions(+), 48 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 486ab91df..c6ee3f61d 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -84,7 +84,23 @@ public: class Dimension { public: template - using Vector = T[NumberOfBaseUnits]; + struct Vector { + const T coefficientAtIndex(size_t i) const { + assert(i < NumberOfBaseUnits); + return *(reinterpret_cast(this) + i); + } + void setCoefficientAtIndex(size_t i, T c) { + assert(i < NumberOfBaseUnits); + *(reinterpret_cast(this) + i) = c; + } + T time; + T distance; + T mass; + T current; + T temperature; + T amountOfSubstance; + T luminuousIntensity; + }; template constexpr Dimension(const Representative (&representatives)[N], const Prefix * stdRepresentativePrefix) : m_representatives(representatives), diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 6292243cc..656544c9a 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -302,16 +302,10 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct return privateShallowReduce(reductionContext, true, true); } -static void ExponentsCopy(Unit::Dimension::Vector &dst, const Unit::Dimension::Vector &src) { - for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { - dst[i] = src[i]; - } -} - static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, size_t & supportSize, Integer & norm) { assert(supportSize == 0 && norm.isZero()); for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { - Integer unsignedExponent = exponents[i]; + Integer unsignedExponent = exponents.coefficientAtIndex(i); unsignedExponent.setNegative(false); if (!unsignedExponent.isZero()) { supportSize++; @@ -347,7 +341,7 @@ static void ExponentsOfBaseUnits(const Expression units, Unit::Dimension::Vector // Fill the exponents array with the unit's exponent const int indexInTable = static_cast(factor).dimension() - Unit::DimensionTable; assert(0 <= indexInTable && indexInTable < Unit::NumberOfBaseUnits); - exponents[indexInTable] = exponent; + exponents.setCoefficientAtIndex(indexInTable, exponent); } } @@ -359,17 +353,9 @@ static bool CanSimplifyUnitProduct( * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and * 'bestRemainder' are updated accordingly. */ - Unit::Dimension::Vector simplifiedExponents = { - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - }; + Unit::Dimension::Vector simplifiedExponents; for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { - simplifiedExponents[i] = operationOnExponents(unitsExponents[i], entryUnitExponents[i]); + simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents.coefficientAtIndex(i))); } size_t simplifiedSupportSize = 0; Integer simplifiedNorm(0); @@ -380,7 +366,7 @@ static bool CanSimplifyUnitProduct( if (isSimpler) { bestUnit = entryUnit; bestUnitNorm = entryUnitNorm; - ExponentsCopy(bestRemainderExponents, simplifiedExponents); + bestRemainderExponents = simplifiedExponents; bestRemainderSupportSize = simplifiedSupportSize; bestRemainderNorm = simplifiedNorm; } @@ -418,28 +404,12 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * - Repeat those steps until no more simplification is possible. */ Multiplication unitsAccu = Multiplication::Builder(); - Unit::Dimension::Vector unitsExponents = { - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - }; + Unit::Dimension::Vector unitsExponents; ExponentsOfBaseUnits(units, unitsExponents); size_t unitsSupportSize = 0; Integer unitsNorm(0); ExponentsMetrics(unitsExponents, unitsSupportSize, unitsNorm); - Unit::Dimension::Vector bestRemainderExponents = { - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - }; + Unit::Dimension::Vector bestRemainderExponents; while (unitsSupportSize > 1) { Expression bestUnit; Integer bestUnitNorm(0); @@ -447,15 +417,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Integer bestRemainderNorm = unitsNorm; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); - Unit::Dimension::Vector entryUnitExponents = { - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - Integer(0), - }; + Unit::Dimension::Vector entryUnitExponents; Integer entryUnitNorm(0); size_t entryUnitSupportSize = 0; ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext), entryUnitExponents); @@ -477,7 +439,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } const int position = unitsAccu.numberOfChildren(); unitsAccu.addChildAtIndexInPlace(bestUnit, position, position); - ExponentsCopy(unitsExponents, bestRemainderExponents); + unitsExponents = bestRemainderExponents; unitsSupportSize = bestRemainderSupportSize; unitsNorm = bestRemainderNorm; } From 2f6770cd69f1b727812864bbc80fe4d047659c9f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 14:05:51 +0100 Subject: [PATCH 013/453] [poincare/multiplication] Change signature of ExponentsOfBaseUnits --- poincare/src/multiplication.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 656544c9a..526a5c86e 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -314,7 +314,8 @@ static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, } } -static void ExponentsOfBaseUnits(const Expression units, Unit::Dimension::Vector &exponents) { +static Unit::Dimension::Vector ExponentsOfBaseUnits(const Expression units) { + Unit::Dimension::Vector exponents; // Make sure the provided Expression is a Multiplication Expression u = units; if (u.type() == ExpressionNode::Type::Unit || u.type() == ExpressionNode::Type::Power) { @@ -343,6 +344,7 @@ static void ExponentsOfBaseUnits(const Expression units, Unit::Dimension::Vector assert(0 <= indexInTable && indexInTable < Unit::NumberOfBaseUnits); exponents.setCoefficientAtIndex(indexInTable, exponent); } + return exponents; } static bool CanSimplifyUnitProduct( @@ -404,8 +406,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * - Repeat those steps until no more simplification is possible. */ Multiplication unitsAccu = Multiplication::Builder(); - Unit::Dimension::Vector unitsExponents; - ExponentsOfBaseUnits(units, unitsExponents); + Unit::Dimension::Vector unitsExponents = ExponentsOfBaseUnits(units); size_t unitsSupportSize = 0; Integer unitsNorm(0); ExponentsMetrics(unitsExponents, unitsSupportSize, unitsNorm); @@ -417,10 +418,9 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Integer bestRemainderNorm = unitsNorm; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); - Unit::Dimension::Vector entryUnitExponents; + Unit::Dimension::Vector entryUnitExponents = ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); Integer entryUnitNorm(0); size_t entryUnitSupportSize = 0; - ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext), entryUnitExponents); ExponentsMetrics(entryUnitExponents, entryUnitSupportSize, entryUnitNorm); CanSimplifyUnitProduct( unitsExponents, entryUnitExponents, entryUnitNorm, entryUnit, From e2cdf786053083593a5d36c38fecc7ce9a1a2d72 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 19 Feb 2020 16:53:11 +0100 Subject: [PATCH 014/453] [poincare] Define and use Unit::Dimension::Vector::Metrics --- poincare/include/poincare/unit.h | 4 ++++ poincare/src/multiplication.cpp | 41 +++++++++++++------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index c6ee3f61d..a7a21a67a 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -85,6 +85,10 @@ public: public: template struct Vector { + struct Metrics { + size_t supportSize; + T norm; + }; const T coefficientAtIndex(size_t i) const { assert(i < NumberOfBaseUnits); return *(reinterpret_cast(this) + i); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 526a5c86e..4e732b67d 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -302,8 +302,9 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct return privateShallowReduce(reductionContext, true, true); } -static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, size_t & supportSize, Integer & norm) { - assert(supportSize == 0 && norm.isZero()); +static Unit::Dimension::Vector::Metrics ExponentsMetrics(const Unit::Dimension::Vector &exponents) { + size_t supportSize = 0; + Integer norm(0); for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { Integer unsignedExponent = exponents.coefficientAtIndex(i); unsignedExponent.setNegative(false); @@ -312,6 +313,7 @@ static void ExponentsMetrics(const Unit::Dimension::Vector &exponents, norm = Integer::Addition(norm, unsignedExponent); } } + return {.supportSize = supportSize, .norm = norm}; } static Unit::Dimension::Vector ExponentsOfBaseUnits(const Expression units) { @@ -350,7 +352,7 @@ static Unit::Dimension::Vector ExponentsOfBaseUnits(const Expression un static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), - Expression & bestUnit, Integer & bestUnitNorm, Unit::Dimension::Vector &bestRemainderExponents, size_t & bestRemainderSupportSize, Integer & bestRemainderNorm) { + Expression & bestUnit, Integer & bestUnitNorm, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and @@ -359,18 +361,15 @@ static bool CanSimplifyUnitProduct( for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents.coefficientAtIndex(i))); } - size_t simplifiedSupportSize = 0; - Integer simplifiedNorm(0); - ExponentsMetrics(simplifiedExponents, simplifiedSupportSize, simplifiedNorm); - bool isSimpler = simplifiedSupportSize < bestRemainderSupportSize || - (simplifiedSupportSize == bestRemainderSupportSize && - Integer::Addition(simplifiedNorm, entryUnitNorm).isLowerThan(Integer::Addition(bestRemainderNorm, bestUnitNorm))); + Unit::Dimension::Vector::Metrics simplifiedMetrics = ExponentsMetrics(simplifiedExponents); + bool isSimpler = simplifiedMetrics.supportSize < bestRemainderMetrics.supportSize || + (simplifiedMetrics.supportSize == bestRemainderMetrics.supportSize && + Integer::Addition(simplifiedMetrics.norm, entryUnitNorm).isLowerThan(Integer::Addition(bestRemainderMetrics.norm, bestUnitNorm))); if (isSimpler) { bestUnit = entryUnit; bestUnitNorm = entryUnitNorm; bestRemainderExponents = simplifiedExponents; - bestRemainderSupportSize = simplifiedSupportSize; - bestRemainderNorm = simplifiedNorm; + bestRemainderMetrics = simplifiedMetrics; } return isSimpler; } @@ -407,31 +406,26 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu */ Multiplication unitsAccu = Multiplication::Builder(); Unit::Dimension::Vector unitsExponents = ExponentsOfBaseUnits(units); - size_t unitsSupportSize = 0; - Integer unitsNorm(0); - ExponentsMetrics(unitsExponents, unitsSupportSize, unitsNorm); + Unit::Dimension::Vector::Metrics unitsMetrics = ExponentsMetrics(unitsExponents); Unit::Dimension::Vector bestRemainderExponents; - while (unitsSupportSize > 1) { + while (unitsMetrics.supportSize > 1) { Expression bestUnit; Integer bestUnitNorm(0); - size_t bestRemainderSupportSize = unitsSupportSize - 1; - Integer bestRemainderNorm = unitsNorm; + Unit::Dimension::Vector::Metrics bestRemainderMetrics = {.supportSize = unitsMetrics.supportSize - 1, .norm = unitsMetrics.norm}; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); Unit::Dimension::Vector entryUnitExponents = ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); - Integer entryUnitNorm(0); - size_t entryUnitSupportSize = 0; - ExponentsMetrics(entryUnitExponents, entryUnitSupportSize, entryUnitNorm); + Integer entryUnitNorm = ExponentsMetrics(entryUnitExponents).norm; CanSimplifyUnitProduct( unitsExponents, entryUnitExponents, entryUnitNorm, entryUnit, Integer::Subtraction, - bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderSupportSize, bestRemainderNorm + bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics ) || CanSimplifyUnitProduct( unitsExponents, entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), Integer::Addition, - bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderSupportSize, bestRemainderNorm + bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics ); } if (bestUnit.isUninitialized()) { @@ -440,8 +434,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu const int position = unitsAccu.numberOfChildren(); unitsAccu.addChildAtIndexInPlace(bestUnit, position, position); unitsExponents = bestRemainderExponents; - unitsSupportSize = bestRemainderSupportSize; - unitsNorm = bestRemainderNorm; + unitsMetrics = bestRemainderMetrics; } if (unitsAccu.numberOfChildren() > 0) { units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); From b6d07cbd90634614341f63fe2d9e176dbbce3315 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 20 Feb 2020 10:05:38 +0100 Subject: [PATCH 015/453] [poincare] Make code more object oriented Turn ExponentsOfBaseUnits function into a method of the Unit::Dimension::Vector class --- poincare/include/poincare/unit.h | 1 + poincare/src/multiplication.cpp | 20 +++----------------- poincare/src/unit.cpp | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index a7a21a67a..b340234e1 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -89,6 +89,7 @@ public: size_t supportSize; T norm; }; + Metrics metrics() const; const T coefficientAtIndex(size_t i) const { assert(i < NumberOfBaseUnits); return *(reinterpret_cast(this) + i); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 4e732b67d..dadef4123 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -302,20 +302,6 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct return privateShallowReduce(reductionContext, true, true); } -static Unit::Dimension::Vector::Metrics ExponentsMetrics(const Unit::Dimension::Vector &exponents) { - size_t supportSize = 0; - Integer norm(0); - for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { - Integer unsignedExponent = exponents.coefficientAtIndex(i); - unsignedExponent.setNegative(false); - if (!unsignedExponent.isZero()) { - supportSize++; - norm = Integer::Addition(norm, unsignedExponent); - } - } - return {.supportSize = supportSize, .norm = norm}; -} - static Unit::Dimension::Vector ExponentsOfBaseUnits(const Expression units) { Unit::Dimension::Vector exponents; // Make sure the provided Expression is a Multiplication @@ -361,7 +347,7 @@ static bool CanSimplifyUnitProduct( for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents.coefficientAtIndex(i))); } - Unit::Dimension::Vector::Metrics simplifiedMetrics = ExponentsMetrics(simplifiedExponents); + Unit::Dimension::Vector::Metrics simplifiedMetrics = simplifiedExponents.metrics(); bool isSimpler = simplifiedMetrics.supportSize < bestRemainderMetrics.supportSize || (simplifiedMetrics.supportSize == bestRemainderMetrics.supportSize && Integer::Addition(simplifiedMetrics.norm, entryUnitNorm).isLowerThan(Integer::Addition(bestRemainderMetrics.norm, bestUnitNorm))); @@ -406,7 +392,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu */ Multiplication unitsAccu = Multiplication::Builder(); Unit::Dimension::Vector unitsExponents = ExponentsOfBaseUnits(units); - Unit::Dimension::Vector::Metrics unitsMetrics = ExponentsMetrics(unitsExponents); + Unit::Dimension::Vector::Metrics unitsMetrics = unitsExponents.metrics(); Unit::Dimension::Vector bestRemainderExponents; while (unitsMetrics.supportSize > 1) { Expression bestUnit; @@ -415,7 +401,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); Unit::Dimension::Vector entryUnitExponents = ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); - Integer entryUnitNorm = ExponentsMetrics(entryUnitExponents).norm; + Integer entryUnitNorm = entryUnitExponents.metrics().norm; CanSimplifyUnitProduct( unitsExponents, entryUnitExponents, entryUnitNorm, entryUnit, Integer::Subtraction, diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index c94c3abc6..25c8f0d04 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -75,6 +75,22 @@ const UnitNode::Prefix * UnitNode::Representative::bestPrefixForValue(double & v return bestPre; } +template<> +Unit::Dimension::Vector::Metrics UnitNode::Dimension::Vector::metrics() const { + size_t supportSize = 0; + Integer norm(0); + for (const Integer * i = reinterpret_cast(this); i < reinterpret_cast(this) + NumberOfBaseUnits; i++) { + Integer coefficient = *i; + if (coefficient.isZero()) { + continue; + } + supportSize++; + coefficient.setNegative(false); + norm = Integer::Addition(norm, coefficient); + } + return {.supportSize = supportSize, .norm = norm}; +} + bool UnitNode::Dimension::canParse(const char * symbol, size_t length, const Representative * * representative, const Prefix * * prefix) const { From 67241bb564ec78b3ab1998aef6e7f1b2090096e1 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 20 Feb 2020 10:26:15 +0100 Subject: [PATCH 016/453] [poincare] Make code more object oriented Turn ExponentsOfBaseUnits function into a static method of the Unit::Dimension::Vector class --- poincare/include/poincare/expression.h | 1 + poincare/include/poincare/unit.h | 3 +-- poincare/src/multiplication.cpp | 37 ++------------------------ poincare/src/unit.cpp | 35 ++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index c8aa3cc10..54877d604 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -117,6 +117,7 @@ class Expression : public TreeHandle { friend class NAryExpressionNode; friend class StoreNode; friend class SymbolNode; + friend class UnitNode; public: static bool IsExpression() { return true; } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index b340234e1..0475fff90 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -90,6 +90,7 @@ public: T norm; }; Metrics metrics() const; + static Vector FromBaseUnits(const Expression baseUnits); const T coefficientAtIndex(size_t i) const { assert(i < NumberOfBaseUnits); return *(reinterpret_cast(this) + i); @@ -512,8 +513,6 @@ public: static bool CanParse(const char * symbol, size_t length, const Dimension * * dimension, const Representative * * representative, const Prefix * * prefix); - const Dimension * dimension() const { return static_cast(node())->dimension(); } - Unit(const UnitNode * node) : Expression(node) {} static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); Expression getUnit() const { return clone(); } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index dadef4123..9776a17a1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -302,39 +302,6 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct return privateShallowReduce(reductionContext, true, true); } -static Unit::Dimension::Vector ExponentsOfBaseUnits(const Expression units) { - Unit::Dimension::Vector exponents; - // Make sure the provided Expression is a Multiplication - Expression u = units; - if (u.type() == ExpressionNode::Type::Unit || u.type() == ExpressionNode::Type::Power) { - u = Multiplication::Builder(u.clone()); - } - const int numberOfChildren = u.numberOfChildren(); - for (int i = 0; i < numberOfChildren; i++) { - Expression factor = u.childAtIndex(i); - - // Get the unit's exponent - Integer exponent(1); - if (factor.type() == ExpressionNode::Type::Power) { - Expression exp = factor.childAtIndex(1); - assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); - exponent = static_cast(exp).signedIntegerNumerator(); - factor = factor.childAtIndex(0); - } - - // The leading factors may not be of Unit type - if (factor.type() != ExpressionNode::Type::Unit) { - continue; - } - - // Fill the exponents array with the unit's exponent - const int indexInTable = static_cast(factor).dimension() - Unit::DimensionTable; - assert(0 <= indexInTable && indexInTable < Unit::NumberOfBaseUnits); - exponents.setCoefficientAtIndex(indexInTable, exponent); - } - return exponents; -} - static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), @@ -391,7 +358,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * - Repeat those steps until no more simplification is possible. */ Multiplication unitsAccu = Multiplication::Builder(); - Unit::Dimension::Vector unitsExponents = ExponentsOfBaseUnits(units); + Unit::Dimension::Vector unitsExponents = Unit::Dimension::Vector::FromBaseUnits(units); Unit::Dimension::Vector::Metrics unitsMetrics = unitsExponents.metrics(); Unit::Dimension::Vector bestRemainderExponents; while (unitsMetrics.supportSize > 1) { @@ -400,7 +367,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit::Dimension::Vector::Metrics bestRemainderMetrics = {.supportSize = unitsMetrics.supportSize - 1, .norm = unitsMetrics.norm}; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); - Unit::Dimension::Vector entryUnitExponents = ExponentsOfBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); + Unit::Dimension::Vector entryUnitExponents = Unit::Dimension::Vector::FromBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); Integer entryUnitNorm = entryUnitExponents.metrics().norm; CanSimplifyUnitProduct( unitsExponents, entryUnitExponents, entryUnitNorm, entryUnit, diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 25c8f0d04..8b02634f9 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -91,6 +91,41 @@ Unit::Dimension::Vector::Metrics UnitNode::Dimension::Vector:: return {.supportSize = supportSize, .norm = norm}; } +template<> +Unit::Dimension::Vector UnitNode::Dimension::Vector::FromBaseUnits(const Expression baseUnits) { + Vector vector; + // Make sure the provided Expression is a Multiplication + Expression u = baseUnits; + if (u.type() == ExpressionNode::Type::Unit || u.type() == ExpressionNode::Type::Power) { + u = Multiplication::Builder(u.clone()); + } + const int numberOfChildren = u.numberOfChildren(); + for (int i = 0; i < numberOfChildren; i++) { + Expression factor = u.childAtIndex(i); + + // Get the unit's exponent + Integer exponent(1); + if (factor.type() == ExpressionNode::Type::Power) { + Expression exp = factor.childAtIndex(1); + assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); + exponent = static_cast(exp).signedIntegerNumerator(); + factor = factor.childAtIndex(0); + } + + // FIXME Remove this once this case may not occur anymore + // The leading factors may not be of Unit type + if (factor.type() != ExpressionNode::Type::Unit) { + continue; + } + + // Fill the vector with the unit's exponent + const ptrdiff_t indexInTable = static_cast(factor.node())->dimension() - Unit::DimensionTable; + assert(0 <= indexInTable && indexInTable < NumberOfBaseUnits); + vector.setCoefficientAtIndex(indexInTable, exponent); + } + return vector; +} + bool UnitNode::Dimension::canParse(const char * symbol, size_t length, const Representative * * representative, const Prefix * * prefix) const { From 191680d96f9323b04d91750b69a258a115aa331b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 20 Feb 2020 17:46:09 +0100 Subject: [PATCH 017/453] [poincare/multiplication] Simplify Unit::Dimension::Vector::Metrics comparison --- poincare/src/multiplication.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 9776a17a1..b565f56a1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -303,7 +303,8 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct } static bool CanSimplifyUnitProduct( - const Unit::Dimension::Vector &unitsExponents, const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, + const Unit::Dimension::Vector &unitsExponents, Unit::Dimension::Vector::Metrics &unitsMetrics, + const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), Expression & bestUnit, Integer & bestUnitNorm, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the @@ -315,14 +316,19 @@ static bool CanSimplifyUnitProduct( simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents.coefficientAtIndex(i))); } Unit::Dimension::Vector::Metrics simplifiedMetrics = simplifiedExponents.metrics(); - bool isSimpler = simplifiedMetrics.supportSize < bestRemainderMetrics.supportSize || - (simplifiedMetrics.supportSize == bestRemainderMetrics.supportSize && - Integer::Addition(simplifiedMetrics.norm, entryUnitNorm).isLowerThan(Integer::Addition(bestRemainderMetrics.norm, bestUnitNorm))); + Unit::Dimension::Vector::Metrics candidateMetrics = { + .supportSize = 1 + simplifiedMetrics.supportSize, + .norm = Integer::Addition(entryUnitNorm, simplifiedMetrics.norm) + }; + bool isSimpler = candidateMetrics.supportSize < unitsMetrics.supportSize || + (candidateMetrics.supportSize == unitsMetrics.supportSize && + candidateMetrics.norm.isLowerThan(unitsMetrics.norm)); if (isSimpler) { bestUnit = entryUnit; bestUnitNorm = entryUnitNorm; bestRemainderExponents = simplifiedExponents; bestRemainderMetrics = simplifiedMetrics; + unitsMetrics = candidateMetrics; } return isSimpler; } @@ -361,22 +367,24 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit::Dimension::Vector unitsExponents = Unit::Dimension::Vector::FromBaseUnits(units); Unit::Dimension::Vector::Metrics unitsMetrics = unitsExponents.metrics(); Unit::Dimension::Vector bestRemainderExponents; + Unit::Dimension::Vector::Metrics bestRemainderMetrics; while (unitsMetrics.supportSize > 1) { Expression bestUnit; Integer bestUnitNorm(0); - Unit::Dimension::Vector::Metrics bestRemainderMetrics = {.supportSize = unitsMetrics.supportSize - 1, .norm = unitsMetrics.norm}; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); Unit::Dimension::Vector entryUnitExponents = Unit::Dimension::Vector::FromBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); Integer entryUnitNorm = entryUnitExponents.metrics().norm; CanSimplifyUnitProduct( - unitsExponents, entryUnitExponents, entryUnitNorm, entryUnit, + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, entryUnit, Integer::Subtraction, bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics ) || CanSimplifyUnitProduct( - unitsExponents, entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), Integer::Addition, bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics ); From d7dab2ae994165de14c9e1c14499699eb29d4f15 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 24 Feb 2020 12:22:39 +0100 Subject: [PATCH 018/453] [poincare/multiplication] bestUnitNorm not necessary anymore --- poincare/src/multiplication.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index b565f56a1..0aa6a53fb 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -306,7 +306,7 @@ static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, Unit::Dimension::Vector::Metrics &unitsMetrics, const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), - Expression & bestUnit, Integer & bestUnitNorm, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { + Expression & bestUnit, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and @@ -325,7 +325,6 @@ static bool CanSimplifyUnitProduct( candidateMetrics.norm.isLowerThan(unitsMetrics.norm)); if (isSimpler) { bestUnit = entryUnit; - bestUnitNorm = entryUnitNorm; bestRemainderExponents = simplifiedExponents; bestRemainderMetrics = simplifiedMetrics; unitsMetrics = candidateMetrics; @@ -370,7 +369,6 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit::Dimension::Vector::Metrics bestRemainderMetrics; while (unitsMetrics.supportSize > 1) { Expression bestUnit; - Integer bestUnitNorm(0); for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); Unit::Dimension::Vector entryUnitExponents = Unit::Dimension::Vector::FromBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); @@ -379,14 +377,14 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu unitsExponents, unitsMetrics, entryUnitExponents, entryUnitNorm, entryUnit, Integer::Subtraction, - bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics + bestUnit, bestRemainderExponents, bestRemainderMetrics ) || CanSimplifyUnitProduct( unitsExponents, unitsMetrics, entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), Integer::Addition, - bestUnit, bestUnitNorm, bestRemainderExponents, bestRemainderMetrics + bestUnit, bestRemainderExponents, bestRemainderMetrics ); } if (bestUnit.isUninitialized()) { From 394e86a28a1b2849a9f05e099012015281ffd98b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 24 Feb 2020 16:45:03 +0100 Subject: [PATCH 019/453] [poincare] Unit::Dimension holds a Vector The Vector does not need to be recomputed from a Representative's definition, which requires parsing and time-consuming reduction. --- poincare/include/poincare/unit.h | 212 ++++++++++++++++++++++++++++++- poincare/src/multiplication.cpp | 8 +- poincare/src/unit.cpp | 15 +++ 3 files changed, 230 insertions(+), 5 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 0475fff90..97bc4ba87 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -108,18 +108,21 @@ public: T luminuousIntensity; }; template - constexpr Dimension(const Representative (&representatives)[N], const Prefix * stdRepresentativePrefix) : + constexpr Dimension(Vector vector, const Representative (&representatives)[N], const Prefix * stdRepresentativePrefix) : + m_vector(vector), m_representatives(representatives), m_representativesUpperBound(representatives + N), m_stdRepresentativePrefix(stdRepresentativePrefix) { } + const Vector * vector() const { return &m_vector; } const Representative * stdRepresentative() const { return m_representatives; } const Representative * representativesUpperBound() const { return m_representativesUpperBound; } const Prefix * stdRepresentativePrefix() const { return m_stdRepresentativePrefix; } bool canParse(const char * symbol, size_t length, const Representative * * representative, const Prefix * * prefix) const; private: + Vector m_vector; const Representative * m_representatives; const Representative * m_representativesUpperBound; const Prefix * m_stdRepresentativePrefix; @@ -416,94 +419,301 @@ public: * The order determines the behavior of simplification. */ Dimension( + Dimension::Vector { + .time = 1, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, TimeRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 1, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, DistanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 0, + .mass = 1, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, MassRepresentatives, &KiloPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 0, + .mass = 0, + .current = 1, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, CurrentRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 1, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, TemperatureRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 1, + .luminuousIntensity = 0, + }, AmountOfSubstanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 1, + }, LuminousIntensityRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-1, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, FrequencyRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance = 1, + .mass = 1, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ForceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance =-1, + .mass = 1, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, PressureRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance = 2, + .mass = 1, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, EnergyRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-3, + .distance = 2, + .mass = 1, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, PowerRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 1, + .distance = 0, + .mass = 0, + .current = 1, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ElectricChargeRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-3, + .distance = 2, + .mass = 1, + .current =-1, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ElectricPotentialRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 4, + .distance =-2, + .mass =-1, + .current = 2, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ElectricCapacitanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-3, + .distance = 2, + .mass = 1, + .current =-2, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ElectricResistanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 3, + .distance =-2, + .mass =-1, + .current = 2, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, ElectricConductanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance = 2, + .mass = 1, + .current =-1, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, MagneticFluxRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance = 0, + .mass = 1, + .current =-1, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, MagneticFieldRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-2, + .distance = 2, + .mass = 1, + .current =-2, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, InductanceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time =-1, + .distance = 0, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 1, + .luminuousIntensity = 0, + }, CatalyticActivityRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 2, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, SurfaceRepresentatives, &EmptyPrefix ), Dimension( + Dimension::Vector { + .time = 0, + .distance = 3, + .mass = 0, + .current = 0, + .temperature = 0, + .amountOfSubstance = 0, + .luminuousIntensity = 0, + }, VolumeRepresentatives, &EmptyPrefix ), diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 0aa6a53fb..9cc88cbf0 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -304,7 +304,7 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, Unit::Dimension::Vector::Metrics &unitsMetrics, - const Unit::Dimension::Vector &entryUnitExponents, const Integer entryUnitNorm, const Expression entryUnit, + const Unit::Dimension::Vector *entryUnitExponents, int8_t entryUnitNorm, const Expression entryUnit, Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), Expression & bestUnit, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the @@ -313,7 +313,7 @@ static bool CanSimplifyUnitProduct( * 'bestRemainder' are updated accordingly. */ Unit::Dimension::Vector simplifiedExponents; for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { - simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents.coefficientAtIndex(i))); + simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents->coefficientAtIndex(i))); } Unit::Dimension::Vector::Metrics simplifiedMetrics = simplifiedExponents.metrics(); Unit::Dimension::Vector::Metrics candidateMetrics = { @@ -371,8 +371,8 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Expression bestUnit; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); - Unit::Dimension::Vector entryUnitExponents = Unit::Dimension::Vector::FromBaseUnits(entryUnit.clone().shallowReduce(reductionContext)); - Integer entryUnitNorm = entryUnitExponents.metrics().norm; + const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); + int8_t entryUnitNorm = entryUnitExponents->metrics().norm; CanSimplifyUnitProduct( unitsExponents, unitsMetrics, entryUnitExponents, entryUnitNorm, entryUnit, diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 8b02634f9..9011a8224 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -91,6 +91,21 @@ Unit::Dimension::Vector::Metrics UnitNode::Dimension::Vector:: return {.supportSize = supportSize, .norm = norm}; } +template<> +Unit::Dimension::Vector::Metrics UnitNode::Dimension::Vector::metrics() const { + size_t supportSize = 0; + int8_t norm = 0; + for (const int8_t * i = reinterpret_cast(this); i < reinterpret_cast(this) + NumberOfBaseUnits; i++) { + int8_t coefficient = *i; + if (coefficient == 0) { + continue; + } + supportSize++; + norm += coefficient > 0 ? coefficient : -coefficient; + } + return {.supportSize = supportSize, .norm = norm}; +} + template<> Unit::Dimension::Vector UnitNode::Dimension::Vector::FromBaseUnits(const Expression baseUnits) { Vector vector; From 2f708cc36cbf5dc1f03c9e602d014a6753773cee Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 24 Feb 2020 16:51:57 +0100 Subject: [PATCH 020/453] [poincare/unit] Dimension::Vector::FromBaseUnits accepts only products of powers of base units and no other factor at all --- poincare/src/unit.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 9011a8224..2fa6ca495 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -127,13 +127,8 @@ Unit::Dimension::Vector UnitNode::Dimension::Vector::FromBaseU factor = factor.childAtIndex(0); } - // FIXME Remove this once this case may not occur anymore - // The leading factors may not be of Unit type - if (factor.type() != ExpressionNode::Type::Unit) { - continue; - } - // Fill the vector with the unit's exponent + assert(factor.type() == ExpressionNode::Type::Unit); const ptrdiff_t indexInTable = static_cast(factor.node())->dimension() - Unit::DimensionTable; assert(0 <= indexInTable && indexInTable < NumberOfBaseUnits); vector.setCoefficientAtIndex(indexInTable, exponent); From 79a81968c8778f14b7ea19329c38d23cc0b50501 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 24 Feb 2020 17:03:45 +0100 Subject: [PATCH 021/453] [poincare/unit] Avoid cloning expression in Dimension::Vector::FromBaseUnits --- poincare/src/unit.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 2fa6ca495..f8617f0df 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -109,15 +109,17 @@ Unit::Dimension::Vector::Metrics UnitNode::Dimension::Vector::me template<> Unit::Dimension::Vector UnitNode::Dimension::Vector::FromBaseUnits(const Expression baseUnits) { Vector vector; - // Make sure the provided Expression is a Multiplication - Expression u = baseUnits; - if (u.type() == ExpressionNode::Type::Unit || u.type() == ExpressionNode::Type::Power) { - u = Multiplication::Builder(u.clone()); + int numberOfFactors; + int factorIndex = 0; + Expression factor; + if (baseUnits.type() == ExpressionNode::Type::Multiplication) { + numberOfFactors = baseUnits.numberOfChildren(); + factor = baseUnits.childAtIndex(0); + } else { + numberOfFactors = 1; + factor = baseUnits; } - const int numberOfChildren = u.numberOfChildren(); - for (int i = 0; i < numberOfChildren; i++) { - Expression factor = u.childAtIndex(i); - + do { // Get the unit's exponent Integer exponent(1); if (factor.type() == ExpressionNode::Type::Power) { @@ -126,13 +128,16 @@ Unit::Dimension::Vector UnitNode::Dimension::Vector::FromBaseU exponent = static_cast(exp).signedIntegerNumerator(); factor = factor.childAtIndex(0); } - // Fill the vector with the unit's exponent assert(factor.type() == ExpressionNode::Type::Unit); const ptrdiff_t indexInTable = static_cast(factor.node())->dimension() - Unit::DimensionTable; assert(0 <= indexInTable && indexInTable < NumberOfBaseUnits); vector.setCoefficientAtIndex(indexInTable, exponent); - } + if (++factorIndex >= numberOfFactors) { + break; + } + factor = baseUnits.childAtIndex(factorIndex); + } while (true); return vector; } From 94bad10ddbc8561f07df352a3b2f2c60849f7e6b Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 17:13:03 +0100 Subject: [PATCH 022/453] [poincare/multiplication] CanSimplifyUnitProduct gets int8_t entryUnitExponent parameter instead of operationOnExponents --- poincare/src/multiplication.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 9cc88cbf0..8e9ff3160 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -304,14 +304,14 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, Unit::Dimension::Vector::Metrics &unitsMetrics, - const Unit::Dimension::Vector *entryUnitExponents, int8_t entryUnitNorm, const Expression entryUnit, - Integer (*operationOnExponents)(const Integer & unitsExponent, const Integer & entryUnitExponent), - Expression & bestUnit, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { + const Unit::Dimension::Vector *entryUnitExponents, int8_t entryUnitNorm, const Expression entryUnit, int8_t entryUnitExponent, + Expression & bestUnit, int8_t & bestUnitExponent, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and * 'bestRemainder' are updated accordingly. */ Unit::Dimension::Vector simplifiedExponents; + Integer (*operationOnExponents)(const Integer &, const Integer &) = entryUnitExponent == -1 ? Integer::Addition : Integer::Subtraction; for (size_t i = 0; i < Unit::NumberOfBaseUnits; i++) { simplifiedExponents.setCoefficientAtIndex(i, operationOnExponents(unitsExponents.coefficientAtIndex(i), entryUnitExponents->coefficientAtIndex(i))); } @@ -325,6 +325,7 @@ static bool CanSimplifyUnitProduct( candidateMetrics.norm.isLowerThan(unitsMetrics.norm)); if (isSimpler) { bestUnit = entryUnit; + bestUnitExponent = entryUnitExponent; bestRemainderExponents = simplifiedExponents; bestRemainderMetrics = simplifiedMetrics; unitsMetrics = candidateMetrics; @@ -369,22 +370,21 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit::Dimension::Vector::Metrics bestRemainderMetrics; while (unitsMetrics.supportSize > 1) { Expression bestUnit; + int8_t bestUnitExponent = 0; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); int8_t entryUnitNorm = entryUnitExponents->metrics().norm; CanSimplifyUnitProduct( unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, entryUnit, - Integer::Subtraction, - bestUnit, bestRemainderExponents, bestRemainderMetrics + entryUnitExponents, entryUnitNorm, entryUnit, 1, + bestUnit, bestUnitExponent, bestRemainderExponents, bestRemainderMetrics ) || CanSimplifyUnitProduct( unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), - Integer::Addition, - bestUnit, bestRemainderExponents, bestRemainderMetrics + entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), -1, + bestUnit, bestUnitExponent, bestRemainderExponents, bestRemainderMetrics ); } if (bestUnit.isUninitialized()) { From 9cbbffcdd6ade1779150e2cf71de6d4dbdb0e227 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 17:24:54 +0100 Subject: [PATCH 023/453] [poincare/multiplication] shallowBeautify builds Power only if necessary --- poincare/src/multiplication.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 8e9ff3160..17302b287 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -383,13 +383,17 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu || CanSimplifyUnitProduct( unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, Power::Builder(entryUnit, Rational::Builder(-1)), -1, + entryUnitExponents, entryUnitNorm, entryUnit, -1, bestUnit, bestUnitExponent, bestRemainderExponents, bestRemainderMetrics ); } if (bestUnit.isUninitialized()) { break; } + assert(bestUnitExponent == 1 || bestUnitExponent == -1); + if (bestUnitExponent == -1) { + bestUnit = Power::Builder(bestUnit, Rational::Builder(-1)); + } const int position = unitsAccu.numberOfChildren(); unitsAccu.addChildAtIndexInPlace(bestUnit, position, position); unitsExponents = bestRemainderExponents; From e43362eee05aa815ffe4f0619f902bccd58d05e3 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 17:34:54 +0100 Subject: [PATCH 024/453] [poincare/multiplication] Factor CanSimplifyUnitProduct --- poincare/src/multiplication.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 17302b287..4d7e9a498 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -304,8 +304,8 @@ Expression Multiplication::shallowReduce(ExpressionNode::ReductionContext reduct static bool CanSimplifyUnitProduct( const Unit::Dimension::Vector &unitsExponents, Unit::Dimension::Vector::Metrics &unitsMetrics, - const Unit::Dimension::Vector *entryUnitExponents, int8_t entryUnitNorm, const Expression entryUnit, int8_t entryUnitExponent, - Expression & bestUnit, int8_t & bestUnitExponent, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { + const Unit::Dimension::Vector *entryUnitExponents, int8_t entryUnitNorm, int8_t entryUnitExponent, + int8_t & bestUnitExponent, Unit::Dimension::Vector &bestRemainderExponents, Unit::Dimension::Vector::Metrics & bestRemainderMetrics) { /* This function tries to simplify a Unit product (given as the * 'unitsExponents' Integer array), by applying a given operation. If the * result of the operation is simpler, 'bestUnit' and @@ -324,7 +324,6 @@ static bool CanSimplifyUnitProduct( (candidateMetrics.supportSize == unitsMetrics.supportSize && candidateMetrics.norm.isLowerThan(unitsMetrics.norm)); if (isSimpler) { - bestUnit = entryUnit; bestUnitExponent = entryUnitExponent; bestRemainderExponents = simplifiedExponents; bestRemainderMetrics = simplifiedMetrics; @@ -375,17 +374,20 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); int8_t entryUnitNorm = entryUnitExponents->metrics().norm; - CanSimplifyUnitProduct( - unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, entryUnit, 1, - bestUnit, bestUnitExponent, bestRemainderExponents, bestRemainderMetrics - ) - || - CanSimplifyUnitProduct( - unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, entryUnit, -1, - bestUnit, bestUnitExponent, bestRemainderExponents, bestRemainderMetrics - ); + if (CanSimplifyUnitProduct( + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, 1, + bestUnitExponent, bestRemainderExponents, bestRemainderMetrics + ) + || + CanSimplifyUnitProduct( + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, -1, + bestUnitExponent, bestRemainderExponents, bestRemainderMetrics + )) + { + bestUnit = entryUnit; + } } if (bestUnit.isUninitialized()) { break; From e03c62838112f0d6c1a504037a501df5eb7b2eee Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 25 Feb 2020 17:45:54 +0100 Subject: [PATCH 025/453] [poincare/multiplication] shallowBeautify builds Unit only if necessary --- poincare/src/multiplication.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 4d7e9a498..68e366239 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -368,10 +368,9 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Unit::Dimension::Vector bestRemainderExponents; Unit::Dimension::Vector::Metrics bestRemainderMetrics; while (unitsMetrics.supportSize > 1) { - Expression bestUnit; + const Unit::Dimension * bestDim = nullptr; int8_t bestUnitExponent = 0; for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { - Unit entryUnit = Unit::Builder(dim, dim->stdRepresentative(), dim->stdRepresentativePrefix()); const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); int8_t entryUnitNorm = entryUnitExponents->metrics().norm; if (CanSimplifyUnitProduct( @@ -386,18 +385,19 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu bestUnitExponent, bestRemainderExponents, bestRemainderMetrics )) { - bestUnit = entryUnit; + bestDim = dim; } } - if (bestUnit.isUninitialized()) { + if (bestDim == nullptr) { break; } + Expression derivedUnit = Unit::Builder(bestDim, bestDim->stdRepresentative(), bestDim->stdRepresentativePrefix()); assert(bestUnitExponent == 1 || bestUnitExponent == -1); if (bestUnitExponent == -1) { - bestUnit = Power::Builder(bestUnit, Rational::Builder(-1)); + derivedUnit = Power::Builder(derivedUnit, Rational::Builder(-1)); } const int position = unitsAccu.numberOfChildren(); - unitsAccu.addChildAtIndexInPlace(bestUnit, position, position); + unitsAccu.addChildAtIndexInPlace(derivedUnit, position, position); unitsExponents = bestRemainderExponents; unitsMetrics = bestRemainderMetrics; } From b05202f2ecbb03d68405ca3e6eec63cd8ddf3d00 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 13 Feb 2020 14:22:23 +0100 Subject: [PATCH 026/453] [poincare] Remove stdio.h inclusions --- poincare/include/poincare/expression.h | 2 -- poincare/src/tree_node.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 54877d604..bce4b2490 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -10,8 +10,6 @@ #include #include -#include - namespace Poincare { class Context; diff --git a/poincare/src/tree_node.cpp b/poincare/src/tree_node.cpp index 29af7657c..3052b4a7e 100644 --- a/poincare/src/tree_node.cpp +++ b/poincare/src/tree_node.cpp @@ -1,7 +1,6 @@ #include #include #include -#include namespace Poincare { From 8e71e03b6e1f5f07caac6afc720659c133dc104f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 13 Feb 2020 14:24:08 +0100 Subject: [PATCH 027/453] [poincare] Remove ostream and iostream header inclusions and keep them precisely where needed --- poincare/include/poincare/tree_pool.h | 1 - poincare/src/integer.cpp | 3 --- poincare/src/tree_handle.cpp | 3 --- poincare/test/tree/helpers.cpp | 4 ---- poincare/test/tree/helpers.h | 4 ---- 5 files changed, 15 deletions(-) diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index 0da0d8f80..d8156e669 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -7,7 +7,6 @@ #include #include #if POINCARE_TREE_LOG -#include #include #endif diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index b1c197398..6cbe5b91c 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -18,9 +18,6 @@ extern "C" { #include #include } -#if POINCARE_INTEGER_LOG -#include -#endif #include namespace Poincare { diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 97e7fbfc1..477565d25 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -2,9 +2,6 @@ #include #include #include -#if POINCARE_TREE_LOG -#include -#endif namespace Poincare { diff --git a/poincare/test/tree/helpers.cpp b/poincare/test/tree/helpers.cpp index b7709b9d7..22490d99a 100644 --- a/poincare/test/tree/helpers.cpp +++ b/poincare/test/tree/helpers.cpp @@ -2,10 +2,6 @@ #include #include -#if POINCARE_TREE_LOG -#include -#endif - int pool_size() { return Poincare::TreePool::sharedPool()->numberOfNodes(); } diff --git a/poincare/test/tree/helpers.h b/poincare/test/tree/helpers.h index 75becf6bc..6ac0e1263 100644 --- a/poincare/test/tree/helpers.h +++ b/poincare/test/tree/helpers.h @@ -1,7 +1,3 @@ -#if POINCARE_TREE_LOG -#include -#endif - int pool_size(); void assert_pool_size(int i); From b8993eafa95daa806ed6887447b493bc062856cc Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 10 Mar 2020 13:52:18 +0100 Subject: [PATCH 028/453] [poincare/expression] Call reduce instead of deepReduce --- poincare/src/expression.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index f274ab3c6..62dc03bc0 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -604,7 +604,7 @@ void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * Expression Expression::simplify(ExpressionNode::ReductionContext reductionContext) { sSimplificationHasBeenInterrupted = false; - Expression e = deepReduce(reductionContext); + Expression e = reduce(reductionContext); if (!sSimplificationHasBeenInterrupted) { e = e.deepBeautify(reductionContext); } @@ -679,11 +679,11 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre // Step 1: we reduce the expression ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation); const bool isUnitConvert = type() == ExpressionNode::Type::UnitConvert; - Expression e = clone().deepReduce(userReductionContext); + Expression e = clone().reduce(userReductionContext); if (sSimplificationHasBeenInterrupted) { sSimplificationHasBeenInterrupted = false; ExpressionNode::ReductionContext systemReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation); - e = deepReduce(systemReductionContext); + e = reduce(systemReductionContext); } *simplifiedExpression = Expression(); if (sSimplificationHasBeenInterrupted) { From e018c9ddc809b8586c8fc50b4755621ebcfa1717 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 10 Mar 2020 13:53:41 +0100 Subject: [PATCH 029/453] [poincare/trigonometry_cheat_table] Reorder parameter names correctly --- poincare/include/poincare/trigonometry_cheat_table.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/trigonometry_cheat_table.h b/poincare/include/poincare/trigonometry_cheat_table.h index 8f77ef8f1..5b5cae99c 100644 --- a/poincare/include/poincare/trigonometry_cheat_table.h +++ b/poincare/include/poincare/trigonometry_cheat_table.h @@ -51,8 +51,8 @@ private: }; // END OF PAIR CLASS - constexpr Row(Pair angleInRadians, Pair angleInGradians, Pair angleInDegrees, Pair sine, Pair cosine, Pair tangent) : - m_pairs{angleInRadians, angleInGradians, angleInDegrees, sine, cosine, tangent} {} + constexpr Row(Pair angleInDegrees, Pair angleInRadians, Pair angleInGradians, Pair sine, Pair cosine, Pair tangent) : + m_pairs{angleInDegrees, angleInRadians, angleInGradians, sine, cosine, tangent} {} float floatForType(Type t) const { assert(((int) t) >= 0 && ((int) t) < k_numberOfPairs); return m_pairs[(int)t].value(); From 145381ad4b1fa94869103c4640e01acc3839c64d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 11:20:54 +0100 Subject: [PATCH 030/453] [apps/calculation/additional_outputs] Remove parentResponder parameter from ListControllers' constructor which was always set to nullptr --- apps/calculation/additional_outputs/complex_list_controller.h | 2 +- .../additional_outputs/expressions_list_controller.cpp | 4 ++-- .../additional_outputs/expressions_list_controller.h | 2 +- .../additional_outputs/illustrated_list_controller.cpp | 4 ++-- .../additional_outputs/illustrated_list_controller.h | 2 +- apps/calculation/additional_outputs/integer_list_controller.h | 2 +- apps/calculation/additional_outputs/list_controller.cpp | 4 ++-- apps/calculation/additional_outputs/list_controller.h | 2 +- .../calculation/additional_outputs/rational_list_controller.h | 2 +- .../additional_outputs/trigonometry_list_controller.h | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/calculation/additional_outputs/complex_list_controller.h b/apps/calculation/additional_outputs/complex_list_controller.h index 1c7d2a654..addb7c342 100644 --- a/apps/calculation/additional_outputs/complex_list_controller.h +++ b/apps/calculation/additional_outputs/complex_list_controller.h @@ -10,7 +10,7 @@ namespace Calculation { class ComplexListController : public IllustratedListController { public: ComplexListController(EditExpressionController * editExpressionController) : - IllustratedListController(nullptr, editExpressionController), + IllustratedListController(editExpressionController), m_complexGraphCell(&m_model) {} // ViewController diff --git a/apps/calculation/additional_outputs/expressions_list_controller.cpp b/apps/calculation/additional_outputs/expressions_list_controller.cpp index 555de4433..956933b0b 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.cpp +++ b/apps/calculation/additional_outputs/expressions_list_controller.cpp @@ -7,8 +7,8 @@ namespace Calculation { /* Expressions list controller */ -ExpressionsListController::ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController) : - ListController(parentResponder, editExpressionController), +ExpressionsListController::ExpressionsListController(EditExpressionController * editExpressionController) : + ListController(editExpressionController), m_cells{} { for (int i = 0; i < k_maxNumberOfCells; i++) { diff --git a/apps/calculation/additional_outputs/expressions_list_controller.h b/apps/calculation/additional_outputs/expressions_list_controller.h index df8f8e4ff..4d6ade149 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.h +++ b/apps/calculation/additional_outputs/expressions_list_controller.h @@ -10,7 +10,7 @@ namespace Calculation { class ExpressionsListController : public ListController { public: - ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController); + ExpressionsListController(EditExpressionController * editExpressionController); // Responder void viewDidDisappear() override; diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.cpp b/apps/calculation/additional_outputs/illustrated_list_controller.cpp index 3fd481ee6..b4d895621 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.cpp +++ b/apps/calculation/additional_outputs/illustrated_list_controller.cpp @@ -8,8 +8,8 @@ namespace Calculation { /* Illustrated list controller */ -IllustratedListController::IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController) : - ListController(parentResponder, editExpressionController, this), +IllustratedListController::IllustratedListController(EditExpressionController * editExpressionController) : + ListController(editExpressionController, this), m_additionalCalculationCells{} { for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) { diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.h b/apps/calculation/additional_outputs/illustrated_list_controller.h index fdac26ddd..d06ca7edc 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.h +++ b/apps/calculation/additional_outputs/illustrated_list_controller.h @@ -11,7 +11,7 @@ namespace Calculation { class IllustratedListController : public ListController, public SelectableTableViewDelegate { public: - IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController); + IllustratedListController(EditExpressionController * editExpressionController); // Responder void viewDidDisappear() override; diff --git a/apps/calculation/additional_outputs/integer_list_controller.h b/apps/calculation/additional_outputs/integer_list_controller.h index a0208762d..b76f46d4d 100644 --- a/apps/calculation/additional_outputs/integer_list_controller.h +++ b/apps/calculation/additional_outputs/integer_list_controller.h @@ -8,7 +8,7 @@ namespace Calculation { class IntegerListController : public ExpressionsListController { public: IntegerListController(EditExpressionController * editExpressionController) : - ExpressionsListController(nullptr, editExpressionController) {} + ExpressionsListController(editExpressionController) {} //ListViewDataSource int numberOfRows() const override; diff --git a/apps/calculation/additional_outputs/list_controller.cpp b/apps/calculation/additional_outputs/list_controller.cpp index 3ea43cf6e..a7ebab267 100644 --- a/apps/calculation/additional_outputs/list_controller.cpp +++ b/apps/calculation/additional_outputs/list_controller.cpp @@ -21,8 +21,8 @@ void ListController::InnerListController::didBecomeFirstResponder() { /* List Controller */ -ListController::ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) : - StackViewController(parentResponder, &m_listController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), +ListController::ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) : + StackViewController(nullptr, &m_listController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), m_listController(this, delegate), m_editExpressionController(editExpressionController) { diff --git a/apps/calculation/additional_outputs/list_controller.h b/apps/calculation/additional_outputs/list_controller.h index 86f24b227..0378c90b6 100644 --- a/apps/calculation/additional_outputs/list_controller.h +++ b/apps/calculation/additional_outputs/list_controller.h @@ -10,7 +10,7 @@ class EditExpressionController; class ListController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource { public: - ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr); + ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr); // Responder bool handleEvent(Ion::Events::Event event) override; diff --git a/apps/calculation/additional_outputs/rational_list_controller.h b/apps/calculation/additional_outputs/rational_list_controller.h index fac0f06eb..62d0de5a9 100644 --- a/apps/calculation/additional_outputs/rational_list_controller.h +++ b/apps/calculation/additional_outputs/rational_list_controller.h @@ -8,7 +8,7 @@ namespace Calculation { class RationalListController : public ExpressionsListController { public: RationalListController(EditExpressionController * editExpressionController) : - ExpressionsListController(nullptr, editExpressionController) {} + ExpressionsListController(editExpressionController) {} //ListViewDataSource int numberOfRows() const override; diff --git a/apps/calculation/additional_outputs/trigonometry_list_controller.h b/apps/calculation/additional_outputs/trigonometry_list_controller.h index dfec810d9..12880e1a0 100644 --- a/apps/calculation/additional_outputs/trigonometry_list_controller.h +++ b/apps/calculation/additional_outputs/trigonometry_list_controller.h @@ -10,7 +10,7 @@ namespace Calculation { class TrigonometryListController : public IllustratedListController { public: TrigonometryListController(EditExpressionController * editExpressionController) : - IllustratedListController(nullptr, editExpressionController), + IllustratedListController(editExpressionController), m_graphCell(&m_model) {} void setExpression(Poincare::Expression e) override; private: From 63ab8710b916eb4b37322b60e24314b14f05b205 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 14:10:47 +0100 Subject: [PATCH 031/453] [apps/calculation] Factor EditExpressionController::insertTextBody --- apps/calculation/additional_outputs/list_controller.cpp | 1 - apps/calculation/edit_expression_controller.cpp | 1 + apps/calculation/history_controller.cpp | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/calculation/additional_outputs/list_controller.cpp b/apps/calculation/additional_outputs/list_controller.cpp index a7ebab267..16f9c9ef6 100644 --- a/apps/calculation/additional_outputs/list_controller.cpp +++ b/apps/calculation/additional_outputs/list_controller.cpp @@ -38,7 +38,6 @@ bool ListController::handleEvent(Ion::Events::Event event) { * insertTextBody. */ Container::activeApp()->dismissModalViewController(); m_editExpressionController->insertTextBody(buffer); - Container::activeApp()->setFirstResponder(m_editExpressionController); return true; } return false; diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 5e69bfee8..b0eb752c9 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -48,6 +48,7 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, } void EditExpressionController::insertTextBody(const char * text) { + Container::activeApp()->setFirstResponder(this); m_contentView.expressionField()->handleEventWithText(text, false, true); } diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 251cc3a1f..5f7424105 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -78,11 +78,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { EditExpressionController * editController = (EditExpressionController *)parentResponder(); if (subviewType == SubviewType::Input) { m_selectableTableView.deselectTable(); - Container::activeApp()->setFirstResponder(editController); editController->insertTextBody(calculationAtIndex(focusRow)->inputText()); } else if (subviewType == SubviewType::Output) { m_selectableTableView.deselectTable(); - Container::activeApp()->setFirstResponder(editController); Shared::ExpiringPointer calculation = calculationAtIndex(focusRow); ScrollableTwoExpressionsView::SubviewPosition outputSubviewPosition = selectedCell->outputView()->selectedSubviewPosition(); if (outputSubviewPosition == ScrollableTwoExpressionsView::SubviewPosition::Right From 167827f0e4b29b6931c961b8a77d8fcab9c175ee Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 11 Mar 2020 15:24:36 +0100 Subject: [PATCH 032/453] [apps/calculation] EditExpressionController accesses subview directly --- apps/calculation/edit_expression_controller.cpp | 2 +- apps/calculation/history_controller.cpp | 4 ---- apps/calculation/history_controller.h | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index b0eb752c9..b02f63211 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -54,7 +54,7 @@ void EditExpressionController::insertTextBody(const char * text) { void EditExpressionController::didBecomeFirstResponder() { int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; - m_historyController->scrollToCell(0, lastRow); + m_contentView.mainView()->scrollToCell(0, lastRow); m_contentView.expressionField()->setEditing(true, false); Container::activeApp()->setFirstResponder(m_contentView.expressionField()); } diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 5f7424105..50a3b8591 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -223,10 +223,6 @@ int HistoryController::typeAtLocation(int i, int j) { return 0; } -void HistoryController::scrollToCell(int i, int j) { - m_selectableTableView.scrollToCell(i, j); -} - bool HistoryController::calculationAtIndexToggles(int index) { Context * context = App::app()->localContext(); return index >= 0 && index < m_calculationStore->numberOfCalculations() && calculationAtIndex(index)->displayOutput(context) == Calculation::DisplayOutput::ExactAndApproximateToggle; diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index 407e52805..606637edb 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -31,7 +31,6 @@ public: KDCoordinate rowHeight(int j) override; int typeAtLocation(int i, int j) override; void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; - void scrollToCell(int i, int j); private: int storeIndex(int i) { return numberOfRows() - i - 1; } Shared::ExpiringPointer calculationAtIndex(int i); From f3bcedd43d4a61fc4824644d12152542aa2053fa Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 16:19:33 +0100 Subject: [PATCH 033/453] [apps/calculation/history_controller] Simplify and harmonize handleEvent --- apps/calculation/history_controller.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 50a3b8591..996df73cd 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -118,11 +118,10 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { int focusRow = selectedRow(); SubviewType subviewType = selectedSubviewType(); m_selectableTableView.deselectTable(); - EditExpressionController * editController = (EditExpressionController *)parentResponder(); m_calculationStore->deleteCalculationAtIndex(storeIndex(focusRow)); reload(); if (numberOfRows()== 0) { - Container::activeApp()->setFirstResponder(editController); + Container::activeApp()->setFirstResponder(parentResponder()); return true; } if (focusRow > 0) { @@ -146,9 +145,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } if (event == Ion::Events::Back) { - EditExpressionController * editController = (EditExpressionController *)parentResponder(); m_selectableTableView.deselectTable(); - Container::activeApp()->setFirstResponder(editController); + Container::activeApp()->setFirstResponder(parentResponder()); return true; } return false; From a3265996fe9e8b601a1025deed4869099b482848 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 16:22:17 +0100 Subject: [PATCH 034/453] [apps/calculation/history_controller] Factor handleEvent --- apps/calculation/history_controller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 996df73cd..8b245c289 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -124,11 +124,7 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { Container::activeApp()->setFirstResponder(parentResponder()); return true; } - if (focusRow > 0) { - m_selectableTableView.selectCellAtLocation(0, focusRow-1); - } else { - m_selectableTableView.selectCellAtLocation(0, 0); - } + m_selectableTableView.selectCellAtLocation(0, (focusRow > 0) * (focusRow - 1)); if (subviewType == SubviewType::Input) { tableViewDidChangeSelection(&m_selectableTableView, 0, selectedRow()); } else { From a31524173f828bdcb7304e34b453220720a87de6 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 16:29:07 +0100 Subject: [PATCH 035/453] [apps/calculation/history_controller] Factor handleEvent --- apps/calculation/history_controller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 8b245c289..cafa5c4cd 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -125,11 +125,7 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, (focusRow > 0) * (focusRow - 1)); - if (subviewType == SubviewType::Input) { - tableViewDidChangeSelection(&m_selectableTableView, 0, selectedRow()); - } else { - tableViewDidChangeSelection(&m_selectableTableView, 0, -1); - } + tableViewDidChangeSelection(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); m_selectableTableView.scrollToCell(0, selectedRow()); return true; } From 8365735f983c18c940fe88020a66efa0134a2cfd Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 17:26:25 +0100 Subject: [PATCH 036/453] [apps/calculation/additional_outputs/expression_list_controller] Computed Layouts must not be uninitialized --- .../additional_outputs/expressions_list_controller.cpp | 4 +--- .../additional_outputs/integer_list_controller.cpp | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/calculation/additional_outputs/expressions_list_controller.cpp b/apps/calculation/additional_outputs/expressions_list_controller.cpp index 956933b0b..2ea1b3ef3 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.cpp +++ b/apps/calculation/additional_outputs/expressions_list_controller.cpp @@ -38,9 +38,7 @@ HighlightCell * ExpressionsListController::reusableCell(int index, int type) { KDCoordinate ExpressionsListController::rowHeight(int j) { Layout l = layoutAtIndex(j); - if (l.isUninitialized()) { - return 0; - } + assert(!l.isUninitialized()); return l.layoutSize().height() + 2 * Metric::CommonSmallMargin + Metric::CellSeparatorThickness; } diff --git a/apps/calculation/additional_outputs/integer_list_controller.cpp b/apps/calculation/additional_outputs/integer_list_controller.cpp index 1e5bb0cb8..98deb516d 100644 --- a/apps/calculation/additional_outputs/integer_list_controller.cpp +++ b/apps/calculation/additional_outputs/integer_list_controller.cpp @@ -28,9 +28,6 @@ Integer::Base baseAtIndex(int index) { } void IntegerListController::computeLayoutAtIndex(int index) { - if (!m_layouts[index].isUninitialized()) { - return; - } assert(m_expression.type() == ExpressionNode::Type::BasedInteger); // For index = k_indexOfFactorExpression, the layout is assumed to be alreday memoized because it is needed to compute the numberOfRows assert(index < k_indexOfFactorExpression); @@ -65,6 +62,6 @@ bool IntegerListController::factorExpressionIsComputable() const { } m_layouts[k_indexOfFactorExpression] = EmptyLayout::Builder(); return false; +} } -} From 032723eae1772b79f8104d96c231706c7243e2a7 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 10:07:05 +0100 Subject: [PATCH 037/453] [poincare/layout_node] Remove unused variable --- poincare/src/layout_node.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/poincare/src/layout_node.cpp b/poincare/src/layout_node.cpp index 7c33a2f3d..6058df3f2 100644 --- a/poincare/src/layout_node.cpp +++ b/poincare/src/layout_node.cpp @@ -169,7 +169,6 @@ bool LayoutNode::protectedIsIdenticalTo(Layout l) { return false; } for (int i = 0; i < numberOfChildren(); i++) { - Layout child = childAtIndex(i); if (!childAtIndex(i)->isIdenticalTo(l.childAtIndex(i))) { return false; } From 121e16a6a5422c03e3254acfa206bdf91e366959 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 16 Mar 2020 11:53:33 +0100 Subject: [PATCH 038/453] [poincare/absolute_value] AbsoluteValue has no Unit shallowReduce returns Undefined if its unique child has a Unit --- poincare/include/poincare/absolute_value.h | 1 - poincare/src/absolute_value.cpp | 4 ---- 2 files changed, 5 deletions(-) diff --git a/poincare/include/poincare/absolute_value.h b/poincare/include/poincare/absolute_value.h index e0a12aa6a..57be4dd32 100644 --- a/poincare/include/poincare/absolute_value.h +++ b/poincare/include/poincare/absolute_value.h @@ -33,7 +33,6 @@ public: Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return ApproximationHelper::Map(this, context, complexFormat, angleUnit, computeOnComplex); } - Expression getUnit() const override; // Layout Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index bf4aee0d1..6945e1fc5 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -19,10 +19,6 @@ Expression AbsoluteValueNode::setSign(Sign s, ReductionContext reductionContext) return AbsoluteValue(this); } -Expression AbsoluteValueNode::getUnit() const { - return childAtIndex(0)->getUnit(); -} - Layout AbsoluteValueNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { return AbsoluteValueLayout::Builder(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits)); } From 2fea3c9b3af3553fed2d3b30d19d1eb081cd1fd7 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Mon, 16 Mar 2020 14:57:25 +0100 Subject: [PATCH 039/453] [poincare/addition] Addition has no Unit --- poincare/include/poincare/addition.h | 1 - poincare/src/addition.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/poincare/include/poincare/addition.h b/poincare/include/poincare/addition.h index 63971f23f..d49303723 100644 --- a/poincare/include/poincare/addition.h +++ b/poincare/include/poincare/addition.h @@ -35,7 +35,6 @@ public: template static MatrixComplex computeOnComplexAndMatrix(const std::complex c, const MatrixComplex m, Preferences::ComplexFormat complexFormat) { return MatrixComplex::Undefined(); } - Expression getUnit() const override; // Simplification LayoutShape leftLayoutShape() const override { diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index aa120632a..5d99cce4b 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -29,11 +29,6 @@ int AdditionNode::getPolynomialCoefficients(Context * context, const char * symb return Addition(this).getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } -Expression AdditionNode::getUnit() const { - // The expression is reduced, so we can just ask the unit of the first child - return childAtIndex(0)->getUnit(); -} - // Layout Layout AdditionNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { From f5b964339cb67588dd341ddd84b0ff6104e17e02 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 17 Mar 2020 10:14:03 +0100 Subject: [PATCH 040/453] [poincare/test/expression_properties] Fix helper assert_reduced_expression_unit First reduce Then getUnit --- poincare/test/expression_properties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 5345e5a66..88f49370f 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -371,13 +371,13 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) { void assert_reduced_expression_unit(const char * expression, const char * unit, ExpressionNode::SymbolicComputation symbolicComutation) { Shared::GlobalContext globalContext; - ExpressionNode::ReductionContext redContext = ExpressionNode::ReductionContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation); + ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation); Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(redContext); Expression u1 = e.getUnit(); - u1 = u1.reduce(redContext); Expression u2 = parse_expression(unit, &globalContext, false); u2 = u2.reduce(redContext); + u2 = u2.getUnit(); quiz_assert_print_if_failure(u1.isIdenticalTo(u2), expression); } From 0c4434d088fcee41461190faec00194f6913acfb Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 17 Mar 2020 10:17:42 +0100 Subject: [PATCH 041/453] [poincare/expression] getUnit returns an uninitialized Expression when there is no Unit instead of Undefined --- poincare/src/addition.cpp | 6 +++++- poincare/src/expression_node.cpp | 2 +- poincare/src/multiplication.cpp | 4 ++-- poincare/src/power.cpp | 2 +- poincare/src/unit_convert.cpp | 2 +- poincare/test/expression_properties.cpp | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 5d99cce4b..02167bf56 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -160,8 +160,12 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon * the result is not homogeneous. */ { Expression unit = childAtIndex(0).getUnit(); + const bool hasUnit = !unit.isUninitialized(); for (int i = 1; i < childrenCount; i++) { - if (!unit.isIdenticalTo(childAtIndex(i).getUnit())) { + Expression otherUnit = childAtIndex(i).getUnit(); + if (hasUnit == otherUnit.isUninitialized() || + (hasUnit && !unit.isIdenticalTo(otherUnit))) + { return replaceWithUndefinedInPlace(); } } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 94115d40e..1ac78e729 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -137,7 +137,7 @@ bool ExpressionNode::isOfType(Type * types, int length) const { } Expression ExpressionNode::getUnit() const { - return Undefined::Builder(); + return Expression(); } void ExpressionNode::setChildrenInPlace(Expression other) { diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 68e366239..14ba43034 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -264,13 +264,13 @@ Expression Multiplication::getUnit() const { int resultChildrenCount = 0; for (int i = 0; i < childrenCount; i++) { Expression currentUnit = childAtIndex(i).getUnit(); - if (!currentUnit.isUndefined()) { + if (!currentUnit.isUninitialized()) { result.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount); resultChildrenCount++; } } if (resultChildrenCount == 0) { - return Undefined::Builder(); + return Expression(); } return std::move(result); } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index da0579f72..d6f27e7bb 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -987,7 +987,7 @@ Expression Power::getUnit() const { return clone(); } Expression baseUnit = childAtIndex(0).getUnit(); - if (baseUnit.isUndefined()) { + if (baseUnit.isUninitialized()) { return baseUnit; } return Power::Builder(baseUnit, childAtIndex(1).clone()); diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 4dfc699ba..0002bb500 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -42,7 +42,7 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits); Expression unit = childAtIndex(1).clone().reduce(reductionContextWithUnits).getUnit(); - if (unit.isUndefined()) { + if (unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); } diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 88f49370f..854888d5b 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -378,7 +378,7 @@ void assert_reduced_expression_unit(const char * expression, const char * unit, Expression u2 = parse_expression(unit, &globalContext, false); u2 = u2.reduce(redContext); u2 = u2.getUnit(); - quiz_assert_print_if_failure(u1.isIdenticalTo(u2), expression); + quiz_assert_print_if_failure(u1.isUninitialized() == u2.isUninitialized() && (u1.isUninitialized() || u1.isIdenticalTo(u2)), expression); } QUIZ_CASE(poincare_properties_get_unit) { From 4558e777c86c90388ea6bfce35c7a5d7a094ba61 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 11:19:39 +0100 Subject: [PATCH 042/453] [poincare/multiplication] Remove old TODO --- poincare/src/multiplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 14ba43034..f89fae016 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -796,7 +796,7 @@ void Multiplication::mergeMultiplicationChildrenInPlace() { while (i < numberOfChildren()) { Expression c = childAtIndex(i); if (c.type() == ExpressionNode::Type::Multiplication) { - mergeChildrenAtIndexInPlace(c, i); // TODO: ensure that matrix children are not swapped to implement MATRIX_EXACT_REDUCING + mergeChildrenAtIndexInPlace(c, i); continue; } i++; From 43327e482e4fe8a51e479c1ae2299fdc614994b0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 14:30:38 +0100 Subject: [PATCH 043/453] [poincare/multiplication] Use mergeChildrenAtIndexInPlace instead of mergeMultiplicationChildrenInPlace --- poincare/src/multiplication.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index f89fae016..38b9fd4e3 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -831,7 +831,7 @@ void Multiplication::mergeInChildByFactorizingBase(int i, Expression e, Expressi * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication * node with this. */ if (p.type() == ExpressionNode::Type::Multiplication) { - mergeMultiplicationChildrenInPlace(); + mergeChildrenAtIndexInPlace(p, i); } } @@ -852,7 +852,7 @@ void Multiplication::factorizeExponent(int i, int j, ExpressionNode::ReductionCo * ie: 12^(1/2) -> 2*3^(1/2). In that case, we need to merge the multiplication * node with this. */ if (p.type() == ExpressionNode::Type::Multiplication) { - mergeMultiplicationChildrenInPlace(); + mergeChildrenAtIndexInPlace(p, i); } } From 965e3b1d9afc57bf5fc98ea4ae2606dff7effb6f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 11:39:13 +0100 Subject: [PATCH 044/453] [poincare/n_ary_expression] Factor mergeMultiplicationChildrenInPlace from Multiplication to NAryExpression so as to use it in Addition --- poincare/include/poincare/multiplication.h | 3 --- poincare/include/poincare/n_ary_expression.h | 1 + poincare/src/addition.cpp | 11 ++--------- poincare/src/multiplication.cpp | 17 ++--------------- poincare/src/n_ary_expression.cpp | 15 +++++++++++++++ poincare/src/unit_convert.cpp | 2 +- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 256c1d479..cf16e64ba 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -63,10 +63,8 @@ private: }; class Multiplication : public NAryExpression { - friend class AdditionNode; friend class Addition; friend class Power; - friend class UnitConvert; public: Multiplication(const MultiplicationNode * n) : NAryExpression(n) {} static Multiplication Builder(const Tuple & children = {}) { return TreeHandle::NAryBuilder(convert(children)); } @@ -92,7 +90,6 @@ public: private: // Simplification Expression privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool expand, bool canBeInterrupted); - void mergeMultiplicationChildrenInPlace(); void factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext); void mergeInChildByFactorizingBase(int i, Expression e, ExpressionNode::ReductionContext reductionContext); void factorizeExponent(int i, int j, ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/include/poincare/n_ary_expression.h b/poincare/include/poincare/n_ary_expression.h index 6db14d2ed..97455f3af 100644 --- a/poincare/include/poincare/n_ary_expression.h +++ b/poincare/include/poincare/n_ary_expression.h @@ -52,6 +52,7 @@ public: Expression squashUnaryHierarchyInPlace() { return node()->squashUnaryHierarchyInPlace(); } + void mergeSameTypeChildrenInPlace(); /* allChildrenAreReal returns: * - 1 if all children are real * - 0 if all non real children are ComplexCartesian diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 02167bf56..9db97c40d 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -144,14 +144,7 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon /* Step 1: Addition is associative, so let's start by merging children which * are additions. */ - int i = 0; - while (i < numberOfChildren()) { - if (childAtIndex(i).type() == ExpressionNode::Type::Addition) { - mergeChildrenAtIndexInPlace(childAtIndex(i), i); - continue; - } - i++; - } + mergeSameTypeChildrenInPlace(); const int childrenCount = numberOfChildren(); assert(childrenCount > 1); @@ -230,7 +223,7 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon /* Step 5: Factorize like terms. Thanks to the simplification order, those are * next to each other at this point. */ - i = 0; + int i = 0; while (i < numberOfChildren()-1) { Expression e1 = childAtIndex(i); Expression e2 = childAtIndex(i+1); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 38b9fd4e3..9a7fff846 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -481,7 +481,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } // Build final Expression result = Multiplication::Builder(resultWithoutUnit, units); - static_cast(result).mergeMultiplicationChildrenInPlace(); + static_cast(result).mergeSameTypeChildrenInPlace(); } } @@ -505,7 +505,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext /* Step 1: MultiplicationNode is associative, so let's start by merging children * which also are multiplications themselves. */ - mergeMultiplicationChildrenInPlace(); + mergeSameTypeChildrenInPlace(); Context * context = reductionContext.context(); @@ -790,19 +790,6 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext return result; } -void Multiplication::mergeMultiplicationChildrenInPlace() { - // Multiplication is associative: a*(b*c)->a*b*c - int i = 0; - while (i < numberOfChildren()) { - Expression c = childAtIndex(i); - if (c.type() == ExpressionNode::Type::Multiplication) { - mergeChildrenAtIndexInPlace(c, i); - continue; - } - i++; - } -} - void Multiplication::factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext) { /* This function factorizes two children which have a common base. For example * if this is Multiplication::Builder(pi^2, pi^3), then pi^2 and pi^3 could be merged diff --git a/poincare/src/n_ary_expression.cpp b/poincare/src/n_ary_expression.cpp index 917877808..314f4b8cb 100644 --- a/poincare/src/n_ary_expression.cpp +++ b/poincare/src/n_ary_expression.cpp @@ -97,6 +97,21 @@ int NAryExpressionNode::simplificationOrderGreaterType(const ExpressionNode * e, return 0; } +void NAryExpression::mergeSameTypeChildrenInPlace() { + // Multiplication is associative: a*(b*c)->a*b*c + // The same goes for Addition + ExpressionNode::Type parentType = type(); + int i = 0; + while (i < numberOfChildren()) { + Expression c = childAtIndex(i); + if (c.type() != parentType) { + i++; + } else { + mergeChildrenAtIndexInPlace(c, i); + } + } +} + int NAryExpression::allChildrenAreReal(Context * context) const { int i = 0; int result = 1; diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 0002bb500..a4d4fedd5 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -71,7 +71,7 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction return Undefined::Builder(); } division = Multiplication::Builder(Float::Builder(floatValue), finalUnit); - static_cast(division).mergeMultiplicationChildrenInPlace(); + static_cast(division).mergeSameTypeChildrenInPlace(); replaceWithInPlace(division); return division; } From f224ac31e3df06eafa1eab14dbe26d40956a6dec Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 24 Mar 2020 15:39:35 +0100 Subject: [PATCH 045/453] [poincare/n_ary_expression] Add TODO about mergeSameTypeChildrenInPlace --- poincare/src/addition.cpp | 5 ++++- poincare/src/multiplication.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 9db97c40d..501a57a10 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -143,7 +143,10 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon } /* Step 1: Addition is associative, so let's start by merging children which - * are additions. */ + * are additions. + * TODO If the parent Expression is an Addition, one should perhaps + * return now and let the parent do the reduction. + */ mergeSameTypeChildrenInPlace(); const int childrenCount = numberOfChildren(); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 9a7fff846..e97e3b3ec 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -504,7 +504,10 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext } /* Step 1: MultiplicationNode is associative, so let's start by merging children - * which also are multiplications themselves. */ + * which also are multiplications themselves. + * TODO If the parent Expression is a Multiplication, one should perhaps + * return now and let the parent do the reduction. + */ mergeSameTypeChildrenInPlace(); Context * context = reductionContext.context(); From c181650922a5ec26c8746d4c124ddeb3ff435b9f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 16:34:16 +0100 Subject: [PATCH 046/453] [poincare/multiplication] Simplify privateShallowReduce --- poincare/src/multiplication.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index e97e3b3ec..641a13fa0 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -613,10 +613,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext Expression oi1 = childAtIndex(i+1); if (oi.recursivelyMatches(Expression::IsRandom, context, true)) { // Do not factorize random or randint - i++; - continue; - } - if (TermsHaveIdenticalBase(oi, oi1)) { + } else if (TermsHaveIdenticalBase(oi, oi1)) { bool shouldFactorizeBase = true; if (TermHasNumeralBase(oi)) { /* Combining powers of a given rational isn't straightforward. Indeed, @@ -669,8 +666,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * i*i -> -1 * 2^(1/2)*2^(1/2) -> 2 * sin(x)*cos(x) -> 1*tan(x) - * Last, we remove the only rational child if it is one and not the only - * child. */ + */ i = 1; while (i < numberOfChildren()) { Expression o = childAtIndex(i); @@ -709,15 +705,15 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * If the first child is 1, we remove it if there are other children. */ { const Expression c = childAtIndex(0); - if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isZero()) { + if (c.type() != ExpressionNode::Type::Rational) { + } else if (static_cast(c).isZero()) { // Check that other children don't match inf or unit bool infiniteOrUnitFactor = recursivelyMatches([](const Expression e, Context * context) { return Expression::IsInfinity(e,context) || e.type() == ExpressionNode::Type::Unit; }, context); if (!infiniteOrUnitFactor) { replaceWithInPlace(c); return c; } - } - if (c.type() == ExpressionNode::Type::Rational && static_cast(c).isOne() && numberOfChildren() > 1) { + } else if (static_cast(c).isOne() && numberOfChildren() > 1) { removeChildAtIndexInPlace(0); } } @@ -764,17 +760,18 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext assert(childAtIndex(i).type() == ExpressionNode::Type::ComplexCartesian); // First, we merge all ComplexCartesian children into one ComplexCartesian child = childAtIndex(i).convert(); - removeChildAtIndexInPlace(i); - i--; - while (i >= 0) { + while (true) { + removeChildAtIndexInPlace(i); + i--; + if (i < 0) { + break; + } Expression e = childAtIndex(i); if (e.type() != ExpressionNode::Type::ComplexCartesian) { // the Multiplication is sorted so ComplexCartesian nodes are the last ones break; } child = child.multiply(static_cast(e), reductionContext); - removeChildAtIndexInPlace(i); - i--; } // The real children are both factors of the real and the imaginary multiplication Multiplication real = *this; From fa1235939b874dd6618c30e8c6bb76717d00ae23 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 19 Mar 2020 17:01:34 +0100 Subject: [PATCH 047/453] [poincare/multiplication] Correct cast --- poincare/src/multiplication.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 641a13fa0..ae83023e6 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -676,8 +676,8 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext } if (o.isNumber()) { if (childAtIndex(0).isNumber()) { - Number o0 = childAtIndex(0).convert(); - Number m = Number::Multiplication(o0, static_cast(o)); + Expression o0 = childAtIndex(0); + Number m = Number::Multiplication(static_cast(o0), static_cast(o)); if ((IsInfinity(m, context) || m.isUndefined()) && !IsInfinity(o0, context) && !o0.isUndefined() && !IsInfinity(o, context) && !o.isUndefined()) From 1351babe375e290c7f518dbc7127c7ad22623741 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 20 Mar 2020 10:25:16 +0100 Subject: [PATCH 048/453] [poincare] Move Power vs Unit checks to Power::shallowReduce --- poincare/src/power.cpp | 15 ++++++++++++--- poincare/src/unit.cpp | 6 ------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index d6f27e7bb..d66ab2273 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -387,9 +387,18 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex Expression base = childAtIndex(0); Expression index = childAtIndex(1); - // Step 1: There should be no unit in the index! - if (index.hasUnit()) { - return replaceWithUndefinedInPlace(); + // Step 1: Handle the units + { + if (index.hasUnit()) { + // There must be no unit in the exponent + return replaceWithUndefinedInPlace(); + } + if (base.hasUnit()) { + if (index.type() != ExpressionNode::Type::Rational || !static_cast(index).isInteger()) { + // The exponent must be an Integer + return replaceWithUndefinedInPlace(); + } + } } // Step 2: Handle matrices diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index f8617f0df..d461ccb17 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -323,12 +323,7 @@ Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionConte m.addChildAtIndexInPlace(*this, 1, 1); return std::move(m); } - // Check that the exponent, if any, of a Unit is an integer if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Power) { - Expression exponent = ancestor.childAtIndex(1); - if (!(exponent.type() == ExpressionNode::Type::Rational && static_cast(exponent).isInteger())) { - goto UnitCheckUnsuccessful; - } ancestor = ancestor.parent(); } /* Check homogeneity: at this point, ancestor must be @@ -344,7 +339,6 @@ Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionConte if (ancestor.isUninitialized()) { return *this; } - UnitCheckUnsuccessful: /* If the latter checks are not successfully passed, then the function * returns replaceWithUndefinedInPlace. * TODO Something else should be returned in order to report a more From b8786dd32c3ff4aea058f40b6d064b8fef13d437 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 27 Mar 2020 09:52:52 +0100 Subject: [PATCH 049/453] Revert "[poincare/multiplication] Fix handling of units with non-integer exponent" This reverts commit 50f1ee97210bba7a3420ea7711245598489ff4cf. Since Power::shallowReduce now checks that the exponent of a Unit is an Integer, instead of Unit::shallowBeautify, there is no need anymore to handle that in Multiplication::splitIntoNormalForm. --- poincare/src/multiplication.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index ae83023e6..241f21e27 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -1032,20 +1032,7 @@ void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & de Expression fd = factor.denominator(reductionContext); if (fd.isUninitialized()) { if (factor.childAtIndex(0).type() == ExpressionNode::Type::Unit) { - /* A Unit should only have integer exponents, otherwise - * simplification returns Undefined. That will be handled later in - * Unit::shallowBeautify: since an Expression is beautified from - * children to parent, the children of the current Multiplication are - * not beautified yet and the exponent of a Unit is not guaranted at - * this point to be an integer. Until then, any Unit with non-integer - * exponent, is flushed into the numerator instead of units. - */ - Expression exponent = factor.childAtIndex(1); - if (exponent.type() == ExpressionNode::Type::Rational && static_cast(exponent).isInteger()) { - factorsUnit = factor; - } else { - factorsNumerator = factor; - } + factorsUnit = factor; } else { factorsNumerator = factor; } From 4d1129b0dbb529a69a035049c3fad69803c5a924 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 26 Mar 2020 10:06:17 +0100 Subject: [PATCH 050/453] [poincare/multiplication] Reorder steps in shallowBeautify --- poincare/src/multiplication.cpp | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 241f21e27..c88746387 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -352,12 +352,19 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Expression numer, denom, units; splitIntoNormalForm(numer, denom, units, reductionContext); - /* Step 2: Recognize derived units - * The reason why 'units' is handled before 'numer' and 'denom' is that this - * step is likely to alter the latter Expressions. + // Step 2: Create a Division if relevant + Expression result; + if (!numer.isUninitialized()) { + result = numer; + } + if (!denom.isUninitialized()) { + result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); + } + + /* Step 3: Handle the units */ if (!units.isUninitialized()) { - /* In the following: + /* Recognize derived units * - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most. * - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'. * - Repeat those steps until no more simplification is possible. @@ -405,21 +412,10 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); units = Multiplication::Builder(unitsAccu, units).shallowReduce(reductionContext); } - } - // Step 3: Create a Division if relevant - Expression result; - if (!numer.isUninitialized()) { - result = numer; - } - if (!denom.isUninitialized()) { - result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); - } - - // Step 4: Turn into 'Float x units' and choose a unit multiple adequate for - // the numerical value - if (!units.isUninitialized()) { - /* An exhaustive exploration of all possible multiples would have + /* Turn into 'Float x units'. + * Choose a unit multiple adequate for the numerical value. + * An exhaustive exploration of all possible multiples would have * exponential complexity with respect to the number of factors. Instead, * we focus on one single factor. The first Unit factor is certainly the * most relevant. From 2895d365a68356532a8d0bdeff046a7c25c14512 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 20 Mar 2020 15:08:43 +0100 Subject: [PATCH 051/453] [poincare/multiplication] Make sure a Multiplication is not made of (Power of) Units only --- poincare/src/multiplication.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index c88746387..5813ec84b 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -360,6 +360,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu if (!denom.isUninitialized()) { result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); } + assert(!result.isUninitialized()); /* Step 3: Handle the units */ @@ -427,18 +428,15 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu Expression unitsNumer, unitsDenom, unitsUnits; static_cast(units).splitIntoNormalForm(unitsNumer, unitsDenom, unitsUnits, reductionContext); if (!unitsNumer.isUninitialized()) { - result = result.isUninitialized() ? unitsNumer : Multiplication::Builder(result, unitsNumer); + result = Multiplication::Builder(result, unitsNumer); } if (!unitsDenom.isUninitialized()) { - result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, unitsDenom); + result = Division::Builder(result, unitsDenom); } units = unitsUnits; } - double value = 1.0; - if (!result.isUninitialized()) { - value = result.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); - } + double value = result.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (std::isnan(value)) { // If the value is undefined, return "undef" without any unit result = Undefined::Builder(); @@ -701,11 +699,15 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * If the first child is 1, we remove it if there are other children. */ { const Expression c = childAtIndex(0); - if (c.type() != ExpressionNode::Type::Rational) { + if (hasUnit()) { + // Make sure a Multiplication is not made of (Power of) Units only + if (!c.isNumber()) { + addChildAtIndexInPlace(Rational::Builder(1), 0, numberOfChildren()); + } + } else if (c.type() != ExpressionNode::Type::Rational) { } else if (static_cast(c).isZero()) { // Check that other children don't match inf or unit - bool infiniteOrUnitFactor = recursivelyMatches([](const Expression e, Context * context) { return Expression::IsInfinity(e,context) || e.type() == ExpressionNode::Type::Unit; }, context); - if (!infiniteOrUnitFactor) { + if (!recursivelyMatches(IsInfinity, context)) { replaceWithInPlace(c); return c; } From c12ab3a2e27397b82d061713c1f9050bbb44e488 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Mar 2020 17:01:45 +0100 Subject: [PATCH 052/453] [poincare/multiplication] Simplify shallowBeautify --- poincare/src/multiplication.cpp | 34 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 5813ec84b..fc8aa8922 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -411,7 +411,25 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } if (unitsAccu.numberOfChildren() > 0) { units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); - units = Multiplication::Builder(unitsAccu, units).shallowReduce(reductionContext); + units = Multiplication::Builder(units); + static_cast(units).mergeSameTypeChildrenInPlace(); + { + Expression unitsNumer, unitsDenom, unitsUnits; + static_cast(units).splitIntoNormalForm(unitsNumer, unitsDenom, unitsUnits, reductionContext); + if (!unitsNumer.isUninitialized()) { + result = Multiplication::Builder(result, unitsNumer); + } + if (!unitsDenom.isUninitialized()) { + result = Division::Builder(result, unitsDenom); + } + units = unitsUnits; + } + if (units.isUninitialized()) { + units = unitsAccu; + } else { + units = Multiplication::Builder(unitsAccu, units); + static_cast(units).mergeSameTypeChildrenInPlace(); + } } /* Turn into 'Float x units'. @@ -421,20 +439,6 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * we focus on one single factor. The first Unit factor is certainly the * most relevant. */ - if (units.type() == ExpressionNode::Type::Multiplication) { - /* First, as step 2 might have introduced non Unit factors in 'units', - * 'units' must be split again. - */ - Expression unitsNumer, unitsDenom, unitsUnits; - static_cast(units).splitIntoNormalForm(unitsNumer, unitsDenom, unitsUnits, reductionContext); - if (!unitsNumer.isUninitialized()) { - result = Multiplication::Builder(result, unitsNumer); - } - if (!unitsDenom.isUninitialized()) { - result = Division::Builder(result, unitsDenom); - } - units = unitsUnits; - } double value = result.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (std::isnan(value)) { From 9a762f1bf635f37998645e1f4ae20600982642db Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 18 Mar 2020 14:25:13 +0100 Subject: [PATCH 053/453] [poincare] A (Power of) Unit must not be orphan --- poincare/src/power.cpp | 14 ++++---------- poincare/src/unit.cpp | 12 ++++-------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index d66ab2273..f5a04957c 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -398,6 +397,10 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // The exponent must be an Integer return replaceWithUndefinedInPlace(); } + if (parent().isUninitialized() && base.type() == ExpressionNode::Type::Unit) { + // A Power of Unit must not be orphan + return Multiplication::Builder(Rational::Builder(1), *this); + } } } @@ -979,15 +982,6 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont replaceWithInPlace(result); return result; } - - // Step 4: Force Float(1) in front of an orphan Power of Unit - if (parent().isUninitialized() && childAtIndex(0).type() == ExpressionNode::Type::Unit) { - Multiplication m = Multiplication::Builder(Float::Builder(1.0)); - replaceWithInPlace(m); - m.addChildAtIndexInPlace(*this, 1, 1); - return std::move(m); - } - return *this; } diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index d461ccb17..344654270 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -310,19 +309,16 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext Expression multiplier = Power::Builder(Rational::Builder(10), Rational::Builder(prefixMultiplier)).shallowReduce(reductionContext); result = Multiplication::Builder(multiplier, result).shallowReduce(reductionContext); } + if (parent().isUninitialized() && result.type() == ExpressionNode::Type::Unit) { + // A Unit must not be orphan + result = Multiplication::Builder(Rational::Builder(1), result); + } replaceWithInPlace(result); return result; } Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { Expression ancestor = parent(); - // Force Float(1) in front of an orphan Unit - if (ancestor.isUninitialized()) { - Multiplication m = Multiplication::Builder(Float::Builder(1.0)); - replaceWithInPlace(m); - m.addChildAtIndexInPlace(*this, 1, 1); - return std::move(m); - } if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Power) { ancestor = ancestor.parent(); } From f2bfc7ec9baf9b1dceabc52c86632cf1ea8c7fd3 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 20 Mar 2020 15:47:06 +0100 Subject: [PATCH 054/453] [poincare/expression] Remove redundancies in getUnit --- poincare/src/multiplication.cpp | 7 ++----- poincare/src/power.cpp | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index fc8aa8922..c482edb56 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -256,12 +256,9 @@ int Multiplication::getPolynomialCoefficients(Context * context, const char * sy } Expression Multiplication::getUnit() const { - const int childrenCount = numberOfChildren(); - if (childrenCount == 1) { - return childAtIndex(0).getUnit(); - } Multiplication result = Multiplication::Builder(); int resultChildrenCount = 0; + const int childrenCount = numberOfChildren(); for (int i = 0; i < childrenCount; i++) { Expression currentUnit = childAtIndex(i).getUnit(); if (!currentUnit.isUninitialized()) { @@ -272,7 +269,7 @@ Expression Multiplication::getUnit() const { if (resultChildrenCount == 0) { return Expression(); } - return std::move(result); + return result.squashUnaryHierarchyInPlace(); } template diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index f5a04957c..b8f096678 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -986,9 +986,6 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont } Expression Power::getUnit() const { - if (childAtIndex(0).type() == ExpressionNode::Type::Unit) { - return clone(); - } Expression baseUnit = childAtIndex(0).getUnit(); if (baseUnit.isUninitialized()) { return baseUnit; From 94e1fdfc7a30b54eb87146958c5ee01b3cfa4f94 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 26 Mar 2020 14:21:05 +0100 Subject: [PATCH 055/453] [poincare/test/simplification] Uncomment passing tests --- poincare/test/simplification.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 3438a414d..e4bb5fd41 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -305,10 +305,10 @@ QUIZ_CASE(poincare_simplification_units) { * expression */ assert_parsed_expression_simplify_to("0×_s", "0×_s"); assert_parsed_expression_simplify_to("inf×_s", "inf×_s"); - //assert_parsed_expression_simplify_to("-inf×_s", "-inf×_s"); + assert_parsed_expression_simplify_to("-inf×_s", "-inf×_s"); assert_parsed_expression_simplify_to("2_s+3_s-5_s", "0×_s"); assert_parsed_expression_simplify_to("normcdf(0,20,3)×_s", "0×_s"); - //assert_parsed_expression_simplify_to("log(0)×_s", "-inf×_s"); + assert_parsed_expression_simplify_to("log(0)×_s", "-inf×_s"); assert_parsed_expression_simplify_to("log(undef)*_s", "undef"); /* Units with invalid exponent */ From bf9653d51035c1440084f6b623467b13d17772fa Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 24 Mar 2020 16:17:04 +0100 Subject: [PATCH 056/453] [poincare/expression] Turn getUnit into extractUnits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addition::shallowReduce factors the unit across its terms. Previously expressions of the form 1_m+π_m were reduced to undef. --- poincare/include/poincare/division.h | 2 +- poincare/include/poincare/empty_expression.h | 2 +- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/expression_node.h | 2 +- poincare/include/poincare/function.h | 3 --- poincare/include/poincare/multiplication.h | 4 ++-- poincare/include/poincare/nth_root.h | 2 +- poincare/include/poincare/parenthesis.h | 2 +- poincare/include/poincare/power.h | 3 +-- poincare/include/poincare/subtraction.h | 2 +- poincare/include/poincare/unit.h | 3 +-- poincare/include/poincare/unit_convert.h | 2 +- poincare/src/addition.cpp | 21 +++++++++++++++++-- poincare/src/expression_node.cpp | 2 +- poincare/src/multiplication.cpp | 22 ++++++++++++++------ poincare/src/power.cpp | 16 ++++++-------- poincare/src/unit.cpp | 4 ++-- poincare/src/unit_convert.cpp | 4 ++-- poincare/test/expression_properties.cpp | 4 ++-- poincare/test/simplification.cpp | 1 + 20 files changed, 61 insertions(+), 42 deletions(-) diff --git a/poincare/include/poincare/division.h b/poincare/include/poincare/division.h index 262f4a418..602f1184d 100644 --- a/poincare/include/poincare/division.h +++ b/poincare/include/poincare/division.h @@ -25,7 +25,7 @@ public: // Properties Type type() const override { return Type::Division; } int polynomialDegree(Context * context, const char * symbolName) const override; - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Approximation virtual Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { diff --git a/poincare/include/poincare/empty_expression.h b/poincare/include/poincare/empty_expression.h index 3814f3e91..3a64cac18 100644 --- a/poincare/include/poincare/empty_expression.h +++ b/poincare/include/poincare/empty_expression.h @@ -22,7 +22,7 @@ public: // Properties Type type() const override { return Type::EmptyExpression; } int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Simplification LayoutShape leftLayoutShape() const override { diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index bce4b2490..c25545bca 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -199,7 +199,7 @@ public: Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } /* Units */ - Expression getUnit() const { return node()->getUnit(); } + Expression extractUnits() { return node()->extractUnits(); } bool hasUnit() const; /* Complex */ diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 21b19004d..896a72c28 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -178,7 +178,7 @@ public: virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const; bool isOfType(Type * types, int length) const; - virtual Expression getUnit() const; // Only reduced nodes should answer + virtual Expression extractUnits(); // Only reduced nodes should answer /* Simplification */ /* SimplificationOrder returns: diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index bb2d2f92c..cc64a531b 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -28,9 +28,6 @@ public: int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable, int nextVariableIndex) const override; float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const override; - /* getUnit() is ExpressionNode::getUnit -> - * as the function is reduced, it would have been replaced if it had a - * definition. It thus has no definition, so no unit. */ private: char m_name[0]; // MUST be the last member variable diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index cf16e64ba..1021ec9e0 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -25,7 +25,7 @@ public: int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression getUnit() const override; + Expression extractUnits() override; // Approximation template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { return Complex::Builder(c*d); } @@ -76,7 +76,7 @@ public: // Properties int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; - Expression getUnit() const; + Expression extractUnits(); // Approximation template static void computeOnArrays(T * m, T * n, T * result, int mNumberOfColumns, int mNumberOfRows, int nNumberOfColumns); // Simplification diff --git a/poincare/include/poincare/nth_root.h b/poincare/include/poincare/nth_root.h index d0d1d8e87..5132282f6 100644 --- a/poincare/include/poincare/nth_root.h +++ b/poincare/include/poincare/nth_root.h @@ -20,7 +20,7 @@ public: #endif private: - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Layout Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; diff --git a/poincare/include/poincare/parenthesis.h b/poincare/include/poincare/parenthesis.h index 067898502..682c7630a 100644 --- a/poincare/include/poincare/parenthesis.h +++ b/poincare/include/poincare/parenthesis.h @@ -21,7 +21,7 @@ public: // Properties Type type() const override { return Type::Parenthesis; } int polynomialDegree(Context * context, const char * symbolName) const override; - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Layout Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index ad269d15d..d9da121c7 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -29,7 +29,7 @@ public: Sign sign(Context * context) const override; Expression setSign(Sign s, ReductionContext reductionContext) override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression getUnit() const override; + Expression extractUnits() override; int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; @@ -79,7 +79,6 @@ public: int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); - Expression getUnit() const; private: constexpr static int k_maxExactPowerMatrix = 100; diff --git a/poincare/include/poincare/subtraction.h b/poincare/include/poincare/subtraction.h index f8703648e..96db82b72 100644 --- a/poincare/include/poincare/subtraction.h +++ b/poincare/include/poincare/subtraction.h @@ -24,7 +24,7 @@ public: Type type() const override { return Type::Subtraction; } int polynomialDegree(Context * context, const char * symbolName) const override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Approximation template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { return Complex::Builder(c - d); } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 97bc4ba87..f3b662e7d 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -151,7 +151,7 @@ public: // Expression Properties Type type() const override { return Type::Unit; } Sign sign(Context * context) const override; - Expression getUnit() const override; + Expression extractUnits() override; /* Layout */ Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -725,7 +725,6 @@ public: Unit(const UnitNode * node) : Expression(node) {} static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); - Expression getUnit() const { return clone(); } // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/include/poincare/unit_convert.h b/poincare/include/poincare/unit_convert.h index 70943a9f5..c142cb712 100644 --- a/poincare/include/poincare/unit_convert.h +++ b/poincare/include/poincare/unit_convert.h @@ -20,7 +20,7 @@ public: Type type() const override { return Type::UnitConvert; } private: - Expression getUnit() const override { assert(false); return ExpressionNode::getUnit(); } + Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } // Simplification Expression shallowReduce(ReductionContext reductionContext) override; // Evalutation diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 501a57a10..4bdec595a 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -155,16 +155,33 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon /* Step 2: Handle the units. All children should have the same unit, otherwise * the result is not homogeneous. */ { - Expression unit = childAtIndex(0).getUnit(); + Expression unit = childAtIndex(0).extractUnits(); const bool hasUnit = !unit.isUninitialized(); for (int i = 1; i < childrenCount; i++) { - Expression otherUnit = childAtIndex(i).getUnit(); + Expression otherUnit = childAtIndex(i).extractUnits(); if (hasUnit == otherUnit.isUninitialized() || (hasUnit && !unit.isIdenticalTo(otherUnit))) { return replaceWithUndefinedInPlace(); } } + if (hasUnit) { + for (int i = 0; i < childrenCount; i++) { + /* Any unary hierarchy must be squashed here since it has not been + * done in extractUnits. + */ + Expression child = childAtIndex(i); + if (child.type() == ExpressionNode::Type::Multiplication) { + static_cast(child).squashUnaryHierarchyInPlace(); + } + } + Expression addition = shallowReduce(reductionContext); + Multiplication result = Multiplication::Builder(unit); + result.mergeSameTypeChildrenInPlace(); + addition.replaceWithInPlace(result); + result.addChildAtIndexInPlace(addition, 0, 1); + return std::move(result); + } } // Step 3: Sort the children diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 1ac78e729..dc87f141f 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -136,7 +136,7 @@ bool ExpressionNode::isOfType(Type * types, int length) const { return false; } -Expression ExpressionNode::getUnit() const { +Expression ExpressionNode::extractUnits() { return Expression(); } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index c482edb56..419db00bf 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -63,8 +63,8 @@ bool MultiplicationNode::childAtIndexNeedsUserParentheses(const Expression & chi return child.isOfType(types, 2); } -Expression MultiplicationNode::getUnit() const { - return Multiplication(this).getUnit(); +Expression MultiplicationNode::extractUnits() { + return Multiplication(this).extractUnits(); } template @@ -255,20 +255,30 @@ int Multiplication::getPolynomialCoefficients(Context * context, const char * sy return deg; } -Expression Multiplication::getUnit() const { +Expression Multiplication::extractUnits() { Multiplication result = Multiplication::Builder(); int resultChildrenCount = 0; - const int childrenCount = numberOfChildren(); - for (int i = 0; i < childrenCount; i++) { - Expression currentUnit = childAtIndex(i).getUnit(); + for (int i = 0; i < numberOfChildren(); i++) { + Expression currentUnit = childAtIndex(i).extractUnits(); if (!currentUnit.isUninitialized()) { + assert(childAtIndex(i) == currentUnit); result.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount); resultChildrenCount++; + removeChildAtIndexInPlace(i--); } } if (resultChildrenCount == 0) { return Expression(); } + /* squashUnaryHierarchyInPlace(); + * That would make 'this' invalid, so we would rather keep any unary + * hierarchy as it is and handle it later. + * TODO ? + * A possible solution would be that the extractUnits method becomes + * Expression extractUnits(Expression & units) + * returning the Expression that is left after extracting the units + * and setting the units reference instead of returning the units. + */ return result.squashUnaryHierarchyInPlace(); } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index b8f096678..576820dc9 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -81,8 +81,12 @@ int PowerNode::polynomialDegree(Context * context, const char * symbolName) cons return -1; } -Expression PowerNode::getUnit() const { - return Power(this).getUnit(); +Expression PowerNode::extractUnits() { + if (!childAtIndex(0)->extractUnits().isUninitialized()) { + assert(childAtIndex(0)->type() == ExpressionNode::Type::Unit); + return Power(this); + } + return ExpressionNode::extractUnits(); } int PowerNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { @@ -985,14 +989,6 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont return *this; } -Expression Power::getUnit() const { - Expression baseUnit = childAtIndex(0).getUnit(); - if (baseUnit.isUninitialized()) { - return baseUnit; - } - return Power::Builder(baseUnit, childAtIndex(1).clone()); -} - // Private // Simplification diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 344654270..7c7a141cf 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -164,8 +164,8 @@ ExpressionNode::Sign UnitNode::sign(Context * context) const { return Sign::Positive; } -Expression UnitNode::getUnit() const { - return Unit(this).getUnit(); +Expression UnitNode::extractUnits() { + return Unit(this); } int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const { diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index a4d4fedd5..8a448af0e 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -41,7 +41,7 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.angleUnit(), reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits); - Expression unit = childAtIndex(1).clone().reduce(reductionContextWithUnits).getUnit(); + Expression unit = childAtIndex(1).clone().reduce(reductionContextWithUnits).extractUnits(); if (unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); @@ -54,7 +54,7 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.angleUnit(), reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - Expression finalUnit = childAtIndex(1).reduce(reductionContextWithoutUnits).getUnit(); + Expression finalUnit = childAtIndex(1).reduce(reductionContextWithoutUnits).extractUnits(); // Divide the left member by the new unit Expression division = Division::Builder(childAtIndex(0), finalUnit.clone()); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 854888d5b..4bfd28073 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -374,10 +374,10 @@ void assert_reduced_expression_unit(const char * expression, const char * unit, ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation); Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(redContext); - Expression u1 = e.getUnit(); + Expression u1 = e.extractUnits(); Expression u2 = parse_expression(unit, &globalContext, false); u2 = u2.reduce(redContext); - u2 = u2.getUnit(); + u2 = u2.extractUnits(); quiz_assert_print_if_failure(u1.isUninitialized() == u2.isUninitialized() && (u1.isUninitialized() || u1.isIdenticalTo(u2)), expression); } diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index e4bb5fd41..04359e9d8 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -414,6 +414,7 @@ QUIZ_CASE(poincare_simplification_units) { /* Valid expressions */ assert_parsed_expression_simplify_to("-2×_A", "-2×_A"); assert_parsed_expression_simplify_to("cos(1_s/1_s)", "cos(1)"); + assert_parsed_expression_simplify_to("1_m+π_m+√(2)_m-cos(15)_m", "6.3154941288217×_m"); } QUIZ_CASE(poincare_simplification_power) { From 7ef28a93bc2d9183fc0447da43bb21f406aab361 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Mar 2020 15:38:43 +0100 Subject: [PATCH 057/453] [poincare/multiplication] Do not expand Multiplication in presence of units --- poincare/src/multiplication.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 419db00bf..510086a29 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -711,6 +711,8 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext { const Expression c = childAtIndex(0); if (hasUnit()) { + // Do not expand Multiplication in presence of units + shouldExpand = false; // Make sure a Multiplication is not made of (Power of) Units only if (!c.isNumber()) { addChildAtIndexInPlace(Rational::Builder(1), 0, numberOfChildren()); From 01b94f85439ce4457722f21dff2fcfc798e5d72f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 13 Mar 2020 16:55:57 +0100 Subject: [PATCH 058/453] [poincare/unit] Units homogeneity is already handled in each Expression subclass specifically if needed or generically in defaultHandleUnitsInChildren --- poincare/include/poincare/unit.h | 2 -- poincare/src/unit.cpp | 30 ------------------------------ 2 files changed, 32 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index f3b662e7d..1b809fab3 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -166,7 +166,6 @@ public: // Simplification Expression shallowReduce(ReductionContext reductionContext) override; - Expression shallowBeautify(ReductionContext reductionContext) override; LayoutShape leftLayoutShape() const override { return LayoutShape::OneLetter; } // TODO const Dimension * dimension() const { return m_dimension; } @@ -728,7 +727,6 @@ public: // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); }; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 7c7a141cf..dfe857004 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -214,10 +214,6 @@ Expression UnitNode::shallowReduce(ReductionContext reductionContext) { return Unit(this).shallowReduce(reductionContext); } -Expression UnitNode::shallowBeautify(ReductionContext reductionContext) { - return Unit(this).shallowBeautify(reductionContext); -} - constexpr const Unit::Prefix Unit::PicoPrefix, Unit::NanoPrefix, @@ -317,32 +313,6 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext return result; } -Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { - Expression ancestor = parent(); - if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Power) { - ancestor = ancestor.parent(); - } - /* Check homogeneity: at this point, ancestor must be - * - either uninitialized - * - or a Multiplication whose parent is uninitialized. - */ - if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Multiplication) { - ancestor = ancestor.parent(); - } - if (!ancestor.isUninitialized() && ancestor.type() == ExpressionNode::Type::Opposite) { - ancestor = ancestor.parent(); - } - if (ancestor.isUninitialized()) { - return *this; - } - /* If the latter checks are not successfully passed, then the function - * returns replaceWithUndefinedInPlace. - * TODO Something else should be returned in order to report a more - * specific error. For instance: inhomogeneous expression. - */ - return replaceWithUndefinedInPlace(); -} - void Unit::chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext) { assert(value != 0 && !std::isnan(value) && !std::isinf(value) && exponent != 0); UnitNode * unitNode = static_cast(node()); From 651b705dbd717037e786105c74c114d82b725f1f Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 13 Mar 2020 17:01:06 +0100 Subject: [PATCH 059/453] Revert "[poincare/expression] deepBeautify bubbles up Undefined children" This reverts commit 300399fe4d5fb5273a326a48067280c0fd1088b1. Not necessary anymore to bubble up Undefined children in deepBeautify since Unit::shallowBeautify does not introduce any Undefined Expression. --- poincare/src/expression.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 62dc03bc0..361af0cb4 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -825,12 +825,6 @@ Expression Expression::deepBeautify(ExpressionNode::ReductionContext reductionCo for (int i = 0; i < nbChildren; i++) { Expression child = e.childAtIndex(i); child = child.deepBeautify(reductionContext); - /* Unit::shallowBeautify replaces units in inhomogeneous Expression by - * Undefined. Undefined children must be bubbled up to the root. - */ - if (child.type() == ExpressionNode::Type::Undefined) { - return e.replaceWithUndefinedInPlace(); - } // We add missing Parentheses after beautifying the parent and child if (e.node()->childAtIndexNeedsUserParentheses(child, i)) { e.replaceChildAtIndexInPlace(i, Parenthesis::Builder(child)); From c71cce295755c541c80bffa14f7e582e636f991d Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 27 Mar 2020 11:48:35 +0100 Subject: [PATCH 060/453] [poincare/test] Factor assertions --- poincare/test/expression_properties.cpp | 1 - poincare/test/helper.cpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 4bfd28073..c5d9ee0c4 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -328,7 +328,6 @@ void assert_reduced_expression_has_polynomial_coefficient(const char * expressio int d = e.getPolynomialReducedCoefficients(symbolName, coefficientBuffer, &globalContext, complexFormat, Radian, symbolicComputation); for (int i = 0; i <= d; i++) { Expression f = parse_expression(coefficients[i], &globalContext, false); - quiz_assert(!f.isUninitialized()); coefficientBuffer[i] = coefficientBuffer[i].reduce(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, SystemForAnalysis, symbolicComputation)); f = f.reduce(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, SystemForAnalysis, symbolicComputation)); quiz_assert_print_if_failure(coefficientBuffer[i].isIdenticalTo(f), expression); diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 67d035b41..3c07c656b 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -72,14 +72,13 @@ void assert_parsed_expression_process_to(const char * expression, const char * r Poincare::Expression parse_expression(const char * expression, Context * context, bool addParentheses) { Expression result = Expression::Parse(expression, context, addParentheses); - quiz_assert(!result.isUninitialized()); + quiz_assert_print_if_failure(!result.isUninitialized(), expression); return result; } void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) { Shared::GlobalContext globalContext; Expression e = parse_expression(expression, &globalContext, false); - quiz_assert_print_if_failure(!e.isUninitialized(), expression); e = e.simplify(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target)); quiz_assert_print_if_failure(!(e.isUninitialized()), expression); } From 914bb38a8ecc353d9f234b7525986e1c2c42588a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Fri, 27 Mar 2020 17:22:18 +0100 Subject: [PATCH 061/453] [poincare/test/helper] Do not beautify in assert_simplify helper function Simplifying a Store expression does not generally reduce the children, so the children should probably not be beautified ? --- poincare/test/helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 3c07c656b..90353b239 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -79,7 +79,7 @@ Poincare::Expression parse_expression(const char * expression, Context * context void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) { Shared::GlobalContext globalContext; Expression e = parse_expression(expression, &globalContext, false); - e = e.simplify(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target)); + e = e.reduce(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target)); quiz_assert_print_if_failure(!(e.isUninitialized()), expression); } From f227cd719f60d99e7d100808d55069937d617958 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 26 Mar 2020 17:18:46 +0100 Subject: [PATCH 062/453] [poincare/multiplication] Use extractUnits instead of splitIntoNormalForm in shallowBeautify --- poincare/include/poincare/multiplication.h | 2 +- poincare/src/multiplication.cpp | 84 +++++++++------------- 2 files changed, 33 insertions(+), 53 deletions(-) diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 1021ec9e0..46dfea69f 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -103,7 +103,7 @@ private: static bool TermHasNumeralExponent(const Expression & e); static const Expression CreateExponent(Expression e); static inline const Expression Base(const Expression e); - void splitIntoNormalForm(Expression & numerator, Expression & denominator, Expression & units, ExpressionNode::ReductionContext reductionContext) const; + void splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const; }; } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 510086a29..86661ac53 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -343,8 +343,8 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu /* Beautifying a Multiplication consists in several possible operations: * - Add Opposite ((-3)*x -> -(3*x), useful when printing fractions) * - Recognize derived units in the product of units - * - Creating a Division if there's either a term with a power of -1 (a.b^(-1) - * shall become a/b) or a non-integer rational term (3/2*a -> (3*a)/2). */ + * - Creating a Division if relevant + */ // Step 1: Turn -n*A into -(n*A) Expression noNegativeNumeral = makePositiveAnyNegativeNumeralFactor(reductionContext); @@ -356,23 +356,13 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu return std::move(o); } - Expression numer, denom, units; - splitIntoNormalForm(numer, denom, units, reductionContext); + Expression result = *this; + Expression units = extractUnits(); - // Step 2: Create a Division if relevant - Expression result; - if (!numer.isUninitialized()) { - result = numer; - } - if (!denom.isUninitialized()) { - result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); - } - assert(!result.isUninitialized()); - - /* Step 3: Handle the units - */ if (!units.isUninitialized()) { - /* Recognize derived units + /* Step 2: Handle the units + * + * Recognize derived units * - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most. * - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'. * - Repeat those steps until no more simplification is possible. @@ -418,23 +408,12 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } if (unitsAccu.numberOfChildren() > 0) { units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); - units = Multiplication::Builder(units); - static_cast(units).mergeSameTypeChildrenInPlace(); - { - Expression unitsNumer, unitsDenom, unitsUnits; - static_cast(units).splitIntoNormalForm(unitsNumer, unitsDenom, unitsUnits, reductionContext); - if (!unitsNumer.isUninitialized()) { - result = Multiplication::Builder(result, unitsNumer); - } - if (!unitsDenom.isUninitialized()) { - result = Division::Builder(result, unitsDenom); - } - units = unitsUnits; - } - if (units.isUninitialized()) { + Expression newUnits = units.extractUnits(); + result = Multiplication::Builder(result, units); + if (newUnits.isUninitialized()) { units = unitsAccu; } else { - units = Multiplication::Builder(unitsAccu, units); + units = Multiplication::Builder(unitsAccu, newUnits); static_cast(units).mergeSameTypeChildrenInPlace(); } } @@ -488,6 +467,17 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu result = Multiplication::Builder(resultWithoutUnit, units); static_cast(result).mergeSameTypeChildrenInPlace(); } + + } else { + // Step 3: Create a Division if relevant + Expression numer, denom; + splitIntoNormalForm(numer, denom, reductionContext); + if (!numer.isUninitialized()) { + result = numer; + } + if (!denom.isUninitialized()) { + result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); + } } replaceWithInPlace(result); @@ -495,8 +485,13 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } Expression Multiplication::denominator(ExpressionNode::ReductionContext reductionContext) const { - Expression numer, denom, units; - splitIntoNormalForm(numer, denom, units, reductionContext); + /* TODO ? + * Turn the denominator const method into an extractDenominator method + * (non const) in the same same way as extractUnits. + * Then remove splitIntoNormalForm. + */ + Expression numer, denom; + splitIntoNormalForm(numer, denom, reductionContext); return denom; } @@ -1010,20 +1005,18 @@ bool Multiplication::TermHasNumeralExponent(const Expression & e) { return false; } -void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & denominator, Expression & units, ExpressionNode::ReductionContext reductionContext) const { +void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const { + assert(const_cast(this)->extractUnits().isUninitialized()); Multiplication mNumerator = Multiplication::Builder(); Multiplication mDenominator = Multiplication::Builder(); - Multiplication mUnits = Multiplication::Builder(); int numberOfFactorsInNumerator = 0; int numberOfFactorsInDenominator = 0; - int numberOfFactorsInUnits = 0; const int numberOfFactors = numberOfChildren(); for (int i = 0; i < numberOfFactors; i++) { Expression factor = childAtIndex(i).clone(); ExpressionNode::Type factorType = factor.type(); Expression factorsNumerator; Expression factorsDenominator; - Expression factorsUnit; if (factorType == ExpressionNode::Type::Rational) { Rational r = static_cast(factor); if (r.isRationalOne()) { @@ -1042,16 +1035,10 @@ void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & de } else if (factorType == ExpressionNode::Type::Power) { Expression fd = factor.denominator(reductionContext); if (fd.isUninitialized()) { - if (factor.childAtIndex(0).type() == ExpressionNode::Type::Unit) { - factorsUnit = factor; - } else { - factorsNumerator = factor; - } + factorsNumerator = factor; } else { factorsDenominator = fd; } - } else if (factorType == ExpressionNode::Type::Unit) { - factorsUnit = factor; } else { factorsNumerator = factor; } @@ -1063,10 +1050,6 @@ void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & de mDenominator.addChildAtIndexInPlace(factorsDenominator, numberOfFactorsInDenominator, numberOfFactorsInDenominator); numberOfFactorsInDenominator++; } - if (!factorsUnit.isUninitialized()) { - mUnits.addChildAtIndexInPlace(factorsUnit, numberOfFactorsInUnits, numberOfFactorsInUnits); - numberOfFactorsInUnits++; - } } if (numberOfFactorsInNumerator) { numerator = mNumerator.squashUnaryHierarchyInPlace(); @@ -1074,9 +1057,6 @@ void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & de if (numberOfFactorsInDenominator) { denominator = mDenominator.squashUnaryHierarchyInPlace(); } - if (numberOfFactorsInUnits) { - units = mUnits.squashUnaryHierarchyInPlace(); - } } const Expression Multiplication::Base(const Expression e) { From 407ce0534c97b63e201fa111f8fb09243d5cf82a Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 25 Mar 2020 14:41:41 +0100 Subject: [PATCH 063/453] [poincare/expression] Use extractUnits instead of hasUnit when possible --- poincare/src/expression.cpp | 2 +- poincare/src/power.cpp | 2 +- poincare/src/unit_convert.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 361af0cb4..40329a08e 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -350,7 +350,7 @@ Expression Expression::defaultHandleUnitsInChildren() { // Generically, an Expression does not accept any Unit in its children. const int childrenCount = numberOfChildren(); for (int i = 0; i < childrenCount; i++) { - if (childAtIndex(i).hasUnit()) { + if (!childAtIndex(i).extractUnits().isUninitialized()) { return replaceWithUndefinedInPlace(); } } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 576820dc9..9d9ee0a62 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -392,7 +392,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // Step 1: Handle the units { - if (index.hasUnit()) { + if (!index.extractUnits().isUninitialized()) { // There must be no unit in the exponent return replaceWithUndefinedInPlace(); } diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 8a448af0e..148897ef5 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -59,7 +59,7 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction // Divide the left member by the new unit Expression division = Division::Builder(childAtIndex(0), finalUnit.clone()); division = division.reduce(reductionContext); - if (division.hasUnit()) { + if (!division.extractUnits().isUninitialized()) { // The left and right members are not homogeneous return replaceWithUndefinedInPlace(); } From f8050f067361b8b50428f61c8159b0e004ced9d0 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Wed, 18 Mar 2020 11:27:54 +0100 Subject: [PATCH 064/453] [poincare/symbol_abstract] Remove redundant code This case is already handled in shallowReduce of Function and Symbol --- poincare/src/symbol_abstract.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index a7af63006..2d8b31f8b 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -66,11 +66,6 @@ bool SymbolAbstract::matches(const SymbolAbstract & symbol, ExpressionTest test, } Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * context, bool clone, ExpressionNode::SymbolicComputation symbolicComputation) { - if (symbolicComputation == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits - || symbolicComputation == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits) - { - return Undefined::Builder(); - } bool shouldNotReplaceSymbols = symbolicComputation == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions; if (symbol.type() == ExpressionNode::Type::Symbol && shouldNotReplaceSymbols) { return clone ? symbol.clone() : *const_cast(&symbol); From 266482ef99783b7002e09be59bf44c24d6da57d4 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Thu, 5 Mar 2020 17:30:16 +0100 Subject: [PATCH 065/453] [apps/calculation] Additional outputs for Unit --- apps/calculation/Makefile | 1 + .../unit_list_controller.cpp | 32 +++++++++++++++++++ .../additional_outputs/unit_list_controller.h | 22 +++++++++++++ apps/calculation/calculation.cpp | 5 +-- apps/calculation/history_controller.cpp | 5 ++- apps/calculation/history_controller.h | 2 ++ 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 apps/calculation/additional_outputs/unit_list_controller.cpp create mode 100644 apps/calculation/additional_outputs/unit_list_controller.h diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index ef4c9d36d..a2de2432c 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -21,6 +21,7 @@ app_calculation_src = $(addprefix apps/calculation/,\ additional_outputs/trigonometry_graph_cell.cpp \ additional_outputs/trigonometry_list_controller.cpp \ additional_outputs/trigonometry_model.cpp \ + additional_outputs/unit_list_controller.cpp \ app.cpp \ edit_expression_controller.cpp \ expression_field.cpp \ diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp new file mode 100644 index 000000000..fe4e61d84 --- /dev/null +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -0,0 +1,32 @@ +#include "unit_list_controller.h" +#include "../app.h" +#include "../../shared/poincare_helpers.h" + +namespace Calculation { + +int UnitListController::numberOfRows() const { //FIXME + return 2; +} + +void UnitListController::computeLayoutAtIndex(int index) { //FIXME + Poincare::Expression expressionAtIndex; + if (index == 0) { + expressionAtIndex = m_expression; + } else { + assert(index == 1); + Poincare::ExpressionNode::ReductionContext reductionContext( + App::app()->localContext(), + Poincare::Preferences::sharedPreferences()->complexFormat(), + Poincare::Preferences::sharedPreferences()->angleUnit(), + Poincare::ExpressionNode::ReductionTarget::SystemForApproximation, + Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + expressionAtIndex = m_expression.reduce(reductionContext); + } + m_layouts[index] = Shared::PoincareHelpers::CreateLayout(expressionAtIndex); +} + +I18n::Message UnitListController::messageAtIndex(int index) { + return (I18n::Message)0; +} + +} diff --git a/apps/calculation/additional_outputs/unit_list_controller.h b/apps/calculation/additional_outputs/unit_list_controller.h new file mode 100644 index 000000000..1e9d168bd --- /dev/null +++ b/apps/calculation/additional_outputs/unit_list_controller.h @@ -0,0 +1,22 @@ +#ifndef CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H +#define CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H + +#include "expressions_list_controller.h" + +namespace Calculation { + +class UnitListController : public ExpressionsListController { +public: + UnitListController(EditExpressionController * editExpressionController) : + ExpressionsListController(editExpressionController) {} + + //ListViewDataSource + int numberOfRows() const override; +private: + void computeLayoutAtIndex(int index) override; + I18n::Message messageAtIndex(int index) override; +}; + +} + +#endif diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index fe3f09f2f..3393e9f2e 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -250,8 +250,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) { return AdditionalInformationType::Trigonometry; } - - // TODO: return AdditionalInformationType::Unit + if (o.hasUnit()) { + return AdditionalInformationType::Unit; + } if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { return AdditionalInformationType::Integer; } diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index cafa5c4cd..694374f02 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -15,7 +15,8 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo m_complexController(editExpressionController), m_integerController(editExpressionController), m_rationalController(editExpressionController), - m_trigonometryController(editExpressionController) + m_trigonometryController(editExpressionController), + m_unitController(editExpressionController) { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { m_calculationHistory[i].setParentResponder(&m_selectableTableView); @@ -106,6 +107,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { vc = &m_integerController; } else if (additionalInfoType == Calculation::AdditionalInformationType::Rational) { vc = &m_rationalController; + } else if (additionalInfoType == Calculation::AdditionalInformationType::Unit) { + vc = &m_unitController; } if (vc) { vc->setExpression(e); diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index 606637edb..2cb20840a 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -9,6 +9,7 @@ #include "additional_outputs/integer_list_controller.h" #include "additional_outputs/rational_list_controller.h" #include "additional_outputs/trigonometry_list_controller.h" +#include "additional_outputs/unit_list_controller.h" namespace Calculation { @@ -45,6 +46,7 @@ private: IntegerListController m_integerController; RationalListController m_rationalController; TrigonometryListController m_trigonometryController; + UnitListController m_unitController; }; } From e4848a7535fc00bea065a00955db9a2ddafdf03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 10 Apr 2020 14:35:39 +0200 Subject: [PATCH 066/453] [apps/calculation] HistoryController: favour understandable code --- apps/calculation/history_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 694374f02..6e437fce0 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -127,7 +127,7 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { Container::activeApp()->setFirstResponder(parentResponder()); return true; } - m_selectableTableView.selectCellAtLocation(0, (focusRow > 0) * (focusRow - 1)); + m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); tableViewDidChangeSelection(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); m_selectableTableView.scrollToCell(0, selectedRow()); return true; From 56c45d1390992dfaf50aaeb1ecc33e438925bc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 15 Apr 2020 18:15:24 +0200 Subject: [PATCH 067/453] [poincare] Parsing: expression -> expression is always parsed but return "undef" when the left expression is neither a custom variable or function nor a unit. This makes the behaviour consistent on theses expressions: 2 -> a+a 2 -> 2*a --- poincare/src/parsing/parser.cpp | 49 +++++++++++++++----------------- poincare/src/parsing/parser.h | 6 ++-- poincare/test/parsing.cpp | 17 +---------- poincare/test/simplification.cpp | 17 +++++++++++ 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/poincare/src/parsing/parser.cpp b/poincare/src/parsing/parser.cpp index 2b8873bd1..f38c57e3f 100644 --- a/poincare/src/parsing/parser.cpp +++ b/poincare/src/parsing/parser.cpp @@ -276,32 +276,29 @@ void Parser::parseRightwardsArrow(Expression & leftHandSide, Token::Type stoppin return; } // At this point, m_currentToken is Token::RightwardsArrow. - bool parseId = m_nextToken.is(Token::Identifier) && !IsReservedName(m_nextToken.text(), m_nextToken.length()); - if (parseId) { - popToken(); - // Try parsing a store - Expression rightHandSide; - parseCustomIdentifier(rightHandSide, m_currentToken.text(), m_currentToken.length(), true); - if (m_status != Status::Progress) { - return; - } - if (!m_nextToken.is(Token::EndOfStream) - || !(rightHandSide.type() == ExpressionNode::Type::Symbol - || (rightHandSide.type() == ExpressionNode::Type::Function - && rightHandSide.childAtIndex(0).type() == ExpressionNode::Type::Symbol))) - { - m_status = Status::Error; // Store expects a single symbol or function. - return; - } + const char * tokenName = m_nextToken.text(); + size_t tokenNameLength = m_nextToken.length(); + /* Right part of the RightwardsArrow are either a Symbol, a Function or units. + * Even undefined function "plouf(x)" should be interpreted as function and + * not as a multiplication. */ + m_symbolPlusParenthesesAreFunctions = true; + Expression rightHandSide = parseUntil(stoppingType); + m_symbolPlusParenthesesAreFunctions = false; + if (m_status != Status::Progress) { + return; + } + + // Pattern : "-> a" or "-> f(x)" Try parsing a store + if (m_nextToken.is(Token::EndOfStream) && + (rightHandSide.type() == ExpressionNode::Type::Symbol + || (rightHandSide.type() == ExpressionNode::Type::Function + && rightHandSide.childAtIndex(0).type() == ExpressionNode::Type::Symbol)) && + !IsReservedName(tokenName, tokenNameLength)) { leftHandSide = Store::Builder(leftHandSide, static_cast(rightHandSide)); return; } // Try parsing a unit convert - Expression rightHandSide = parseUntil(stoppingType); - if (m_status != Status::Progress) { - return; - } - if (!m_nextToken.is(Token::EndOfStream) || rightHandSide.isUninitialized() || rightHandSide.type() == ExpressionNode::Type::Store || rightHandSide.type() == ExpressionNode::Type::UnitConvert) { + if (!m_nextToken.is(Token::EndOfStream) || rightHandSide.isUninitialized() || rightHandSide.type() == ExpressionNode::Type::Store || rightHandSide.type() == ExpressionNode::Type::UnitConvert || rightHandSide.type() == ExpressionNode::Type::Equal) { m_status = Status::Error; // UnitConvert expect a unit on the right. return; } @@ -451,19 +448,19 @@ void Parser::parseSpecialIdentifier(Expression & leftHandSide) { } } -void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions) { +void Parser::parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length) { if (length >= SymbolAbstract::k_maxNameSize) { m_status = Status::Error; // Identifier name too long. return; } bool poppedParenthesisIsSystem = false; - /* If symbolPlusParenthesesAreFunctions is false, check the context: if the + /* If m_symbolPlusParenthesesAreFunctions is false, check the context: if the * identifier does not already exist as a function, interpret it as a symbol, * even if there are parentheses afterwards. */ Context::SymbolAbstractType idType = Context::SymbolAbstractType::None; - if (m_context != nullptr && !symbolPlusParenthesesAreFunctions) { + if (m_context != nullptr && !m_symbolPlusParenthesesAreFunctions) { idType = m_context->expressionTypeForIdentifier(name, length); if (idType != Context::SymbolAbstractType::Function) { leftHandSide = Symbol::Builder(name, length); @@ -511,7 +508,7 @@ void Parser::parseIdentifier(Expression & leftHandSide, Token::Type stoppingType } else if (IsSpecialIdentifierName(m_currentToken.text(), m_currentToken.length())) { parseSpecialIdentifier(leftHandSide); } else { - parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length(), false); + parseCustomIdentifier(leftHandSide, m_currentToken.text(), m_currentToken.length()); } isThereImplicitMultiplication(); } diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 08e04a211..37ff4f523 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -26,7 +26,8 @@ public: m_tokenizer(text), m_currentToken(Token(Token::Undefined)), m_nextToken(m_tokenizer.popToken()), - m_pendingImplicitMultiplication(false) {} + m_pendingImplicitMultiplication(false), + m_symbolPlusParenthesesAreFunctions(false) {} Expression parse(); Status getStatus() const { return m_status; } @@ -75,7 +76,7 @@ private: void parseReservedFunction(Expression & leftHandSide, const Expression::FunctionHelper * const * functionHelper); void parseSpecialIdentifier(Expression & leftHandSide); void parseSequence(Expression & leftHandSide, const char name, Token::Type leftDelimiter1, Token::Type rightDelimiter1, Token::Type leftDelimiter2, Token::Type rightDelimiter2); - void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length, bool symbolPlusParenthesesAreFunctions); + void parseCustomIdentifier(Expression & leftHandSide, const char * name, size_t length); void defaultParseLeftParenthesis(bool isSystemParenthesis, Expression & leftHandSide, Token::Type stoppingType); // Data members @@ -88,6 +89,7 @@ private: Token m_currentToken; Token m_nextToken; bool m_pendingImplicitMultiplication; + bool m_symbolPlusParenthesesAreFunctions; // The array of reserved functions' helpers static constexpr const Expression::FunctionHelper * s_reservedFunctions[] = { diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index 8d01d0f2b..8ed79c0b8 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -239,6 +239,7 @@ QUIZ_CASE(poincare_parsing_parse) { assert_text_not_parsable("t0000000"); assert_text_not_parsable("[[t0000000["); assert_text_not_parsable("0→x=0"); + assert_text_not_parsable("0→3=0"); assert_text_not_parsable("0=0→x"); assert_text_not_parsable("1ᴇ2ᴇ3"); assert_text_not_parsable("0b001112"); @@ -428,9 +429,7 @@ QUIZ_CASE(poincare_parsing_parse_store) { assert_text_not_parsable("1→\1"); // UnknownX assert_text_not_parsable("1→\2"); // UnknownN assert_text_not_parsable("1→acos"); - assert_text_not_parsable("1→f(2)"); assert_text_not_parsable("1→f(f)"); - assert_text_not_parsable("3→f(g(4))"); } QUIZ_CASE(poincare_parsing_parse_unit_convert) { @@ -438,20 +437,6 @@ QUIZ_CASE(poincare_parsing_parse_unit_convert) { assert_parsed_expression_is("1→_m", UnitConvert::Builder(BasedInteger::Builder(1), meter)); Expression kilometer = Expression::Parse("_km", nullptr); assert_parsed_expression_is("1→_m/_km", UnitConvert::Builder(BasedInteger::Builder(1), Division::Builder(meter, kilometer))); - - assert_simplify("_m→a", Radian, Real); - assert_simplify("_m→b", Radian, Real); - assert_text_not_parsable("1_km→a×b"); - - assert_simplify("2→a"); - assert_text_not_parsable("3_m→a×_km"); - assert_simplify("2→f(x)"); - assert_text_not_parsable("3_m→f(2)×_km"); - - // Clean the storage for other tests - Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); - Ion::Storage::sharedStorage()->recordNamed("b.exp").destroy(); - Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); } QUIZ_CASE(poincare_parsing_implicit_multiplication) { diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 04359e9d8..bb57beaac 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1022,6 +1022,9 @@ QUIZ_CASE(poincare_simplification_unit_convert) { assert_parsed_expression_simplify_to("4×_N×3_N×2_N→_N^3", "24×_N^3"); assert_parsed_expression_simplify_to("1→2", Undefined::Name()); + assert_parsed_expression_simplify_to("1→a+a", Undefined::Name()); + assert_parsed_expression_simplify_to("1→f(2)", Undefined::Name()); + assert_parsed_expression_simplify_to("1→f(g(4))", Undefined::Name()); assert_parsed_expression_simplify_to("1→u(n)", Undefined::Name()); assert_parsed_expression_simplify_to("1→u(n+1)", Undefined::Name()); assert_parsed_expression_simplify_to("1→v(n)", Undefined::Name()); @@ -1040,6 +1043,20 @@ QUIZ_CASE(poincare_simplification_unit_convert) { assert_parsed_expression_simplify_to("1→3_m", Undefined::Name()); assert_parsed_expression_simplify_to("4→_km/_m", Undefined::Name()); assert_parsed_expression_simplify_to("3×_min→_s+1-1", Undefined::Name()); + + assert_simplify("_m→a", Radian, Real); + assert_simplify("_m→b", Radian, Real); + assert_parsed_expression_simplify_to("1_km→a×b", Undefined::Name()); + + assert_simplify("2→a"); + assert_parsed_expression_simplify_to("3_m→a×_km", Undefined::Name()); + assert_simplify("2→f(x)"); + assert_parsed_expression_simplify_to("3_m→f(2)×_km", Undefined::Name()); + + // Clean the storage for other tests + Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); + Ion::Storage::sharedStorage()->recordNamed("b.exp").destroy(); + Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); } QUIZ_CASE(poincare_simplification_complex_format) { From 38659587f5bbf05bb0d0f15b012262255f378974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 16 Apr 2020 10:44:55 +0200 Subject: [PATCH 068/453] [poincare] Multiplication::shallowBeautify: fix typo (fix tests) --- poincare/src/multiplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 86661ac53..85b00d24a 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -476,7 +476,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu result = numer; } if (!denom.isUninitialized()) { - result = Division::Builder(result.isUninitialized() ? Rational::Builder(1) : result, denom); + result = Division::Builder(numer.isUninitialized() ? Rational::Builder(1) : numer, denom); } } From 4e2da5de054eb53b7f630b13c85d2914cf3dab88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 16 Apr 2020 15:21:30 +0200 Subject: [PATCH 069/453] [poincare] Add crashing tests on units --- poincare/test/simplification.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index bb57beaac..f1500a85c 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -260,6 +260,10 @@ QUIZ_CASE(poincare_simplification_units) { assert_parsed_expression_simplify_to("_L", "0.001×_m^3"); assert_parsed_expression_simplify_to("_ha", "0.01×_km^2"); + /* Unit sum/subtract */ + assert_parsed_expression_simplify_to("_m+_m", "2×_m"); + assert_parsed_expression_simplify_to("_m-_m", "0×_m"); + /* Usual physical quantities */ assert_parsed_expression_simplify_to("_A×_s×_m^(-3)", "1×_C×_m^\u0012-3\u0013"); // Charge density assert_parsed_expression_simplify_to("_kg×_m×_s^(-3)×_K^(-1)", "1×_N×_K^\u0012-1\u0013×_s^\u0012-1\u0013"); // Thermal conductivity _W×_m^-1×_K^-1 From d805c592021366e911f5f4dcfa8bae44bc4e0f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 16 Apr 2020 15:25:49 +0200 Subject: [PATCH 070/453] [poincare] Fix extractUnit into removeUnit paradigm --- poincare/include/poincare/division.h | 2 +- poincare/include/poincare/empty_expression.h | 2 +- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/expression_node.h | 2 +- poincare/include/poincare/multiplication.h | 8 ++- poincare/include/poincare/nth_root.h | 2 +- poincare/include/poincare/parenthesis.h | 2 +- poincare/include/poincare/power.h | 5 +- poincare/include/poincare/subtraction.h | 2 +- poincare/include/poincare/unit.h | 6 ++- poincare/include/poincare/unit_convert.h | 2 +- poincare/src/addition.cpp | 15 ++---- poincare/src/expression.cpp | 4 +- poincare/src/expression_node.cpp | 4 +- poincare/src/multiplication.cpp | 55 +++++++++++--------- poincare/src/power.cpp | 30 ++++++++--- poincare/src/unit.cpp | 11 +++- poincare/src/unit_convert.cpp | 12 +++-- poincare/test/expression_properties.cpp | 10 ++-- 19 files changed, 108 insertions(+), 68 deletions(-) diff --git a/poincare/include/poincare/division.h b/poincare/include/poincare/division.h index 602f1184d..4b924844d 100644 --- a/poincare/include/poincare/division.h +++ b/poincare/include/poincare/division.h @@ -25,7 +25,7 @@ public: // Properties Type type() const override { return Type::Division; } int polynomialDegree(Context * context, const char * symbolName) const override; - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Approximation virtual Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { diff --git a/poincare/include/poincare/empty_expression.h b/poincare/include/poincare/empty_expression.h index 3a64cac18..0ac5a21e7 100644 --- a/poincare/include/poincare/empty_expression.h +++ b/poincare/include/poincare/empty_expression.h @@ -22,7 +22,7 @@ public: // Properties Type type() const override { return Type::EmptyExpression; } int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Simplification LayoutShape leftLayoutShape() const override { diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index c25545bca..323804f15 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -199,7 +199,7 @@ public: Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } /* Units */ - Expression extractUnits() { return node()->extractUnits(); } + Expression removeUnit(Expression * unit) { return node()->removeUnit(unit); } bool hasUnit() const; /* Complex */ diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 896a72c28..1a06b3b6e 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -178,7 +178,7 @@ public: virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const; bool isOfType(Type * types, int length) const; - virtual Expression extractUnits(); // Only reduced nodes should answer + virtual Expression removeUnit(Expression * unit); // Only reduced nodes should answer /* Simplification */ /* SimplificationOrder returns: diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 46dfea69f..4b1c41a74 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -25,7 +25,7 @@ public: int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression extractUnits() override; + Expression removeUnit(Expression * unit) override; // Approximation template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { return Complex::Builder(c*d); } @@ -65,6 +65,7 @@ private: class Multiplication : public NAryExpression { friend class Addition; friend class Power; + friend class MultiplicationNode; public: Multiplication(const MultiplicationNode * n) : NAryExpression(n) {} static Multiplication Builder(const Tuple & children = {}) { return TreeHandle::NAryBuilder(convert(children)); } @@ -76,7 +77,7 @@ public: // Properties int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; - Expression extractUnits(); + // Approximation template static void computeOnArrays(T * m, T * n, T * result, int mNumberOfColumns, int mNumberOfRows, int nNumberOfColumns); // Simplification @@ -88,6 +89,9 @@ public: NAryExpression::sortChildrenInPlace(order, context, false, canBeInterrupted); } private: + // Unit + Expression removeUnit(Expression * unit); + // Simplification Expression privateShallowReduce(ExpressionNode::ReductionContext reductionContext, bool expand, bool canBeInterrupted); void factorizeBase(int i, int j, ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/include/poincare/nth_root.h b/poincare/include/poincare/nth_root.h index 5132282f6..b1280494a 100644 --- a/poincare/include/poincare/nth_root.h +++ b/poincare/include/poincare/nth_root.h @@ -20,7 +20,7 @@ public: #endif private: - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Layout Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; diff --git a/poincare/include/poincare/parenthesis.h b/poincare/include/poincare/parenthesis.h index 682c7630a..66fe39ca2 100644 --- a/poincare/include/poincare/parenthesis.h +++ b/poincare/include/poincare/parenthesis.h @@ -21,7 +21,7 @@ public: // Properties Type type() const override { return Type::Parenthesis; } int polynomialDegree(Context * context, const char * symbolName) const override; - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Layout Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index d9da121c7..815dc065c 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -29,7 +29,7 @@ public: Sign sign(Context * context) const override; Expression setSign(Sign s, ReductionContext reductionContext) override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression extractUnits() override; + Expression removeUnit(Expression * unit) override; int polynomialDegree(Context * context, const char * symbolName) const override; int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; @@ -84,6 +84,9 @@ private: constexpr static int k_maxExactPowerMatrix = 100; constexpr static int k_maxNumberOfTermsInExpandedMultinome = 25; + // Unit + Expression removeUnit(Expression * unit); + // Simplification Expression denominator(ExpressionNode::ReductionContext reductionContext) const; diff --git a/poincare/include/poincare/subtraction.h b/poincare/include/poincare/subtraction.h index 96db82b72..92e213ba9 100644 --- a/poincare/include/poincare/subtraction.h +++ b/poincare/include/poincare/subtraction.h @@ -24,7 +24,7 @@ public: Type type() const override { return Type::Subtraction; } int polynomialDegree(Context * context, const char * symbolName) const override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Approximation template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { return Complex::Builder(c - d); } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 1b809fab3..6f5596cec 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -151,7 +151,7 @@ public: // Expression Properties Type type() const override { return Type::Unit; } Sign sign(Context * context) const override; - Expression extractUnits() override; + Expression removeUnit(Expression * unit) override; /* Layout */ Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; @@ -183,6 +183,7 @@ private: }; class Unit final : public Expression { + friend class UnitNode; public: typedef UnitNode::Prefix Prefix; typedef UnitNode::Representative Representative; @@ -728,6 +729,9 @@ public: // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); + +private: + Expression removeUnit(Expression * unit); }; } diff --git a/poincare/include/poincare/unit_convert.h b/poincare/include/poincare/unit_convert.h index c142cb712..b1ff98b1d 100644 --- a/poincare/include/poincare/unit_convert.h +++ b/poincare/include/poincare/unit_convert.h @@ -20,7 +20,7 @@ public: Type type() const override { return Type::UnitConvert; } private: - Expression extractUnits() override { assert(false); return ExpressionNode::extractUnits(); } + Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Simplification Expression shallowReduce(ReductionContext reductionContext) override; // Evalutation diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 4bdec595a..076c054b7 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -155,10 +155,12 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon /* Step 2: Handle the units. All children should have the same unit, otherwise * the result is not homogeneous. */ { - Expression unit = childAtIndex(0).extractUnits(); + Expression unit; + childAtIndex(0).removeUnit(&unit); const bool hasUnit = !unit.isUninitialized(); for (int i = 1; i < childrenCount; i++) { - Expression otherUnit = childAtIndex(i).extractUnits(); + Expression otherUnit; + childAtIndex(i).removeUnit(&otherUnit); if (hasUnit == otherUnit.isUninitialized() || (hasUnit && !unit.isIdenticalTo(otherUnit))) { @@ -166,15 +168,6 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon } } if (hasUnit) { - for (int i = 0; i < childrenCount; i++) { - /* Any unary hierarchy must be squashed here since it has not been - * done in extractUnits. - */ - Expression child = childAtIndex(i); - if (child.type() == ExpressionNode::Type::Multiplication) { - static_cast(child).squashUnaryHierarchyInPlace(); - } - } Expression addition = shallowReduce(reductionContext); Multiplication result = Multiplication::Builder(unit); result.mergeSameTypeChildrenInPlace(); diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 40329a08e..119574427 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -350,7 +350,9 @@ Expression Expression::defaultHandleUnitsInChildren() { // Generically, an Expression does not accept any Unit in its children. const int childrenCount = numberOfChildren(); for (int i = 0; i < childrenCount; i++) { - if (!childAtIndex(i).extractUnits().isUninitialized()) { + Expression unit; + childAtIndex(i).removeUnit(&unit); + if (!unit.isUninitialized()) { return replaceWithUndefinedInPlace(); } } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index dc87f141f..fe117da7e 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -136,8 +136,8 @@ bool ExpressionNode::isOfType(Type * types, int length) const { return false; } -Expression ExpressionNode::extractUnits() { - return Expression(); +Expression ExpressionNode::removeUnit(Expression * unit) { + return Expression(this); } void ExpressionNode::setChildrenInPlace(Expression other) { diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 85b00d24a..d3b6391ee 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -63,8 +63,8 @@ bool MultiplicationNode::childAtIndexNeedsUserParentheses(const Expression & chi return child.isOfType(types, 2); } -Expression MultiplicationNode::extractUnits() { - return Multiplication(this).extractUnits(); +Expression MultiplicationNode::removeUnit(Expression * unit) { + return Multiplication(this).removeUnit(unit); } template @@ -255,31 +255,30 @@ int Multiplication::getPolynomialCoefficients(Context * context, const char * sy return deg; } -Expression Multiplication::extractUnits() { - Multiplication result = Multiplication::Builder(); +Expression Multiplication::removeUnit(Expression * unit) { + Multiplication unitMult = Multiplication::Builder(); int resultChildrenCount = 0; for (int i = 0; i < numberOfChildren(); i++) { - Expression currentUnit = childAtIndex(i).extractUnits(); + Expression currentUnit; + childAtIndex(i).removeUnit(¤tUnit); if (!currentUnit.isUninitialized()) { - assert(childAtIndex(i) == currentUnit); - result.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount); + unitMult.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount); resultChildrenCount++; + assert(childAtIndex(i).isRationalOne()); removeChildAtIndexInPlace(i--); } } if (resultChildrenCount == 0) { - return Expression(); + *unit = Expression(); + } else { + *unit = unitMult.squashUnaryHierarchyInPlace(); } - /* squashUnaryHierarchyInPlace(); - * That would make 'this' invalid, so we would rather keep any unary - * hierarchy as it is and handle it later. - * TODO ? - * A possible solution would be that the extractUnits method becomes - * Expression extractUnits(Expression & units) - * returning the Expression that is left after extracting the units - * and setting the units reference instead of returning the units. - */ - return result.squashUnaryHierarchyInPlace(); + if (numberOfChildren() == 0) { + Expression one = Rational::Builder(1); + replaceWithInPlace(one); + return one; + } + return squashUnaryHierarchyInPlace(); } template @@ -356,9 +355,11 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu return std::move(o); } - Expression result = *this; - Expression units = extractUnits(); + Expression self = *this; + Expression units; + self = removeUnit(&units); + Expression result; if (!units.isUninitialized()) { /* Step 2: Handle the units * @@ -408,8 +409,12 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } if (unitsAccu.numberOfChildren() > 0) { units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); - Expression newUnits = units.extractUnits(); - result = Multiplication::Builder(result, units); + Expression newUnits; + units = units.removeUnit(&newUnits); + Multiplication m = Multiplication::Builder(units); + self.replaceWithInPlace(m); + m.addChildAtIndexInPlace(self, 0, 1); + self = m; if (newUnits.isUninitialized()) { units = unitsAccu; } else { @@ -426,7 +431,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu * most relevant. */ - double value = result.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + double value = self.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (std::isnan(value)) { // If the value is undefined, return "undef" without any unit result = Undefined::Builder(); @@ -480,7 +485,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } } - replaceWithInPlace(result); + self.replaceWithInPlace(result); return result; } @@ -1006,7 +1011,7 @@ bool Multiplication::TermHasNumeralExponent(const Expression & e) { } void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const { - assert(const_cast(this)->extractUnits().isUninitialized()); + assert(!hasUnit()); Multiplication mNumerator = Multiplication::Builder(); Multiplication mDenominator = Multiplication::Builder(); int numberOfFactorsInNumerator = 0; diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 9d9ee0a62..8f5729bc2 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -81,12 +81,8 @@ int PowerNode::polynomialDegree(Context * context, const char * symbolName) cons return -1; } -Expression PowerNode::extractUnits() { - if (!childAtIndex(0)->extractUnits().isUninitialized()) { - assert(childAtIndex(0)->type() == ExpressionNode::Type::Unit); - return Power(this); - } - return ExpressionNode::extractUnits(); +Expression PowerNode::removeUnit(Expression * unit) { + return Power(this).removeUnit(unit); } int PowerNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { @@ -378,6 +374,23 @@ int Power::getPolynomialCoefficients(Context * context, const char * symbolName, return -1; } +Expression Power::removeUnit(Expression * unit) { + Expression childUnit; + Expression child = childAtIndex(0).node()->removeUnit(&childUnit); + if (!childUnit.isUninitialized()) { + // Reduced power containing unit are of form "unit^i" with i integer + assert(child.isRationalOne()); + assert(childUnit.type() == ExpressionNode::Type::Unit); + Power p = *this; + Expression result = child; + replaceWithInPlace(child); + p.replaceChildAtIndexInPlace(0, childUnit); + *unit = p; + return child; + } + return *this; +} + Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContext) { { @@ -392,10 +405,13 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // Step 1: Handle the units { - if (!index.extractUnits().isUninitialized()) { + Expression indexUnit; + index.removeUnit(&indexUnit); + if (!indexUnit.isUninitialized()) { // There must be no unit in the exponent return replaceWithUndefinedInPlace(); } + assert(index == childAtIndex(1)); if (base.hasUnit()) { if (index.type() != ExpressionNode::Type::Rational || !static_cast(index).isInteger()) { // The exponent must be an Integer diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index dfe857004..8501d3e0a 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -164,8 +164,8 @@ ExpressionNode::Sign UnitNode::sign(Context * context) const { return Sign::Positive; } -Expression UnitNode::extractUnits() { - return Unit(this); +Expression UnitNode::removeUnit(Expression * unit) { + return Unit(this).removeUnit(unit); } int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const { @@ -341,6 +341,13 @@ void Unit::chooseBestMultipleForValue(double & value, const int exponent, Expres value = bestVal; } +Expression Unit::removeUnit(Expression * unit) { + *unit = *this; + Expression one = Rational::Builder(1); + replaceWithInPlace(one); + return one; +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 148897ef5..2ca423e48 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -41,7 +41,8 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.angleUnit(), reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits); - Expression unit = childAtIndex(1).clone().reduce(reductionContextWithUnits).extractUnits(); + Expression unit; + childAtIndex(1).clone().reduce(reductionContextWithUnits).removeUnit(&unit); if (unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); @@ -54,18 +55,21 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.angleUnit(), reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - Expression finalUnit = childAtIndex(1).reduce(reductionContextWithoutUnits).extractUnits(); + Expression finalUnit; + childAtIndex(1).reduce(reductionContextWithoutUnits).removeUnit(&finalUnit); // Divide the left member by the new unit Expression division = Division::Builder(childAtIndex(0), finalUnit.clone()); division = division.reduce(reductionContext); - if (!division.extractUnits().isUninitialized()) { + Expression divisionUnit; + division = division.removeUnit(&divisionUnit); + if (!divisionUnit.isUninitialized()) { // The left and right members are not homogeneous return replaceWithUndefinedInPlace(); } double floatValue = division.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (std::isinf(floatValue)) { - return Infinity::Builder(false); //FIXME sign? + return Infinity::Builder(floatValue < 0.0); //FIXME sign? } if (std::isnan(floatValue)) { return Undefined::Builder(); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index c5d9ee0c4..5d03ca620 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -373,10 +373,12 @@ void assert_reduced_expression_unit(const char * expression, const char * unit, ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation); Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(redContext); - Expression u1 = e.extractUnits(); - Expression u2 = parse_expression(unit, &globalContext, false); - u2 = u2.reduce(redContext); - u2 = u2.extractUnits(); + Expression u1; + e = e.removeUnit(&u1); + Expression e2 = parse_expression(unit, &globalContext, false); + Expression u2; + e2 = e2.reduce(redContext); + e2.removeUnit(&u2); quiz_assert_print_if_failure(u1.isUninitialized() == u2.isUninitialized() && (u1.isUninitialized() || u1.isIdenticalTo(u2)), expression); } From 3f34e5e64490d35ed52687042899a2a7318c05e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 17 Apr 2020 15:12:01 +0200 Subject: [PATCH 071/453] [poincare] Enable to choose the "UnitConversion" mode at simplification between: only SI, none, default... --- poincare/include/poincare/expression.h | 6 +- poincare/include/poincare/expression_node.h | 16 +- poincare/src/expression.cpp | 14 +- poincare/src/function.cpp | 3 +- poincare/src/multiplication.cpp | 183 ++++++++++---------- poincare/src/symbol.cpp | 4 +- poincare/src/unit.cpp | 2 +- poincare/src/unit_convert.cpp | 6 +- poincare/test/expression_properties.cpp | 20 +-- poincare/test/helper.h | 6 +- 10 files changed, 136 insertions(+), 124 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 323804f15..14def7d80 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -239,11 +239,11 @@ public: * account the complex format required in the expression they return. * (For instance, in Polar mode, they return an expression of the form * r*e^(i*th) reduced and approximated.) */ - static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); + static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default); Expression simplify(ExpressionNode::ReductionContext reductionContext); - static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); - void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); + static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default); + void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default); Expression reduce(ExpressionNode::ReductionContext context); Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 1a06b3b6e..6a5f576b3 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -128,8 +128,13 @@ public: ReplaceAllSymbolsWithDefinitionsOrUndefined = 0, ReplaceAllDefinedSymbolsWithDefinition = 1, ReplaceDefinedFunctionsWithDefinitions = 2, - ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits = 3, // Used in UnitConvert::shallowReduce - ReplaceAllSymbolsWithUndefinedAndReplaceUnits = 4 // Used in UnitConvert::shallowReduce + ReplaceAllSymbolsWithUndefined = 3 // Used in UnitConvert::shallowReduce + }; + enum class UnitConversion { + None = 0, + Default, + InternationalSystem, + Classic // km/h, days + hours + minute }; enum class Sign { Negative = -1, @@ -139,24 +144,27 @@ public: class ReductionContext { public: - ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, SymbolicComputation symbolicComputation = SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) : + ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, SymbolicComputation symbolicComputation = SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, UnitConversion unitConversion = UnitConversion::Default) : m_context(context), m_complexFormat(complexFormat), m_angleUnit(angleUnit), m_target(target), - m_symbolicComputation(symbolicComputation) + m_symbolicComputation(symbolicComputation), + m_unitConversion(unitConversion) {} Context * context() { return m_context; } Preferences::ComplexFormat complexFormat() const { return m_complexFormat; } Preferences::AngleUnit angleUnit() const { return m_angleUnit; } ReductionTarget target() const { return m_target; } SymbolicComputation symbolicComputation() const { return m_symbolicComputation; } + UnitConversion unitConversion() const { return m_unitConversion; } private: Context * m_context; Preferences::ComplexFormat m_complexFormat; Preferences::AngleUnit m_angleUnit; ReductionTarget m_target; SymbolicComputation m_symbolicComputation; + UnitConversion m_unitConversion; }; virtual Sign sign(Context * context) const { return Sign::Unknown; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 119574427..444741c38 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -571,12 +571,12 @@ int Expression::serialize(char * buffer, int bufferSize, Preferences::PrintFloat /* Simplification */ -Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { +Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) { Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { return Undefined::Builder(); } - exp = exp.simplify(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation)); + exp = exp.simplify(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation, unitConversion)); /* simplify might have been interrupted, in which case the resulting * expression is uninitialized, so we need to check that. */ if (exp.isUninitialized()) { @@ -585,7 +585,7 @@ Expression Expression::ParseAndSimplify(const char * text, Context * context, Pr return exp; } -void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { +void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) { assert(simplifiedExpression); Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { @@ -593,7 +593,7 @@ void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * *approximateExpression = Undefined::Builder(); return; } - exp.simplifyAndApproximate(simplifiedExpression, approximateExpression, context, complexFormat, angleUnit, symbolicComputation); + exp.simplifyAndApproximate(simplifiedExpression, approximateExpression, context, complexFormat, angleUnit, symbolicComputation, unitConversion); /* simplify might have been interrupted, in which case the resulting * expression is uninitialized, so we need to check that. */ if (simplifiedExpression->isUninitialized()) { @@ -675,16 +675,16 @@ void Expression::beautifyAndApproximateScalar(Expression * simplifiedExpression, } } -void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { +void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) { assert(simplifiedExpression); sSimplificationHasBeenInterrupted = false; // Step 1: we reduce the expression - ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation); + ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation, unitConversion); const bool isUnitConvert = type() == ExpressionNode::Type::UnitConvert; Expression e = clone().reduce(userReductionContext); if (sSimplificationHasBeenInterrupted) { sSimplificationHasBeenInterrupted = false; - ExpressionNode::ReductionContext systemReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation); + ExpressionNode::ReductionContext systemReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation, unitConversion); e = reduce(systemReductionContext); } *simplifiedExpression = Expression(); diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 9ed5e7fae..6aa0695d6 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -115,8 +115,7 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol, } Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits - || reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined || childAtIndex(0).isUndefined()) { return replaceWithUndefinedInPlace(); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index d3b6391ee..11cdca1af 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -355,75 +355,77 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu return std::move(o); } + // Step 2: Handle the units Expression self = *this; Expression units; self = removeUnit(&units); Expression result; if (!units.isUninitialized()) { - /* Step 2: Handle the units - * - * Recognize derived units - * - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most. - * - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'. - * - Repeat those steps until no more simplification is possible. - */ - Multiplication unitsAccu = Multiplication::Builder(); - Unit::Dimension::Vector unitsExponents = Unit::Dimension::Vector::FromBaseUnits(units); - Unit::Dimension::Vector::Metrics unitsMetrics = unitsExponents.metrics(); - Unit::Dimension::Vector bestRemainderExponents; - Unit::Dimension::Vector::Metrics bestRemainderMetrics; - while (unitsMetrics.supportSize > 1) { - const Unit::Dimension * bestDim = nullptr; - int8_t bestUnitExponent = 0; - for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { - const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); - int8_t entryUnitNorm = entryUnitExponents->metrics().norm; - if (CanSimplifyUnitProduct( - unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, 1, - bestUnitExponent, bestRemainderExponents, bestRemainderMetrics - ) - || - CanSimplifyUnitProduct( - unitsExponents, unitsMetrics, - entryUnitExponents, entryUnitNorm, -1, - bestUnitExponent, bestRemainderExponents, bestRemainderMetrics - )) - { - bestDim = dim; + ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion(); + if (unitConversionMode == ExpressionNode::UnitConversion::Default || unitConversionMode == ExpressionNode::UnitConversion::Classic) { + /* Step 2a: Recognize derived units + * - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most. + * - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'. + * - Repeat those steps until no more simplification is possible. + */ + Multiplication unitsAccu = Multiplication::Builder(); + Unit::Dimension::Vector unitsExponents = Unit::Dimension::Vector::FromBaseUnits(units); + Unit::Dimension::Vector::Metrics unitsMetrics = unitsExponents.metrics(); + Unit::Dimension::Vector bestRemainderExponents; + Unit::Dimension::Vector::Metrics bestRemainderMetrics; + while (unitsMetrics.supportSize > 1) { + const Unit::Dimension * bestDim = nullptr; + int8_t bestUnitExponent = 0; + for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) { + const Unit::Dimension::Vector * entryUnitExponents = dim->vector(); + int8_t entryUnitNorm = entryUnitExponents->metrics().norm; + if (CanSimplifyUnitProduct( + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, 1, + bestUnitExponent, bestRemainderExponents, bestRemainderMetrics + ) + || + CanSimplifyUnitProduct( + unitsExponents, unitsMetrics, + entryUnitExponents, entryUnitNorm, -1, + bestUnitExponent, bestRemainderExponents, bestRemainderMetrics + )) + { + bestDim = dim; + } } + if (bestDim == nullptr) { + break; + } + Expression derivedUnit = Unit::Builder(bestDim, bestDim->stdRepresentative(), bestDim->stdRepresentativePrefix()); + assert(bestUnitExponent == 1 || bestUnitExponent == -1); + if (bestUnitExponent == -1) { + derivedUnit = Power::Builder(derivedUnit, Rational::Builder(-1)); + } + const int position = unitsAccu.numberOfChildren(); + unitsAccu.addChildAtIndexInPlace(derivedUnit, position, position); + unitsExponents = bestRemainderExponents; + unitsMetrics = bestRemainderMetrics; } - if (bestDim == nullptr) { - break; - } - Expression derivedUnit = Unit::Builder(bestDim, bestDim->stdRepresentative(), bestDim->stdRepresentativePrefix()); - assert(bestUnitExponent == 1 || bestUnitExponent == -1); - if (bestUnitExponent == -1) { - derivedUnit = Power::Builder(derivedUnit, Rational::Builder(-1)); - } - const int position = unitsAccu.numberOfChildren(); - unitsAccu.addChildAtIndexInPlace(derivedUnit, position, position); - unitsExponents = bestRemainderExponents; - unitsMetrics = bestRemainderMetrics; - } - if (unitsAccu.numberOfChildren() > 0) { - units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); - Expression newUnits; - units = units.removeUnit(&newUnits); - Multiplication m = Multiplication::Builder(units); - self.replaceWithInPlace(m); - m.addChildAtIndexInPlace(self, 0, 1); - self = m; - if (newUnits.isUninitialized()) { - units = unitsAccu; - } else { - units = Multiplication::Builder(unitsAccu, newUnits); - static_cast(units).mergeSameTypeChildrenInPlace(); + if (unitsAccu.numberOfChildren() > 0) { + units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext); + Expression newUnits; + units = units.removeUnit(&newUnits); + Multiplication m = Multiplication::Builder(units); + self.replaceWithInPlace(m); + m.addChildAtIndexInPlace(self, 0, 1); + self = m; + if (newUnits.isUninitialized()) { + units = unitsAccu; + } else { + units = Multiplication::Builder(unitsAccu, newUnits); + static_cast(units).mergeSameTypeChildrenInPlace(); + } } } - /* Turn into 'Float x units'. + /* Step 2b: Turn into 'Float x units'. * Choose a unit multiple adequate for the numerical value. * An exhaustive exploration of all possible multiples would have * exponential complexity with respect to the number of factors. Instead, @@ -436,41 +438,46 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu // If the value is undefined, return "undef" without any unit result = Undefined::Builder(); } else { - Expression resultWithoutUnit; - if (std::isinf(value)) { - resultWithoutUnit = Infinity::Builder(value < 0.0); + if (unitConversionMode == ExpressionNode::UnitConversion::Classic) { + // TODO create new result 1h 23min 24secondes ? + // Utiliser store ? } else { - // Find the right unit prefix when the value ≠ 0 - if (value != 0.0 && value != 1.0) { - // Identify the first Unit factor and its exponent - Expression firstFactor = units; - int exponent = 1; - if (firstFactor.type() == ExpressionNode::Type::Multiplication) { - firstFactor = firstFactor.childAtIndex(0); - } - if (firstFactor.type() == ExpressionNode::Type::Power) { - Expression exp = firstFactor.childAtIndex(1); - firstFactor = firstFactor.childAtIndex(0); - assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); - Integer expInt = static_cast(exp).signedIntegerNumerator(); - if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { - exponent = expInt.extractedInt(); - } else { - // The exponent is too large to be extracted, so do not try to use it. - exponent = 0; + Expression resultWithoutUnit; + if (std::isinf(value)) { + resultWithoutUnit = Infinity::Builder(value < 0.0); + } else { + // Find the right unit prefix when the value ≠ 0 + if (unitConversionMode == ExpressionNode::UnitConversion::Default && value != 0.0 && value != 1.0) { + // Identify the first Unit factor and its exponent + Expression firstFactor = units; + int exponent = 1; + if (firstFactor.type() == ExpressionNode::Type::Multiplication) { + firstFactor = firstFactor.childAtIndex(0); + } + if (firstFactor.type() == ExpressionNode::Type::Power) { + Expression exp = firstFactor.childAtIndex(1); + firstFactor = firstFactor.childAtIndex(0); + assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); + Integer expInt = static_cast(exp).signedIntegerNumerator(); + if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { + exponent = expInt.extractedInt(); + } else { + // The exponent is too large to be extracted, so do not try to use it. + exponent = 0; + } + } + assert(firstFactor.type() == ExpressionNode::Type::Unit); + // Choose its multiple and update value accordingly + if (exponent != 0) { + static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); } } - assert(firstFactor.type() == ExpressionNode::Type::Unit); - // Choose its multiple and update value accordingly - if (exponent != 0) { - static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); - } + resultWithoutUnit = Float::Builder(value); } - resultWithoutUnit = Float::Builder(value); + // Build final Expression + result = Multiplication::Builder(resultWithoutUnit, units); + static_cast(result).mergeSameTypeChildrenInPlace(); } - // Build final Expression - result = Multiplication::Builder(resultWithoutUnit, units); - static_cast(result).mergeSameTypeChildrenInPlace(); } } else { diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 7f58b44b9..3a2a47c50 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -154,9 +154,7 @@ Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionConte if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions) { return *this; } - if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits - || reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits) - { + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined) { return replaceWithUndefinedInPlace(); } { diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 8501d3e0a..3b1e58654 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -282,7 +282,7 @@ Unit Unit::Builder(const Dimension * dimension, const Representative * represent } Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits) { + if (reductionContext.unitConversion() == ExpressionNode::UnitConversion::None) { return *this; } UnitNode * unitNode = static_cast(node()); diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 2ca423e48..ed3c62a20 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -35,12 +35,13 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction // Find the unit { + // ExpressionNode::ReductionContext reductionContextWithUnits = ExpressionNode::ReductionContext( reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.target(), - ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits); + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined); Expression unit; childAtIndex(1).clone().reduce(reductionContextWithUnits).removeUnit(&unit); if (unit.isUninitialized()) { @@ -54,7 +55,8 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.target(), - ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined, + ExpressionNode::UnitConversion::None); Expression finalUnit; childAtIndex(1).reduce(reductionContextWithoutUnits).removeUnit(&finalUnit); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 5d03ca620..ffb6f7229 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -368,9 +368,9 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) { Ion::Storage::sharedStorage()->recordNamed("x.exp").destroy(); } -void assert_reduced_expression_unit(const char * expression, const char * unit, ExpressionNode::SymbolicComputation symbolicComutation) { +void assert_reduced_expression_unit_is(const char * expression, const char * unit) { Shared::GlobalContext globalContext; - ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation); + ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation); Expression e = parse_expression(expression, &globalContext, false); e = e.reduce(redContext); Expression u1; @@ -383,15 +383,9 @@ void assert_reduced_expression_unit(const char * expression, const char * unit, } QUIZ_CASE(poincare_properties_get_unit) { - assert_reduced_expression_unit("_km", "_km", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - assert_reduced_expression_unit("_min/_km", "_km^(-1)×_min", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - assert_reduced_expression_unit("_km^3", "_km^3", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - assert_reduced_expression_unit("1_m+_km", Undefined::Name(), ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - assert_reduced_expression_unit("_L^2×3×_s", "_L^2×_s", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits); - - assert_reduced_expression_unit("_km", "_m", ReplaceAllSymbolsWithDefinitionsOrUndefined); - assert_reduced_expression_unit("_min/_km", "_m^(-1)×_s", ReplaceAllSymbolsWithDefinitionsOrUndefined); - assert_reduced_expression_unit("_km^3", "_m^3", ReplaceAllSymbolsWithDefinitionsOrUndefined); - assert_reduced_expression_unit("1_m+_km", "_m", ReplaceAllSymbolsWithDefinitionsOrUndefined); - assert_reduced_expression_unit("_L^2×3×_s", "_m^6×_s", ReplaceAllSymbolsWithDefinitionsOrUndefined); + assert_reduced_expression_unit_is("_km", "_m"); + assert_reduced_expression_unit_is("_min/_km", "_m^(-1)×_s"); + assert_reduced_expression_unit_is("_km^3", "_m^3"); + assert_reduced_expression_unit_is("1_m+_km", "_m"); + assert_reduced_expression_unit_is("_L^2×3×_s", "_m^6×_s"); } diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 5e7f5942e..91febd09a 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -11,7 +11,11 @@ constexpr Poincare::ExpressionNode::ReductionTarget User = Poincare::ExpressionN constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllDefinedSymbolsWithDefinition = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition; constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithDefinitionsOrUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined; constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceDefinedFunctionsWithDefinitions = Poincare::ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions; -constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits; +constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined; +constexpr Poincare::ExpressionNode::UnitConversion NoUnitConversion = Poincare::ExpressionNode::UnitConversion::None; +constexpr Poincare::ExpressionNode::UnitConversion DefaultUnitConversion = Poincare::ExpressionNode::UnitConversion::Default; +constexpr Poincare::ExpressionNode::UnitConversion ClassicUnitConversion = Poincare::ExpressionNode::UnitConversion::Classic; +constexpr Poincare::ExpressionNode::UnitConversion InternationalSystemUnitConversion = Poincare::ExpressionNode::UnitConversion::InternationalSystem; constexpr Poincare::Preferences::AngleUnit Degree = Poincare::Preferences::AngleUnit::Degree; constexpr Poincare::Preferences::AngleUnit Radian = Poincare::Preferences::AngleUnit::Radian; constexpr Poincare::Preferences::AngleUnit Gradian = Poincare::Preferences::AngleUnit::Gradian; From c3e68d19686d69c4e97862d501598bf0e39dcbdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 17 Apr 2020 17:33:51 +0200 Subject: [PATCH 072/453] [poincare] Add test on the UnitConversion mode --- poincare/test/helper.cpp | 16 ++++++++-------- poincare/test/helper.h | 4 ++-- poincare/test/simplification.cpp | 7 +++++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 90353b239..ba019ab4c 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -37,10 +37,10 @@ void quiz_assert_log_if_failure(bool test, TreeHandle tree) { quiz_assert(test); } -void assert_parsed_expression_process_to(const char * expression, const char * result, ExpressionNode::ReductionTarget target, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ProcessExpression process, int numberOfSignifiantDigits) { +void assert_parsed_expression_process_to(const char * expression, const char * result, ExpressionNode::ReductionTarget target, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion, ProcessExpression process, int numberOfSignifiantDigits) { Shared::GlobalContext globalContext; Expression e = parse_expression(expression, &globalContext, false); - Expression m = process(e, ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target, symbolicComputation)); + Expression m = process(e, ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target, symbolicComputation, unitConversion)); constexpr int bufferSize = 500; char buffer[bufferSize]; m.serialize(buffer, bufferSize, DecimalMode, numberOfSignifiantDigits); @@ -83,11 +83,11 @@ void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, quiz_assert_print_if_failure(!(e.isUninitialized()), expression); } -void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, ExpressionNode::ReductionTarget target, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::SymbolicComputation symbolicComputation) { - assert_parsed_expression_process_to(expression, simplifiedExpression, target, complexFormat, angleUnit, symbolicComputation, [](Expression e, ExpressionNode::ReductionContext reductionContext) { +void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, ExpressionNode::ReductionTarget target, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) { + assert_parsed_expression_process_to(expression, simplifiedExpression, target, complexFormat, angleUnit, symbolicComputation, unitConversion, [](Expression e, ExpressionNode::ReductionContext reductionContext) { Expression copy = e.clone(); if (reductionContext.target() == ExpressionNode::ReductionTarget::User) { - copy.simplifyAndApproximate(©, nullptr, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.symbolicComputation()); + copy.simplifyAndApproximate(©, nullptr, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.symbolicComputation(), reductionContext.unitConversion()); } else { copy = copy.simplify(reductionContext); } @@ -102,14 +102,14 @@ template void assert_expression_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { int numberOfDigits = sizeof(T) == sizeof(double) ? PrintFloat::k_numberOfStoredSignificantDigits : PrintFloat::k_numberOfPrintedSignificantDigits; numberOfDigits = numberOfSignificantDigits > 0 ? numberOfSignificantDigits : numberOfDigits; - assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, [](Expression e, ExpressionNode::ReductionContext reductionContext) { + assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, DefaultUnitConversion, [](Expression e, ExpressionNode::ReductionContext reductionContext) { return e.approximate(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); }, numberOfDigits); } void assert_expression_simplifies_and_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { int numberOfDigits = numberOfSignificantDigits > 0 ? numberOfSignificantDigits : PrintFloat::k_numberOfStoredSignificantDigits; - assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, [](Expression e, ExpressionNode::ReductionContext reductionContext) { + assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, DefaultUnitConversion, [](Expression e, ExpressionNode::ReductionContext reductionContext) { Expression reduced; Expression approximated; e.simplifyAndApproximate(&reduced, &approximated, reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.symbolicComputation()); @@ -121,7 +121,7 @@ template void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, int numberOfSignificantDigits) { int numberOfDigits = sizeof(T) == sizeof(double) ? PrintFloat::k_numberOfStoredSignificantDigits : PrintFloat::k_numberOfPrintedSignificantDigits; numberOfDigits = numberOfSignificantDigits > 0 ? numberOfSignificantDigits : numberOfDigits; - assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, [](Expression e, ExpressionNode::ReductionContext reductionContext) { + assert_parsed_expression_process_to(expression, approximation, SystemForApproximation, complexFormat, angleUnit, ReplaceAllSymbolsWithDefinitionsOrUndefined, DefaultUnitConversion, [](Expression e, ExpressionNode::ReductionContext reductionContext) { e = e.simplify(reductionContext); return e.approximate(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); }, numberOfDigits); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 91febd09a..18b81b31f 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -31,7 +31,7 @@ void quiz_assert_log_if_failure(bool test, Poincare::TreeHandle tree); typedef Poincare::Expression (*ProcessExpression)(Poincare::Expression, Poincare::ExpressionNode::ReductionContext reductionContext); -void assert_parsed_expression_process_to(const char * expression, const char * result, Poincare::ExpressionNode::ReductionTarget target, Poincare::Preferences::ComplexFormat complexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ExpressionNode::SymbolicComputation symbolicComputation, ProcessExpression process, int numberOfSignifiantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits); +void assert_parsed_expression_process_to(const char * expression, const char * result, Poincare::ExpressionNode::ReductionTarget target, Poincare::Preferences::ComplexFormat complexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ExpressionNode::SymbolicComputation symbolicComputation, Poincare::ExpressionNode::UnitConversion unitConversion, ProcessExpression process, int numberOfSignifiantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits); // Parsing @@ -41,7 +41,7 @@ Poincare::Expression parse_expression(const char * expression, Poincare::Context void assert_simplify(const char * expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User); -void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Poincare::ExpressionNode::ReductionTarget target = User, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = ReplaceAllDefinedSymbolsWithDefinition); +void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Poincare::ExpressionNode::ReductionTarget target = User, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = DefaultUnitConversion); // Approximation diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index f1500a85c..40971b7a6 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1280,6 +1280,13 @@ QUIZ_CASE(poincare_simplification_reduction_target) { assert_parsed_expression_simplify_to("(2+x)^2", "x^2+4×x+4", User); } +QUIZ_CASE(poincare_simplification_unit_conversion) { + assert_parsed_expression_simplify_to("1000000_cm", "10×_km", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, DefaultUnitConversion); + assert_parsed_expression_simplify_to("1000000_cm", "1000000×_cm", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, NoUnitConversion); + assert_parsed_expression_simplify_to("1000000_cm", "10000×_m", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, InternationalSystemUnitConversion); + //assert_parsed_expression_simplify_to("10_m/h", "0.01km/h", SystemForApproximation, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); +} + QUIZ_CASE(poincare_simplification_user_function) { // User defined function // f: x → x*1 From 3308b13b9c9538a59c0831529503e08d9ea140e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 17 Apr 2020 17:36:11 +0200 Subject: [PATCH 073/453] [poincare] UnitConvert: - do the smart part at beautification to avoid requiring an escape case just for UnitConvert - Use UnitConvert::None --- poincare/include/poincare/unit_convert.h | 7 +-- poincare/src/expression.cpp | 8 --- poincare/src/unit_convert.cpp | 62 +++++++++++++----------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/poincare/include/poincare/unit_convert.h b/poincare/include/poincare/unit_convert.h index b1ff98b1d..dfa57ae42 100644 --- a/poincare/include/poincare/unit_convert.h +++ b/poincare/include/poincare/unit_convert.h @@ -22,7 +22,8 @@ public: private: Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } // Simplification - Expression shallowReduce(ReductionContext reductionContext) override; + void deepReduceChildren(ExpressionNode::ReductionContext reductionContext) override; + Expression shallowBeautify(ReductionContext reductionContext) override; // Evalutation Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } @@ -36,8 +37,8 @@ public: static UnitConvert Builder(Expression value, Expression unit) { return TreeHandle::FixedArityBuilder({value, unit}); } // Expression - Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - + void deepReduceChildren(ExpressionNode::ReductionContext reductionContext); + Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); private: UnitConvertNode * node() const { return static_cast(Expression::node()); } }; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 444741c38..c6f444236 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -680,7 +680,6 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre sSimplificationHasBeenInterrupted = false; // Step 1: we reduce the expression ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation, unitConversion); - const bool isUnitConvert = type() == ExpressionNode::Type::UnitConvert; Expression e = clone().reduce(userReductionContext); if (sSimplificationHasBeenInterrupted) { sSimplificationHasBeenInterrupted = false; @@ -714,13 +713,6 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre if (approximateExpression) { static_cast(approximateExpression)->setDimensions(m.numberOfRows(), m.numberOfColumns()); } - } else if (isUnitConvert) { - /* Case 2: the initial expression is a unit convert, so we already beautified the result. */ - *simplifiedExpression = e; - if (approximateExpression) { - *approximateExpression = e; - } - return; } else { /* Case 3: the reduced expression is scalar or too complex to respect the * complex format. */ diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index ed3c62a20..bcf7d39a7 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -13,8 +13,12 @@ namespace Poincare { -Expression UnitConvertNode::shallowReduce(ReductionContext reductionContext) { - return UnitConvert(this).shallowReduce(reductionContext); +Expression UnitConvertNode::shallowBeautify(ReductionContext reductionContext) { + return UnitConvert(this).shallowBeautify(reductionContext); +} + +void UnitConvertNode::deepReduceChildren(ExpressionNode::ReductionContext reductionContext) { + UnitConvert(this).deepReduceChildren(reductionContext); } template @@ -25,17 +29,22 @@ Evaluation UnitConvertNode::templatedApproximate(Context * context, Preferenc return Complex::Undefined(); } -Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - { - Expression e = Expression::defaultShallowReduce(); - if (e.isUndefined()) { - return e; - } - } +void UnitConvert::deepReduceChildren(ExpressionNode::ReductionContext reductionContext) { + childAtIndex(0).deepReduce(reductionContext); + ExpressionNode::ReductionContext reductionContextKeepUnitAsIs = ExpressionNode::ReductionContext( + reductionContext.context(), + reductionContext.complexFormat(), + reductionContext.angleUnit(), + reductionContext.target(), + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined, + ExpressionNode::UnitConversion::None); + // Don't transform the targetted unit + childAtIndex(1).deepReduce(reductionContextKeepUnitAsIs); +} - // Find the unit +Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { + // Discard cases like 4 -> _m/_km { - // ExpressionNode::ReductionContext reductionContextWithUnits = ExpressionNode::ReductionContext( reductionContext.context(), reductionContext.complexFormat(), @@ -43,13 +52,13 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined); Expression unit; - childAtIndex(1).clone().reduce(reductionContextWithUnits).removeUnit(&unit); + childAtIndex(1).clone().deepReduce(reductionContextWithUnits).removeUnit(&unit); if (unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); } } - + // Find the unit ExpressionNode::ReductionContext reductionContextWithoutUnits = ExpressionNode::ReductionContext( reductionContext.context(), reductionContext.complexFormat(), @@ -57,29 +66,26 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined, ExpressionNode::UnitConversion::None); - Expression finalUnit; - childAtIndex(1).reduce(reductionContextWithoutUnits).removeUnit(&finalUnit); + Expression unit; + childAtIndex(1).removeUnit(&unit); + if (unit.isUninitialized()) { + // There is no unit on the right + return replaceWithUndefinedInPlace(); + } // Divide the left member by the new unit - Expression division = Division::Builder(childAtIndex(0), finalUnit.clone()); - division = division.reduce(reductionContext); + Expression division = Division::Builder(childAtIndex(0), unit.clone()); + division = division.deepReduce(reductionContext); Expression divisionUnit; division = division.removeUnit(&divisionUnit); if (!divisionUnit.isUninitialized()) { // The left and right members are not homogeneous return replaceWithUndefinedInPlace(); } - double floatValue = division.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); - if (std::isinf(floatValue)) { - return Infinity::Builder(floatValue < 0.0); //FIXME sign? - } - if (std::isnan(floatValue)) { - return Undefined::Builder(); - } - division = Multiplication::Builder(Float::Builder(floatValue), finalUnit); - static_cast(division).mergeSameTypeChildrenInPlace(); - replaceWithInPlace(division); - return division; + Expression result = Multiplication::Builder(division, unit); + replaceWithInPlace(result); + result.shallowReduce(reductionContextWithoutUnits); + return result.shallowBeautify(reductionContextWithoutUnits); } template Evaluation UnitConvertNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; From ae71c23147a0a0fc80cf51e200152597631a6da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 17 Apr 2020 17:43:04 +0200 Subject: [PATCH 074/453] [poincare] Override method Unit::node to return UnitNode --- poincare/include/poincare/unit.h | 1 + poincare/src/unit.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 6f5596cec..2d05ad88a 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -731,6 +731,7 @@ public: void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); private: + UnitNode * node() const { return static_cast(Expression::node()); } Expression removeUnit(Expression * unit); }; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 3b1e58654..91a4b3ef2 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -285,7 +285,7 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext if (reductionContext.unitConversion() == ExpressionNode::UnitConversion::None) { return *this; } - UnitNode * unitNode = static_cast(node()); + UnitNode * unitNode = node(); const Dimension * dim = unitNode->dimension(); const Representative * rep = unitNode->representative(); const Prefix * pre = unitNode->prefix(); @@ -315,7 +315,7 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext void Unit::chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext) { assert(value != 0 && !std::isnan(value) && !std::isinf(value) && exponent != 0); - UnitNode * unitNode = static_cast(node()); + UnitNode * unitNode = node(); const Dimension * dim = unitNode->dimension(); /* Find in the Dimension 'dim' which unit (Representative and Prefix) make * the value closer to 1. From 8a370966806b910b4c6a3415f7db49f11e75101d Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Thu, 12 Mar 2020 11:09:46 +0100 Subject: [PATCH 075/453] [nl] Start translation --- apps/Makefile | 3 + apps/calculation/Makefile | 1 + apps/calculation/base.nl.i18n | 9 ++ apps/code/Makefile | 3 + apps/code/base.nl.i18n | 8 ++ apps/code/catalog.nl.i18n | 185 ++++++++++++++++++++++++++++++++ apps/code/toolbox.nl.i18n | 4 + apps/graph/Makefile | 1 + apps/graph/base.nl.i18n | 33 ++++++ apps/home/Makefile | 1 + apps/home/base.nl.i18n | 4 + apps/language_nl.universal.i18n | 1 + apps/on_boarding/Makefile | 1 + apps/on_boarding/base.nl.i18n | 13 +++ apps/probability/Makefile | 1 + apps/probability/base.nl.i18n | 27 +++++ apps/regression/Makefile | 1 + apps/regression/base.nl.i18n | 21 ++++ apps/sequence/Makefile | 1 + apps/sequence/base.nl.i18n | 22 ++++ apps/settings/Makefile | 1 + apps/settings/base.nl.i18n | 41 +++++++ apps/shared.nl.i18n | 81 ++++++++++++++ apps/solver/Makefile | 1 + apps/solver/base.nl.i18n | 29 +++++ apps/statistics/Makefile | 1 + apps/statistics/base.nl.i18n | 25 +++++ apps/toolbox.nl.i18n | 167 ++++++++++++++++++++++++++++ apps/usb/Makefile | 1 + apps/usb/base.nl.i18n | 7 ++ apps/variables.nl.i18n | 10 ++ build/config.mak | 2 +- 32 files changed, 705 insertions(+), 1 deletion(-) create mode 100644 apps/calculation/base.nl.i18n create mode 100644 apps/code/base.nl.i18n create mode 100644 apps/code/catalog.nl.i18n create mode 100644 apps/code/toolbox.nl.i18n create mode 100644 apps/graph/base.nl.i18n create mode 100644 apps/home/base.nl.i18n create mode 100644 apps/language_nl.universal.i18n create mode 100644 apps/on_boarding/base.nl.i18n create mode 100644 apps/probability/base.nl.i18n create mode 100644 apps/regression/base.nl.i18n create mode 100644 apps/sequence/base.nl.i18n create mode 100644 apps/settings/base.nl.i18n create mode 100644 apps/shared.nl.i18n create mode 100644 apps/solver/base.nl.i18n create mode 100644 apps/statistics/base.nl.i18n create mode 100644 apps/toolbox.nl.i18n create mode 100644 apps/usb/base.nl.i18n create mode 100644 apps/variables.nl.i18n diff --git a/apps/Makefile b/apps/Makefile index 681b69805..ffcf1794c 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -65,17 +65,20 @@ i18n_files += $(addprefix apps/,\ shared.en.i18n\ shared.es.i18n\ shared.fr.i18n\ + shared.nl.i18n\ shared.pt.i18n\ shared.universal.i18n\ toolbox.de.i18n\ toolbox.en.i18n\ toolbox.es.i18n\ toolbox.fr.i18n\ + toolbox.nl.i18n\ toolbox.pt.i18n\ variables.de.i18n\ variables.en.i18n\ variables.es.i18n\ variables.fr.i18n\ + variables.nl.i18n\ variables.pt.i18n\ ) diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index a2de2432c..89e83582b 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -38,6 +38,7 @@ i18n_files += $(addprefix apps/calculation/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/calculation/base.nl.i18n b/apps/calculation/base.nl.i18n new file mode 100644 index 000000000..ab3718a15 --- /dev/null +++ b/apps/calculation/base.nl.i18n @@ -0,0 +1,9 @@ +CalculApp = "Calculatie" +CalculAppCapital = "CALCULATION" +AdditionalResults = "Additional results" +DecimalBase = "Decimal" +HexadecimalBase = "Hexadecimal" +BinaryBase = "Binary" +PrimeFactors = "Prime factors" +MixedFraction = "Mixed fraction" +EuclideanDivision = "Euclidean division" diff --git a/apps/code/Makefile b/apps/code/Makefile index aa61accc9..b3140cfea 100644 --- a/apps/code/Makefile +++ b/apps/code/Makefile @@ -34,18 +34,21 @@ i18n_files += $(addprefix apps/code/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ catalog.de.i18n\ catalog.en.i18n\ catalog.es.i18n\ catalog.fr.i18n\ + catalog.nl.i18n\ catalog.pt.i18n\ catalog.universal.i18n\ toolbox.de.i18n\ toolbox.en.i18n\ toolbox.es.i18n\ toolbox.fr.i18n\ + toolbox.nl.i18n\ toolbox.pt.i18n\ toolbox.universal.i18n\ ) diff --git a/apps/code/base.nl.i18n b/apps/code/base.nl.i18n new file mode 100644 index 000000000..8bf1e3c9f --- /dev/null +++ b/apps/code/base.nl.i18n @@ -0,0 +1,8 @@ +Console = "Python shell" +AddScript = "Add a script" +ScriptOptions = "Script options" +ExecuteScript = "Execute script" +AutoImportScript = "Auto import in shell" +DeleteScript = "Delete script" +FunctionsAndVariables = "Functions and variables" +AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n new file mode 100644 index 000000000..5f6bc9416 --- /dev/null +++ b/apps/code/catalog.nl.i18n @@ -0,0 +1,185 @@ +PythonPound = "Comment" +PythonPercent = "Modulo" +Python1J = "Imaginary i" +PythonLF = "Line feed" +PythonTab = "Tabulation" +PythonAmpersand = "Bitwise and" +PythonSymbolExp = "Bitwise exclusive or" +PythonVerticalBar = "Bitwise or" +PythonImag = "Imaginary part of z" +PythonReal = "Real part of z" +PythonSingleQuote = "Single quote" +PythonAbs = "Absolute value/Magnitude" +PythonAcos = "Arc cosine" +PythonAcosh = "Arc hyperbolic cosine" +PythonAppend = "Add x to the end of the list" +PythonAsin = "Arc sine" +PythonAsinh = "Arc hyperbolic sine" +PythonAtan = "Arc tangent" +PythonAtan2 = "Return atan(y/x)" +PythonAtanh = "Arc hyperbolic tangent" +PythonBin = "Convert integer to binary" +PythonCeil = "Ceiling" +PythonChoice = "Random number in the list" +PythonClear = "Empty the list" +PythonCmathFunction = "cmath module function prefix" +PythonColor = "Define a rgb color" +PythonComplex = "Return a+ib" +PythonCopySign = "Return x with the sign of y" +PythonCos = "Cosine" +PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the occurrences of x" +PythonDegrees = "Convert x from radians to degrees" +PythonDivMod = "Quotient and remainder" +PythonDrawString = "Display a text from pixel (x,y)" +PythonErf = "Error function" +PythonErfc = "Complementary error function" +PythonEval = "Return the evaluated expression" +PythonExp = "Exponential function" +PythonExpm1 = "Compute exp(x)-1" +PythonFabs = "Absolute value" +PythonFillRect = "Fill a rectangle at pixel (x,y)" +PythonFloat = "Convert x to a float" +PythonFloor = "Floor" +PythonFmod = "a modulo b" +PythonFrExp = "Mantissa and exponent of x" +PythonGamma = "Gamma function" +PythonGetPixel = "Return pixel (x,y) color" +PythonGetrandbits = "Integer with k random bits" +PythonHex = "Convert integer to hexadecimal" +PythonImportCmath = "Import cmath module" +PythonImportIon = "Import ion module" +PythonImportKandinsky = "Import kandinsky module" +PythonImportRandom = "Import random module" +PythonImportMath = "Import math module" +PythonImportTime = "Import time module" +PythonImportTurtle = "Import turtle module" +PythonIndex = "Index of the first x occurrence" +PythonInput = "Prompt a value" +PythonInsert = "Insert x at index i in the list" +PythonInt = "Convert x to an integer" +PythonIonFunction = "ion module function prefix" +PythonIsFinite = "Check if x is finite" +PythonIsInfinite = "Check if x is infinity" +PythonIsKeyDown = "Return True if the k key is down" +PythonIsNaN = "Check if x is a NaN" +PythonKandinskyFunction = "kandinsky module function prefix" +PythonKeyLeft = "LEFT ARROW key" +PythonKeyUp = "UP ARROW key" +PythonKeyDown = "DOWN ARROW key" +PythonKeyRight = "RIGHT ARROW key" +PythonKeyOk = "OK key" +PythonKeyBack = "BACK key" +PythonKeyHome = "HOME key" +PythonKeyOnOff = "ON/OFF key" +PythonKeyShift = "SHIFT key" +PythonKeyAlpha = "ALPHA key" +PythonKeyXnt = "X,N,T key" +PythonKeyVar = "VAR key" +PythonKeyToolbox = "TOOLBOX key" +PythonKeyBackspace = "BACKSPACE key" +PythonKeyExp = "EXPONENTIAL key" +PythonKeyLn = "NATURAL LOGARITHM key" +PythonKeyLog = "DECIMAL LOGARITHM key" +PythonKeyImaginary = "IMAGINARY I key" +PythonKeyComma = "COMMA key" +PythonKeyPower = "POWER key" +PythonKeySine = "SINE key" +PythonKeyCosine = "COSINE key" +PythonKeyTangent = "TANGENT key" +PythonKeyPi = "PI key" +PythonKeySqrt = "SQUARE ROOT key" +PythonKeySquare = "SQUARE key" +PythonKeySeven = "7 key" +PythonKeyEight = "8 key" +PythonKeyNine = "9 key" +PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" +PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" +PythonKeyFour = "4 key" +PythonKeyFive = "5 key" +PythonKeySix = "6 key" +PythonKeyMultiplication = "MULTIPLICATION key" +PythonKeyDivision = "DIVISION key" +PythonKeyOne = "1 key" +PythonKeyTwo = "2 key" +PythonKeyThree = "3 key" +PythonKeyPlus = "PLUS key" +PythonKeyMinus = "MINUS key" +PythonKeyZero = "0 key" +PythonKeyDot = "DOT key" +PythonKeyEe = "10 POWER X key" +PythonKeyAns = "ANS key" +PythonKeyExe = "EXE key" +PythonLdexp = "Return x*(2**i), inverse of frexp" +PythonLength = "Length of an object" +PythonLgamma = "Log-gamma function" +PythonLog = "Logarithm to base a" +PythonLog10 = "Logarithm to base 10" +PythonLog2 = "Logarithm to base 2" +PythonMathFunction = "math module function prefix" +PythonMax = "Maximum" +PythonMin = "Minimum" +PythonModf = "Fractional and integer parts of x" +PythonMonotonic = "Value of a monotonic clock" +PythonOct = "Convert integer to octal" +PythonPhase = "Phase of z" +PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return the last item" +PythonPower = "x raised to the power y" +PythonPrint = "Print object" +PythonRadians = "Convert x from degrees to radians" +PythonRandint = "Random integer in [a,b]" +PythonRandom = "Floating point number in [0,1[" +PythonRandomFunction = "random module function prefix" +PythonRandrange = "Random number in range(start, stop)" +PythonRangeStartStop = "List from start to stop-1" +PythonRangeStop = "List from 0 to stop-1" +PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" +PythonRound = "Round to n digits" +PythonSeed = "Initialize random number generator" +PythonSetPixel = "Color pixel (x,y)" +PythonSin = "Sine" +PythonSinh = "Hyperbolic sine" +PythonSleep = "Suspend the execution for t seconds" +PythonSort = "Sort the list" +PythonSqrt = "Square root" +PythonSum = "Sum the items of a list" +PythonTan = "Tangent" +PythonTanh = "Hyperbolic tangent" +PythonTimeFunction = "time module function prefix" +PythonTrunc = "x truncated to an integer" +PythonTurtleBackward = "Move backward by x pixels" +PythonTurtleBlack = "Black color" +PythonTurtleBlue = "Blue color" +PythonTurtleBrown = "Brown color" +PythonTurtleCircle = "Circle of radius r pixels" +PythonTurtleColor = "Set the pen color" +PythonTurtleColorMode = "Set the color mode to 1.0 or 255" +PythonTurtleForward = "Move forward by x pixels" +PythonTurtleFunction = "turtle module function prefix" +PythonTurtleGoto = "Move to (x,y) coordinates" +PythonTurtleGreen = "Green color" +PythonTurtleGrey = "Grey color" +PythonTurtleHeading = "Return the current heading" +PythonTurtleHideturtle = "Hide the turtle" +PythonTurtleIsdown = "Return True if the pen is down" +PythonTurtleLeft = "Turn left by a degrees" +PythonTurtleOrange = "Orange color" +PythonTurtlePendown = "Pull the pen down" +PythonTurtlePensize = "Set the line thickness to x pixels" +PythonTurtlePenup = "Pull the pen up" +PythonTurtlePink = "Pink color" +PythonTurtlePosition = "Return the current (x,y) location" +PythonTurtlePurple = "Purple color" +PythonTurtleRed = "Red color" +PythonTurtleReset = "Reset the drawing" +PythonTurtleRight = "Turn right by a degrees" +PythonTurtleSetheading = "Set the orientation to a degrees" +PythonTurtleSetposition = "Positionne la tortue" +PythonTurtleShowturtle = "Show the turtle" +PythonTurtleSpeed = "Drawing speed between 0 and 10" +PythonTurtleWhite = "White color" +PythonTurtleYellow = "Yellow color" +PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/toolbox.nl.i18n b/apps/code/toolbox.nl.i18n new file mode 100644 index 000000000..178d42b7b --- /dev/null +++ b/apps/code/toolbox.nl.i18n @@ -0,0 +1,4 @@ +Functions = "Functions" +Catalog = "Catalog" +Modules = "Modules" +LoopsAndTests = "Loops and tests" diff --git a/apps/graph/Makefile b/apps/graph/Makefile index 482528ad2..d4fdfdb9a 100644 --- a/apps/graph/Makefile +++ b/apps/graph/Makefile @@ -38,6 +38,7 @@ i18n_files += $(addprefix apps/graph/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/graph/base.nl.i18n b/apps/graph/base.nl.i18n new file mode 100644 index 000000000..c65a3370e --- /dev/null +++ b/apps/graph/base.nl.i18n @@ -0,0 +1,33 @@ +FunctionApp = "Functions" +FunctionAppCapital = "FUNCTIONS" +FunctionTab = "Functions" +AddFunction = "Add function" +DeleteFunction = "Delete function" +CurveType = "Curve type" +CartesianType = "Cartesian " +PolarType = "Polar " +ParametricType = "Parametric " +IntervalT = "t interval" +IntervalTheta = "θ interval" +IntervalX = "x interval" +FunctionDomain = "Plot range" +FunctionColor = "Function color" +NoFunction = "No function" +NoActivatedFunction = "No function is turned on" +PlotOptions = "Plot options" +Compute = "Calculate" +Zeros = "Zeros" +Tangent = "Tangent" +Intersection = "Intersection" +Preimage = "Inverse image" +SelectLowerBound = "Select lower bound" +SelectUpperBound = "Select upper bound" +NoMaximumFound = "No maximum found" +NoMinimumFound = "No minimum found" +NoZeroFound = "No zero found" +NoIntersectionFound = "No intersection found" +NoPreimageFound = "No inverse image found" +DerivativeFunctionColumn = "Derivative function column" +HideDerivativeColumn = "Hide the derivative function" +AllowedCharactersAZaz09 = "Allowed characters: A-Z, a-z, 0-9, _" +ReservedName = "Reserved name" diff --git a/apps/home/Makefile b/apps/home/Makefile index d052cada2..691a6ac86 100644 --- a/apps/home/Makefile +++ b/apps/home/Makefile @@ -11,5 +11,6 @@ i18n_files += $(addprefix apps/home/,\ base.en.i18n \ base.es.i18n \ base.fr.i18n \ + base.nl.i18n \ base.pt.i18n \ ) diff --git a/apps/home/base.nl.i18n b/apps/home/base.nl.i18n new file mode 100644 index 000000000..158fa3bda --- /dev/null +++ b/apps/home/base.nl.i18n @@ -0,0 +1,4 @@ +Apps = "Applications" +AppsCapital = "APPLICATIONS" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/language_nl.universal.i18n b/apps/language_nl.universal.i18n new file mode 100644 index 000000000..a509bf7b0 --- /dev/null +++ b/apps/language_nl.universal.i18n @@ -0,0 +1 @@ +LanguageNL = "Nederlands " diff --git a/apps/on_boarding/Makefile b/apps/on_boarding/Makefile index 7942bd97f..06f95ba74 100644 --- a/apps/on_boarding/Makefile +++ b/apps/on_boarding/Makefile @@ -14,6 +14,7 @@ i18n_files += $(addprefix apps/on_boarding/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/on_boarding/base.nl.i18n b/apps/on_boarding/base.nl.i18n new file mode 100644 index 000000000..b923a3291 --- /dev/null +++ b/apps/on_boarding/base.nl.i18n @@ -0,0 +1,13 @@ +UpdateAvailable = "UPDATE AVAILABLE" +UpdateMessage1 = "There are important upgrades" +UpdateMessage2 = "for your calculator." +UpdateMessage3 = "Browse our page from your computer" +UpdateMessage4 = "www.numworks.com/update" +BetaVersion = "BETA VERSION" +BetaVersionMessage1 = "" +BetaVersionMessage2 = "Your device runs a beta software." +BetaVersionMessage3 = "You might run into bugs or glitches." +BetaVersionMessage4 = "" +BetaVersionMessage5 = "Please send any feedback to" +BetaVersionMessage6 = "contact@numworks.com" +Skip = "Skip" diff --git a/apps/probability/Makefile b/apps/probability/Makefile index c2d1080dc..b9b5c189c 100644 --- a/apps/probability/Makefile +++ b/apps/probability/Makefile @@ -45,6 +45,7 @@ i18n_files += $(addprefix apps/probability/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ ) diff --git a/apps/probability/base.nl.i18n b/apps/probability/base.nl.i18n new file mode 100644 index 000000000..c05cf05bb --- /dev/null +++ b/apps/probability/base.nl.i18n @@ -0,0 +1,27 @@ +ProbaApp = "Probability" +ProbaAppCapital = "PROBABILITY" +ChooseDistribution = "Choose the distribution" +Binomial = "Binomial" +Geometric = "Geometric" +Uniforme = "Uniform" +Normal = "Normal" +ChiSquared = "Chi-squared" +UniformDistribution = "Uniform distribution" +ExponentialDistribution = "Exponential distribution" +GeometricDistribution = "Geometric distribution" +PoissonDistribution = "Poisson distribution" +ChiSquaredDistribution = "Chi-squared distribution" +StudentDistribution = "Student's distribution" +FisherDistribution = "F distribution" +ChooseParameters = "Choose parameters" +RepetitionNumber = "n: Number of trials" +SuccessProbability = "p: Success probability" +IntervalDefinition = "[a,b]: Interval" +LambdaExponentialDefinition = "λ: Rate parameter" +MeanDefinition = "μ: Mean" +DeviationDefinition = "σ: Standard deviation" +LambdaPoissonDefinition = "λ: Parameter" +DegreesOfFreedomDefinition = "k: Degrees of freedom" +D1FisherDefinition = "d1: Degrees of freedom of the numerator" +D2FisherDefinition = "d2: Degrees of freedom of the denominator" +ComputeProbability = "Calculate probabilities" diff --git a/apps/regression/Makefile b/apps/regression/Makefile index e63a802cb..239cf0376 100644 --- a/apps/regression/Makefile +++ b/apps/regression/Makefile @@ -45,6 +45,7 @@ i18n_files += $(addprefix apps/regression/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ ) diff --git a/apps/regression/base.nl.i18n b/apps/regression/base.nl.i18n new file mode 100644 index 000000000..fc6f307f2 --- /dev/null +++ b/apps/regression/base.nl.i18n @@ -0,0 +1,21 @@ +RegressionApp = "Regression" +RegressionAppCapital = "REGRESSION" +Regression = "Regression" +Reg = "reg" +MeanDot = "mean" +RegressionCurve = "Regression curve" +XPrediction = "Prediction given X" +YPrediction = "Prediction given Y" +ValueNotReachedByRegression = "Value not reached in this window" +NumberOfDots = "Number of points" +Covariance = "Covariance" +Linear = "Linear" +Proportional = "Proportioneel" +Quadratic = "Quadratic" +Cubic = "Cubic" +Quartic = "Quartic" +Logarithmic = "Logarithmic" +Power = "Power" +Trigonometrical = "Trigonometric" +Logistic = "Logistic" +DataNotSuitableForRegression = " Data not suitable for this regression model" diff --git a/apps/sequence/Makefile b/apps/sequence/Makefile index 4320815e7..ee1b38ee5 100644 --- a/apps/sequence/Makefile +++ b/apps/sequence/Makefile @@ -33,6 +33,7 @@ i18n_files += $(addprefix apps/sequence/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/sequence/base.nl.i18n b/apps/sequence/base.nl.i18n new file mode 100644 index 000000000..e9917698c --- /dev/null +++ b/apps/sequence/base.nl.i18n @@ -0,0 +1,22 @@ +SequenceApp = "Sequences" +SequenceAppCapital = "SEQUENCES" +SequenceTab = "Sequences" +AddSequence = "Add sequence" +ChooseSequenceType = "Choose sequence type" +SequenceType = "Sequence type" +Explicit = "Explicit expression" +SingleRecurrence = "Recursive first order" +DoubleRecurrence = "Recursive second order" +SequenceOptions = "Sequence options" +SequenceColor = "Sequence color" +DeleteSequence = "Delete sequence" +NoSequence = "No sequence" +NoActivatedSequence = "No sequence is turned on" +NStart = "N start" +NEnd = "N end" +TermSum = "Sum of terms" +SelectFirstTerm = "Select First Term " +SelectLastTerm = "Select last term " +ValueNotReachedBySequence = "Value not reached by sequence" +NColumn = "n column" +FirstTermIndex = "First term index" diff --git a/apps/settings/Makefile b/apps/settings/Makefile index 5334f862c..bd65b2692 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -30,6 +30,7 @@ i18n_files += $(addprefix apps/settings/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n new file mode 100644 index 000000000..f7ea577db --- /dev/null +++ b/apps/settings/base.nl.i18n @@ -0,0 +1,41 @@ +SettingsApp = "Settings" +SettingsAppCapital = "SETTINGS" +AngleUnit = "Angle measure" +DisplayMode = "Result format" +EditionMode = "Writing format" +EditionLinear = "Linear " +Edition2D = "Natural " +ComplexFormat = "Complex format" +ExamMode = "Exam mode" +ExamModeActive = "Reactivate exam mode" +ToDeactivateExamMode1 = "To deactivate the exam mode," +ToDeactivateExamMode2 = "plug the calculator to a computer" +ToDeactivateExamMode3 = "or to a power socket." +# --------------------- Please do not edit these messages --------------------- +ExamModeWarning1 = "Caution: compliance of this" +ExamModeWarning2 = "unofficial software's exam mode" +ExamModeWarning3 = "is not guaranteed by NumWorks." +AboutWarning1 = "Caution: you're using an" +AboutWarning2 = "unofficial software version." +AboutWarning3 = "NumWorks can't be held responsible" +AboutWarning4 = "for any resulting damage." +# ----------------------------------------------------------------------------- +About = "About" +Degrees = "Degrees " +Gradians = "Gradians " +Radian = "Radians " +Decimal = "Decimal " +Scientific = "Scientific " +Engineering = "Engineering " +SignificantFigures = "Significant figures " +Real = "Real " +Cartesian = "Cartesian " +Polar = "Polar " +Brightness = "Brightness" +FontSizes = "Python font size" +LargeFont = "Large " +SmallFont = "Small " +SoftwareVersion = "Software version" +SerialNumber = "Serial number" +UpdatePopUp = "Update pop-up" +BetaPopUp = "Beta pop-up" diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n new file mode 100644 index 000000000..761eabbb9 --- /dev/null +++ b/apps/shared.nl.i18n @@ -0,0 +1,81 @@ +ActivateDeactivate = "Turn on/off" +ActivateExamMode = "Activate exam mode" +ActivateDutchExamMode = "Activate Dutch exam mode" +ActiveExamModeMessage1 = "All your data will be " +ActiveExamModeMessage2 = "deleted when you activate " +ActiveExamModeMessage3 = "the exam mode." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." +Axis = "Axes" +Cancel = "Cancel" +ClearColumn = "Clear column" +ColumnOptions = "Column options" +CopyColumnInList = "Export the column to a list" +DataNotSuitable = "Data not suitable" +DataTab = "Data" +DefaultSetting = "Basic settings" +Deg = "deg" +Deviation = "Variance" +DisplayValues = "Display values" +Empty = "Empty" +Eng = "eng" +ExitExamMode1 = "Exit the exam " +ExitExamMode2 = "mode?" +Exponential = "Exponential" +FillWithFormula = "Fill with a formula" +ForbiddenValue = "Forbidden value" +FunctionColumn = "0(0) column" +FunctionOptions = "Function options" +Goto = "Go to" +GraphTab = "Graph" +HardwareTestLaunch1 = "You are starting the hardware" +HardwareTestLaunch2 = " test. At the end of the test, you" +HardwareTestLaunch3 = "will have to reset the device and" +HardwareTestLaunch4 = "all your data will be deleted." +Initialization = "Preadjustment" +IntervalSet = "Set the interval" +Language = "Language" +LowBattery = "Low battery" +Mean = "Mean" +Move = " Move: " +NameCannotStartWithNumber = "A name cannot start with a number" +NameTaken = "This name has already been taken" +NameTooLong = "This name is too long" +Next = "Next" +NoDataToPlot = "No data to draw" +NoFunctionToDelete = "No function to delete" +NoValueToCompute = "No values to calculate" +NEnd = "N end" +NStart = "N start" +Ok = "Confirm" +Or = " or " +Orthonormal = "Orthonormal" +Plot = "Plot graph" +PoolMemoryFull1 = "The working memory is full." +PoolMemoryFull2 = "Try again." +Rad = "rad" +Rename = "Rename" +RoundAbscissa = "Integer" +Sci = "sci" +SquareSum = "Sum of squares" +StandardDeviation = "Standard deviation" +StoreExpressionNotAllowed = "'store' is not allowed" +StatTab = "Stats" +Step = "Step" +StorageMemoryFull1 = "The memory is full." +StorageMemoryFull2 = "Erase data and try again." +SyntaxError = "Syntax error" +TEnd = "T end" +ThetaEnd = "θ end" +ThetaStart = "θ start" +TStart = "T start" +ToZoom = "Zoom: " +Trigonometric = "Trigonometrical" +UndefinedValue = "Undefined value" +ValueNotReachedByFunction = "Value not reached by function" +ValuesTab = "Table" +Warning = "Warning" +XEnd = "X end" +XStart = "X start" +Zoom = "Zoom" diff --git a/apps/solver/Makefile b/apps/solver/Makefile index 447fec0b4..e85014c6c 100644 --- a/apps/solver/Makefile +++ b/apps/solver/Makefile @@ -23,6 +23,7 @@ i18n_files += $(addprefix apps/solver/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/solver/base.nl.i18n b/apps/solver/base.nl.i18n new file mode 100644 index 000000000..017cad04d --- /dev/null +++ b/apps/solver/base.nl.i18n @@ -0,0 +1,29 @@ +SolverApp = "Equations" +SolverAppCapital = "EQUATIONS" +AddEquation = "Add equation" +ResolveEquation = "Solve the equation" +ResolveSystem = "Solve the system" +UseEquationModel = "Use an equation template" +RequireEquation = "The input must be an equation" +UnrealEquation = "Unreal equation" +UndefinedEquation = "Undefined equation" +TooManyVariables = "There are too many unknowns" +NonLinearSystem = "The system is not linear" +Solution = "Solution" +ApproximateSolution = "Approximate solution" +SearchInverval = "Search interval" +NoSolutionSystem = "The system has no solution" +NoSolutionEquation = "The equation has no solution" +NoSolutionInterval = "No solution found in the interval" +EnterEquation = "Enter an equation" +InfiniteNumberOfSolutions = "There are an infinite number of solutions" +ApproximateSolutionIntervalInstruction0= "Enter the interval to search" +ApproximateSolutionIntervalInstruction1= "for an approximate solution" +OnlyFirstSolutionsDisplayed0 = "Only the first 10 solutions" +OnlyFirstSolutionsDisplayed1 = "are displayed" +PolynomeHasNoRealSolution0 = "The polynomial has no" +PolynomeHasNoRealSolution1 = "real root" +PredefinedVariablesUsedLeft = "Used " +PredefinedVariablesUsedRight = "predefined variables" +PredefinedVariablesIgnoredLeft = "Ignored" +PredefinedVariablesIgnoredRight = " predefined variables" diff --git a/apps/statistics/Makefile b/apps/statistics/Makefile index 34e9cb878..f7543025a 100644 --- a/apps/statistics/Makefile +++ b/apps/statistics/Makefile @@ -34,6 +34,7 @@ i18n_files += $(addprefix apps/statistics/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/statistics/base.nl.i18n b/apps/statistics/base.nl.i18n new file mode 100644 index 000000000..61091e835 --- /dev/null +++ b/apps/statistics/base.nl.i18n @@ -0,0 +1,25 @@ +StatsApp = "Statistics" +StatsAppCapital = "STATISTICS" +HistogramTab = "Histogram" +BoxTab = "Box" +Values1 = "Values V1" +Values2 = "Values V2" +Values3 = "Values V3" +Sizes1 = "Sizes N1" +Sizes2 = "Sizes N2" +Sizes3 = "Sizes N3" +ImportList = "Import from a list" +Interval = " Interval " +Size = " Size" +Frequency = "Frequency" +HistogramSet = "Histogram settings" +RectangleWidth = "Bin width" +BarStart = "X start" +FirstQuartile = "First quartile" +Median = "Median" +ThirdQuartile = "Third quartile" +TotalSize = "Total size" +Range = "Range" +StandardDeviationSigma = "Standard deviation σ" +SampleStandardDeviationS = "Sample std deviation s" +InterquartileRange = "Interquartile range" diff --git a/apps/toolbox.nl.i18n b/apps/toolbox.nl.i18n new file mode 100644 index 000000000..c80a6038c --- /dev/null +++ b/apps/toolbox.nl.i18n @@ -0,0 +1,167 @@ +Unit = "Units" +UnitTimeMenu = "Time" +UnitTimeSecondMenu = "Second" +UnitTimeSecond = "Second" +UnitTimeSecondMilli = "Millisecond" +UnitTimeSecondMicro = "Microsecond" +UnitTimeSecondNano = "Nanosecond" +UnitTimeMinute = "Minute" +UnitTimeHour = "Hour" +UnitTimeDay = "Day" +UnitTimeWeek = "Week" +UnitTimeMonth = "Month" +UnitTimeYear = "Year" +UnitDistanceMenu = "Distance" +UnitDistanceMeterMenu = "Meter" +UnitDistanceMeterKilo = "Kilometer" +UnitDistanceMeter = "Meter" +UnitDistanceMeterMilli = "Millimeter" +UnitDistanceMeterMicro = "Micrometer" +UnitDistanceMeterNano = "Nanometer" +UnitDistanceMeterPico = "Picometer" +UnitDistanceAstronomicalUnit = "Astronomical unit" +UnitDistanceLightYear = "Light year" +UnitDistanceParsec = "Parsec" +UnitMassMenu = "Mass" +UnitMassGramKilo = "Kilogram" +UnitMassGram = "Gram" +UnitMassGramMilli = "Milligram" +UnitMassGramMicro = "Microgram" +UnitMassGramNano = "Nanogram" +UnitMassTonne = "Tonne" +UnitCurrentMenu = "Electric current" +UnitCurrentAmpere = "Ampere" +UnitCurrentAmpereMilli = "Milliampere" +UnitCurrentAmpereMicro = "Microampere" +UnitTemperatureMenu = "Temperature" +UnitTemperatureKelvin = "Kelvin" +UnitAmountMenu = "Amount of substance" +UnitAmountMole = "Mole" +UnitAmountMoleMilli = "Millimole" +UnitAmountMoleMicro = "Micromole" +UnitLuminousIntensityMenu = "Luminous intensity" +UnitLuminousIntensityCandela = "Candela" +UnitFrequencyMenu = "Frequency" +UnitFrequencyHertzGiga = "Gigahertz" +UnitFrequencyHertzMega = "Megahertz" +UnitFrequencyHertzKilo = "Kilohertz" +UnitFrequencyHertz = "Hertz" +UnitForceMenu = "Force" +UnitForceNewtonKilo = "Kilonewton" +UnitForceNewton = "Newton" +UnitForceNewtonMilli = "Millinewton" +UnitPressureMenu = "Pressure" +UnitPressurePascal = "Pascal" +UnitPressurePascalHecto = "Hectopascal" +UnitPressureBar = "Bar" +UnitPressureAtm = "Atmosphere" +UnitEnergyMenu = "Energy" +UnitEnergyJouleMenu = "Joule" +UnitEnergyJouleKilo = "Kilojoule" +UnitEnergyJoule = "Joule" +UnitEnergyJouleMilli = "Millijoule" +UnitEnergyEletronVoltMenu = "Electronvolt" +UnitEnergyElectronVoltMega = "Megaelectronvolt" +UnitEnergyElectronVoltKilo = "Kiloelectronvolt" +UnitEnergyElectronVolt = "Electronvolt" +UnitEnergyElectronVoltMilli = "Millielectronvolt" +UnitPowerMenu = "Power" +UnitPowerWattGiga = "Gigawatt" +UnitPowerWattMega = "Megawatt" +UnitPowerWattKilo = "Kilowatt" +UnitPowerWatt = "Watt" +UnitPowerWattMilli = "Milliwatt" +UnitPowerWattMicro = "Microwatt" +UnitElectricChargeMenu = "Electric charge" +UnitChargeCoulomb = "Coulomb" +UnitPotentialMenu = "Electric potential" +UnitPotentialVoltKilo = "Kilovolt" +UnitPotentialVolt = "Volt" +UnitPotentialVoltMilli = "Millivolt" +UnitPotentialVoltMicro = "Microvolt" +UnitCapacitanceMenu = "Electrical capacitance" +UnitCapacitanceFarad = "Farad" +UnitCapacitanceFaradMilli = "Millifarad" +UnitCapacitanceFaradMicro = "Microfarad" +UnitResistanceMenu = "Electrical resistance" +UnitResistanceOhmKilo = "Kiloohm" +UnitResistanceOhm = "Ohm" +UnitConductanceMenu = "Electrical conductance" +UnitConductanceSiemens = "Siemens" +UnitConductanceSiemensMilli = "Millisiemens" +UnitMagneticFieldMenu = "Magnetic field" +UnitMagneticFieldTesla = "Tesla" +InductanceMenu = "Electrical inductance" +UnitInductanceHenry = "Henry" +UnitSurfaceMenu = "Area" +UnitSurfaceHectar = "Hectare" +UnitVolumeMenu = "Volume" +UnitVolumeLiter = "Liter" +UnitVolumeLiterDeci = "Deciliter" +UnitVolumeLiterCenti = "Centiliter" +UnitVolumeLiterMilli = "Milliliter" +Toolbox = "Toolbox" +AbsoluteValue = "Absolute value" +NthRoot = "nth-root" +BasedLogarithm = "Logarithm to base a" +Calculation = "Calculation" +ComplexNumber = "Complex numbers" +Combinatorics = "Combinatorics" +Arithmetic = "Arithmetic" +Matrices = "Matrix" +NewMatrix = "New matrix" +Identity = "Identity matrix of size n" +Lists = "List" +HyperbolicTrigonometry = "Hyperbolic trigonometry" +Fluctuation = "Prediction Interval" +DerivateNumber = "Derivative" +Integral = "Integral" +Sum = "Sum" +Product = "Product" +ComplexAbsoluteValue = "Absolute value" +Agument = "Argument" +RealPart = "Real part" +ImaginaryPart = "Imaginary part" +Conjugate = "Conjugate" +Combination = "Combination" +Permutation = "Permutation" +GreatCommonDivisor = "GCD" +LeastCommonMultiple = "LCM" +Remainder = "Remainder division p by q" +Quotient = "Quotient division p by q" +Inverse = "Inverse" +Determinant = "Determinant" +Transpose = "Transpose" +Trace = "Trace" +Dimension = "Size" +Sort = "Sort ascending " +InvSort = "Sort descending" +Maximum = "Maximum" +Minimum = "Minimum" +Floor = "Floor" +FracPart = "Fractional part" +Ceiling = "Ceiling" +Rounding = "Rounding to n digits" +HyperbolicCosine = "Hyperbolic cosine" +HyperbolicSine = "Hyperbolic sine" +HyperbolicTangent = "Hyperbolic tangent" +InverseHyperbolicCosine = "Inverse hyperbolic cosine" +InverseHyperbolicSine = "Inverse hyperbolic sine" +InverseHyperbolicTangent = "Inverse hyperbolic tangent" +Prediction95 = "Prediction interval 95%" +Prediction = "Simple prediction interval" +Confidence = "Confidence interval" +RandomAndApproximation = "Random and approximation" +RandomFloat = "Floating point number in [0,1[" +RandomInteger = "Random integer in [a,b]" +PrimeFactorDecomposition = "Integer factorization" +NormCDF = "P(X Date: Fri, 13 Mar 2020 11:44:24 +0100 Subject: [PATCH 076/453] [nl] Translation Python-app --- apps/calculation/base.nl.i18n | 16 +- apps/code/base.nl.i18n | 14 +- apps/code/catalog.nl.i18n | 360 +++++++++++++++++----------------- apps/settings/base.nl.i18n | 2 +- 4 files changed, 196 insertions(+), 196 deletions(-) diff --git a/apps/calculation/base.nl.i18n b/apps/calculation/base.nl.i18n index ab3718a15..0ae59c24a 100644 --- a/apps/calculation/base.nl.i18n +++ b/apps/calculation/base.nl.i18n @@ -1,9 +1,9 @@ CalculApp = "Calculatie" -CalculAppCapital = "CALCULATION" -AdditionalResults = "Additional results" -DecimalBase = "Decimal" -HexadecimalBase = "Hexadecimal" -BinaryBase = "Binary" -PrimeFactors = "Prime factors" -MixedFraction = "Mixed fraction" -EuclideanDivision = "Euclidean division" +CalculAppCapital = "CALCULATIE" +AdditionalResults = "Bijkomende resultaten" +DecimalBase = "Decimaal" +HexadecimalBase = "Hexadecimaal" +BinaryBase = "Binaire" +PrimeFactors = "Priemfactoren" +MixedFraction = "Gemengde breuk" +EuclideanDivision = "Geheeltallige deling" diff --git a/apps/code/base.nl.i18n b/apps/code/base.nl.i18n index 8bf1e3c9f..a898aa833 100644 --- a/apps/code/base.nl.i18n +++ b/apps/code/base.nl.i18n @@ -1,8 +1,8 @@ Console = "Python shell" -AddScript = "Add a script" -ScriptOptions = "Script options" -ExecuteScript = "Execute script" -AutoImportScript = "Auto import in shell" -DeleteScript = "Delete script" -FunctionsAndVariables = "Functions and variables" -AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" +AddScript = "Script toevoegen" +ScriptOptions = "Script opties" +ExecuteScript = "Script uitvoeren" +AutoImportScript = "Automatisch importeren in shell" +DeleteScript = "Script verwijderen" +FunctionsAndVariables = "Functies en variabelen" +AllowedCharactersaz09 = "Toegestane tekens: a-z, 0-9, _" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index 5f6bc9416..03f10f0f8 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -1,185 +1,185 @@ -PythonPound = "Comment" +PythonPound = "Opmerkingen" PythonPercent = "Modulo" -Python1J = "Imaginary i" -PythonLF = "Line feed" -PythonTab = "Tabulation" -PythonAmpersand = "Bitwise and" -PythonSymbolExp = "Bitwise exclusive or" -PythonVerticalBar = "Bitwise or" -PythonImag = "Imaginary part of z" -PythonReal = "Real part of z" -PythonSingleQuote = "Single quote" -PythonAbs = "Absolute value/Magnitude" -PythonAcos = "Arc cosine" -PythonAcosh = "Arc hyperbolic cosine" -PythonAppend = "Add x to the end of the list" -PythonAsin = "Arc sine" -PythonAsinh = "Arc hyperbolic sine" -PythonAtan = "Arc tangent" -PythonAtan2 = "Return atan(y/x)" -PythonAtanh = "Arc hyperbolic tangent" -PythonBin = "Convert integer to binary" -PythonCeil = "Ceiling" -PythonChoice = "Random number in the list" -PythonClear = "Empty the list" -PythonCmathFunction = "cmath module function prefix" -PythonColor = "Define a rgb color" -PythonComplex = "Return a+ib" -PythonCopySign = "Return x with the sign of y" -PythonCos = "Cosine" -PythonCosh = "Hyperbolic cosine" -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" -PythonErf = "Error function" -PythonErfc = "Complementary error function" -PythonEval = "Return the evaluated expression" -PythonExp = "Exponential function" -PythonExpm1 = "Compute exp(x)-1" -PythonFabs = "Absolute value" -PythonFillRect = "Fill a rectangle at pixel (x,y)" -PythonFloat = "Convert x to a float" -PythonFloor = "Floor" +Python1J = "Imaginaire i" +PythonLF = "Nieuwe regel" +PythonTab = "Tabulatie" +PythonAmpersand = "Bitsgewijze en" +PythonSymbolExp = "Bitsgewijze exclusieve of" +PythonVerticalBar = "Bitsgewijze of" +PythonImag = "Imaginair deel van z" +PythonReal = "Reëel deel van z" +PythonSingleQuote = "Enkele aanhalingstekens" +PythonAbs = "Absolute waarde" +PythonAcos = "Arccosinus" +PythonAcosh = "Arccosinus hyperbolicus" +PythonAppend = "Voeg x toe aan het eind van je lijst" +PythonAsin = "Arcsinus" +PythonAsinh = "Arcsinus hyperbolicus" +PythonAtan = "Arctangens" +PythonAtan2 = "Geeft atan(y/x)" +PythonAtanh = "Arctangens hyperbolicus" +PythonBin = "Zet integer om in een binair getal" +PythonCeil = "Plafond" +PythonChoice = "Geeft willek. getal van de lijst" +PythonClear = "Lijst leegmaken" +PythonCmathFunction = "cmath module voorvoegsel" +PythonColor = "Definieer een rgb kleur" +PythonComplex = "Geeft a+ib" +PythonCopySign = "Geeft x met het teken van y" +PythonCos = "Cosinus" +PythonCosh = "Cosinus hyperbolicus" +PythonCount = "Tel voorkomen van x" +PythonDegrees = "Zet x om van radialen naar graden" +PythonDivMod = "Quotiënt en rest" +PythonDrawString = "Geef een tekst weer van pixel (x,y)" +PythonErf = "Error functie" +PythonErfc = "Complementaire error functie" +PythonEval = "Geef de geëvalueerde uitdrukking" +PythonExp = "Exponentiële functie" +PythonExpm1 = "Bereken exp(x)-1" +PythonFabs = "Absolute waarde" +PythonFillRect = "Vul een rechthoek bij pixel (x,y)" +PythonFloat = "Zet x om in een float" +PythonFloor = "Vloer" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" -PythonGamma = "Gamma function" -PythonGetPixel = "Return pixel (x,y) color" -PythonGetrandbits = "Integer with k random bits" -PythonHex = "Convert integer to hexadecimal" -PythonImportCmath = "Import cmath module" -PythonImportIon = "Import ion module" -PythonImportKandinsky = "Import kandinsky module" -PythonImportRandom = "Import random module" -PythonImportMath = "Import math module" -PythonImportTime = "Import time module" -PythonImportTurtle = "Import turtle module" -PythonIndex = "Index of the first x occurrence" -PythonInput = "Prompt a value" -PythonInsert = "Insert x at index i in the list" -PythonInt = "Convert x to an integer" -PythonIonFunction = "ion module function prefix" -PythonIsFinite = "Check if x is finite" -PythonIsInfinite = "Check if x is infinity" -PythonIsKeyDown = "Return True if the k key is down" -PythonIsNaN = "Check if x is a NaN" -PythonKandinskyFunction = "kandinsky module function prefix" -PythonKeyLeft = "LEFT ARROW key" -PythonKeyUp = "UP ARROW key" -PythonKeyDown = "DOWN ARROW key" -PythonKeyRight = "RIGHT ARROW key" -PythonKeyOk = "OK key" -PythonKeyBack = "BACK key" -PythonKeyHome = "HOME key" -PythonKeyOnOff = "ON/OFF key" -PythonKeyShift = "SHIFT key" -PythonKeyAlpha = "ALPHA key" -PythonKeyXnt = "X,N,T key" -PythonKeyVar = "VAR key" -PythonKeyToolbox = "TOOLBOX key" -PythonKeyBackspace = "BACKSPACE key" -PythonKeyExp = "EXPONENTIAL key" -PythonKeyLn = "NATURAL LOGARITHM key" -PythonKeyLog = "DECIMAL LOGARITHM key" -PythonKeyImaginary = "IMAGINARY I key" -PythonKeyComma = "COMMA key" -PythonKeyPower = "POWER key" -PythonKeySine = "SINE key" -PythonKeyCosine = "COSINE key" -PythonKeyTangent = "TANGENT key" -PythonKeyPi = "PI key" -PythonKeySqrt = "SQUARE ROOT key" -PythonKeySquare = "SQUARE key" -PythonKeySeven = "7 key" -PythonKeyEight = "8 key" -PythonKeyNine = "9 key" -PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" -PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" -PythonKeyFour = "4 key" -PythonKeyFive = "5 key" -PythonKeySix = "6 key" -PythonKeyMultiplication = "MULTIPLICATION key" -PythonKeyDivision = "DIVISION key" -PythonKeyOne = "1 key" -PythonKeyTwo = "2 key" -PythonKeyThree = "3 key" -PythonKeyPlus = "PLUS key" -PythonKeyMinus = "MINUS key" -PythonKeyZero = "0 key" -PythonKeyDot = "DOT key" -PythonKeyEe = "10 POWER X key" -PythonKeyAns = "ANS key" -PythonKeyExe = "EXE key" -PythonLdexp = "Return x*(2**i), inverse of frexp" -PythonLength = "Length of an object" -PythonLgamma = "Log-gamma function" -PythonLog = "Logarithm to base a" -PythonLog10 = "Logarithm to base 10" -PythonLog2 = "Logarithm to base 2" -PythonMathFunction = "math module function prefix" +PythonFrExp = "Mantisse en exponent van x" +PythonGamma = "Gammafunctie" +PythonGetPixel = "Geef pixel (x,y) kleur (rgb)" +PythonGetrandbits = "Integer met k willekeurige bits" +PythonHex = "Zet integer om in hexadecimaal" +PythonImportCmath = "Importeer cmath module" +PythonImportIon = "Importeer ion module" +PythonImportKandinsky = "Importeer kandinsky module" +PythonImportRandom = "Importeer random module" +PythonImportMath = "Importeer math module" +PythonImportTime = "Importeer time module" +PythonImportTurtle = "Importeer turtle module" +PythonIndex = "Index van de eerste x aanwezigheden" +PythonInput = "Wijs een waarde toe" +PythonInsert = "Voeg x toe aan index i in de lijst" +PythonInt = "Zet x om in een integer" +PythonIonFunction = "ion module voorvoegsel" +PythonIsFinite = "Controleer of x eindig is" +PythonIsInfinite = "Controleer of x oneindig is" +PythonIsKeyDown = "Geef True als k toets omlaag is" +PythonIsNaN = "Controleer of x geen nummer is" +PythonKandinskyFunction = "kandinsky module voorvoegsel" +PythonKeyLeft = "PIJL NAAR LINKS toets" +PythonKeyUp = "PIJL OMHOOG toets" +PythonKeyDown = "PIJL OMLAAG toets" +PythonKeyRight = "PIJL NAAR RECHTS toets" +PythonKeyOk = "OK toets" +PythonKeyBack = "TERUG toets" +PythonKeyHome = "HOME toets" +PythonKeyOnOff = "AAN/UIT toets" +PythonKeyShift = "SHIFT toets" +PythonKeyAlpha = "ALPHA toets" +PythonKeyXnt = "X,N,T toets" +PythonKeyVar = "VAR toets" +PythonKeyToolbox = "TOOLBOX toets" +PythonKeyBackspace = "BACKSPACE toets" +PythonKeyExp = "EXPONENTIEEL toets" +PythonKeyLn = "NATUURLIJKE LOGARITME toets" +PythonKeyLog = "BRIGGSE LOGARITME toets" +PythonKeyImaginary = "IMAGINAIRE I toets" +PythonKeyComma = "KOMMA toets" +PythonKeyPower = "MACHT toets" +PythonKeySine = "SINUS toets" +PythonKeyCosine = "COSINUS toets" +PythonKeyTangent = "TANGENS toets" +PythonKeyPi = "PI toets" +PythonKeySqrt = "VIERKANTSWORTEL toets" +PythonKeySquare = "KWADRAAT toets" +PythonKeySeven = "7 toets" +PythonKeyEight = "8 toets" +PythonKeyNine = "9 toets" +PythonKeyLeftParenthesis = "HAAKJE OPENEN toets" +PythonKeyRightParenthesis = "HAAKJE SLUITEN toets" +PythonKeyFour = "4 toets" +PythonKeyFive = "5 toets" +PythonKeySix = "6 toets" +PythonKeyMultiplication = "VERMENIGVULDIGEN toets" +PythonKeyDivision = "DELEN toets" +PythonKeyOne = "1 toets" +PythonKeyTwo = "2 toets" +PythonKeyThree = "3 toets" +PythonKeyPlus = "PLUS toets" +PythonKeyMinus = "MIN toets" +PythonKeyZero = "0 toets" +PythonKeyDot = "PUNT toets" +PythonKeyEe = "10 TOT DE MACHT X toets" +PythonKeyAns = "ANS toets" +PythonKeyExe = "EXE toets" +PythonLdexp = "Geeft x*(2**i), inversie van frexp" +PythonLength = "Lengte van een object" +PythonLgamma = "Log-gammafunctie" +PythonLog = "Logaritme met grondgetal a" +PythonLog10 = "Logaritme met grondgetal 10" +PythonLog2 = "Logaritme met grondgetal 2" +PythonMathFunction = "math module voorvoegsel" PythonMax = "Maximum" PythonMin = "Minimum" -PythonModf = "Fractional and integer parts of x" -PythonMonotonic = "Value of a monotonic clock" -PythonOct = "Convert integer to octal" -PythonPhase = "Phase of z" -PythonPolar = "z in polar coordinates" -PythonPop = "Remove and return the last item" -PythonPower = "x raised to the power y" +PythonModf = "Fractionele en gehele delen van x" +PythonMonotonic = "Waarde van een monotone klok" +PythonOct = "Integer omzetten naar octaal" +PythonPhase = "Fase van z in radialen" +PythonPolar = "z in poolcoördinaten" +PythonPop = "Verwijder en breng het laatste item terug" +PythonPower = "x tot de macht y" PythonPrint = "Print object" -PythonRadians = "Convert x from degrees to radians" -PythonRandint = "Random integer in [a,b]" -PythonRandom = "Floating point number in [0,1[" -PythonRandomFunction = "random module function prefix" -PythonRandrange = "Random number in range(start, stop)" -PythonRangeStartStop = "List from start to stop-1" -PythonRangeStop = "List from 0 to stop-1" -PythonRect = "z in cartesian coordinates" -PythonRemove = "Remove the first occurrence of x" -PythonReverse = "Reverse the elements of the list" -PythonRound = "Round to n digits" -PythonSeed = "Initialize random number generator" -PythonSetPixel = "Color pixel (x,y)" -PythonSin = "Sine" -PythonSinh = "Hyperbolic sine" -PythonSleep = "Suspend the execution for t seconds" -PythonSort = "Sort the list" -PythonSqrt = "Square root" -PythonSum = "Sum the items of a list" -PythonTan = "Tangent" -PythonTanh = "Hyperbolic tangent" -PythonTimeFunction = "time module function prefix" -PythonTrunc = "x truncated to an integer" -PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" -PythonTurtleCircle = "Circle of radius r pixels" -PythonTurtleColor = "Set the pen color" -PythonTurtleColorMode = "Set the color mode to 1.0 or 255" -PythonTurtleForward = "Move forward by x pixels" -PythonTurtleFunction = "turtle module function prefix" -PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" -PythonTurtleHeading = "Return the current heading" -PythonTurtleHideturtle = "Hide the turtle" -PythonTurtleIsdown = "Return True if the pen is down" -PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" -PythonTurtlePendown = "Pull the pen down" -PythonTurtlePensize = "Set the line thickness to x pixels" -PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" -PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" -PythonTurtleReset = "Reset the drawing" -PythonTurtleRight = "Turn right by a degrees" -PythonTurtleSetheading = "Set the orientation to a degrees" -PythonTurtleSetposition = "Positionne la tortue" -PythonTurtleShowturtle = "Show the turtle" -PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" -PythonUniform = "Floating point number in [a,b]" +PythonRadians = "Zet x om van graden naar radialen" +PythonRandint = "Geeft willek. integer in [a,b]" +PythonRandom = "Een willekeurig getal in [0,1[" +PythonRandomFunction = "random module voorvoegsel" +PythonRandrange = "Willek. getal in range(start, stop)" +PythonRangeStartStop = "Lijst van start tot stop-1" +PythonRangeStop = "Lijst van 0 tot stop-1" +PythonRect = "z in cartesiaanse coördinaten" +PythonRemove = "Verwijder het eerste voorkomen van x" +PythonReverse = "Keer de elementen van de lijst om" +PythonRound = "Rond af op n cijfers" +PythonSeed = "Start willek. getallengenerator" +PythonSetPixel = "Kleur pixel (x,y)" +PythonSin = "Sinus" +PythonSinh = "Sinus hyperbolicus" +PythonSleep = "Stel executie voor t seconden uit" +PythonSort = "Sorteer de lijst" +PythonSqrt = "Vierkantswortel" +PythonSum = "Sommeer de items van een lijst" +PythonTan = "Tangens" +PythonTanh = "Tangens hyperbolicus" +PythonTimeFunction = "time module voorvoegsel" +PythonTrunc = "x afgeknot tot een integer" +PythonTurtleBackward = "Ga achterwaarts met x pixels" +PythonTurtleBlack = "Zwarte kleur" +PythonTurtleBlue = "Blauwe kleur" +PythonTurtleBrown = "Bruine kleur" +PythonTurtleCircle = "Cirkel van straal r pixels" +PythonTurtleColor = "Stel de kleur van de pen in" +PythonTurtleColorMode = "Stel de kleurmodus in op 1.0 of 255" +PythonTurtleForward = "Ga voorwaarts met x pixels" +PythonTurtleFunction = "turtle module voorvoegsel" +PythonTurtleGoto = "Verplaats naar (x,y) coordinaten" +PythonTurtleGreen = "Groene kleur" +PythonTurtleGrey = "Grijze kleur" +PythonTurtleHeading = "Ga terug naar de huidige koers" +PythonTurtleHideturtle = "Verberg de schildpad" +PythonTurtleIsdown = "Geeft True als pen naar beneden is" +PythonTurtleLeft = "Ga linksaf met a graden" +PythonTurtleOrange = "Oranje kleur" +PythonTurtlePendown = "Zet de pen naar beneden" +PythonTurtlePensize = "Stel de lijndikte in op x pixels" +PythonTurtlePenup = "Zet de pen omhoog" +PythonTurtlePink = "Roze kleur" +PythonTurtlePosition = "Zet huidige (x,y) locatie terug" +PythonTurtlePurple = "Paarse kleur" +PythonTurtleRed = "Rode kleur" +PythonTurtleReset = "Reset de tekening" +PythonTurtleRight = "Ga rechtsaf met a graden" +PythonTurtleSetheading = "Zet de oriëntatie op a graden" +PythonTurtleSetposition = "Plaats de schildpad" +PythonTurtleShowturtle = "Laat de schildpad zien" +PythonTurtleSpeed = "Tekensnelheid tussen 0 and 10" +PythonTurtleWhite = "Witte kleur" +PythonTurtleYellow = "Gele kleur" +PythonUniform = "Zwevendekommagetal in [a,b]" diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n index f7ea577db..2434b8174 100644 --- a/apps/settings/base.nl.i18n +++ b/apps/settings/base.nl.i18n @@ -11,7 +11,7 @@ ExamModeActive = "Reactivate exam mode" ToDeactivateExamMode1 = "To deactivate the exam mode," ToDeactivateExamMode2 = "plug the calculator to a computer" ToDeactivateExamMode3 = "or to a power socket." -# --------------------- Please do not edit these messages --------------------- +# --------------------- Please do not edit these messages - Discuss with Leo (remove this later) --------------------- ExamModeWarning1 = "Caution: compliance of this" ExamModeWarning2 = "unofficial software's exam mode" ExamModeWarning3 = "is not guaranteed by NumWorks." From 1426da8c448b96ddbd0c3f68c41ff083b3a9b5fa Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Fri, 13 Mar 2020 11:46:29 +0100 Subject: [PATCH 077/453] [nl] Also python-app --- apps/code/toolbox.nl.i18n | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/toolbox.nl.i18n b/apps/code/toolbox.nl.i18n index 178d42b7b..3fb634129 100644 --- a/apps/code/toolbox.nl.i18n +++ b/apps/code/toolbox.nl.i18n @@ -1,4 +1,4 @@ -Functions = "Functions" -Catalog = "Catalog" +Functions = "Functies" +Catalog = "Catalogus" Modules = "Modules" LoopsAndTests = "Loops and tests" From 07f924bed675a07a1da1634a9c5ff74f47908e45 Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Fri, 13 Mar 2020 18:03:28 +0100 Subject: [PATCH 078/453] [nl] Translation Functions app And other translation In file: epsilon/apps/graph/base.nl.i18n some text would look better if placed slightly to the left. I'm talking about lines 23 and 24: SelectLowerBound and SelectUpperBound --- apps/code/catalog.nl.i18n | 2 +- apps/graph/base.nl.i18n | 60 +++++++++++++++++------------------ apps/home/base.nl.i18n | 8 ++--- apps/on_boarding/base.nl.i18n | 20 ++++++------ apps/probability/base.nl.i18n | 48 ++++++++++++++-------------- apps/regression/base.nl.i18n | 36 ++++++++++----------- apps/sequence/base.nl.i18n | 44 ++++++++++++------------- 7 files changed, 109 insertions(+), 109 deletions(-) diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index 03f10f0f8..739442d0c 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -42,7 +42,7 @@ PythonFillRect = "Vul een rechthoek bij pixel (x,y)" PythonFloat = "Zet x om in een float" PythonFloor = "Vloer" PythonFmod = "a modulo b" -PythonFrExp = "Mantisse en exponent van x" +PythonFrExp = "Mantisse en exponent van x: (m,e)" PythonGamma = "Gammafunctie" PythonGetPixel = "Geef pixel (x,y) kleur (rgb)" PythonGetrandbits = "Integer met k willekeurige bits" diff --git a/apps/graph/base.nl.i18n b/apps/graph/base.nl.i18n index c65a3370e..a1b24f965 100644 --- a/apps/graph/base.nl.i18n +++ b/apps/graph/base.nl.i18n @@ -1,33 +1,33 @@ -FunctionApp = "Functions" -FunctionAppCapital = "FUNCTIONS" -FunctionTab = "Functions" -AddFunction = "Add function" -DeleteFunction = "Delete function" -CurveType = "Curve type" -CartesianType = "Cartesian " -PolarType = "Polar " -ParametricType = "Parametric " +FunctionApp = "Functies" +FunctionAppCapital = "FUNCTIES" +FunctionTab = "Functies" +AddFunction = "Functie toevoegen" +DeleteFunction = "Functie verwijderen" +CurveType = "Kromme type" +CartesianType = "Cartesiaans " +PolarType = "Polair " +ParametricType = "Parametrisch " IntervalT = "t interval" IntervalTheta = "θ interval" IntervalX = "x interval" -FunctionDomain = "Plot range" -FunctionColor = "Function color" -NoFunction = "No function" -NoActivatedFunction = "No function is turned on" -PlotOptions = "Plot options" -Compute = "Calculate" -Zeros = "Zeros" -Tangent = "Tangent" -Intersection = "Intersection" -Preimage = "Inverse image" -SelectLowerBound = "Select lower bound" -SelectUpperBound = "Select upper bound" -NoMaximumFound = "No maximum found" -NoMinimumFound = "No minimum found" -NoZeroFound = "No zero found" -NoIntersectionFound = "No intersection found" -NoPreimageFound = "No inverse image found" -DerivativeFunctionColumn = "Derivative function column" -HideDerivativeColumn = "Hide the derivative function" -AllowedCharactersAZaz09 = "Allowed characters: A-Z, a-z, 0-9, _" -ReservedName = "Reserved name" +FunctionDomain = "Plotbereik" +FunctionColor = "Functiekleur" +NoFunction = "Geen functie" +NoActivatedFunction = "Geen functie is ingeschakelt" +PlotOptions = "Plot opties" +Compute = "Bereken" +Zeros = "Nulpunten" +Tangent = "Tangens" +Intersection = "Snijpunt" +Preimage = "Inverse beeld" +SelectLowerBound = "Selecteer ondergrens" +SelectUpperBound = "Selecteer bovengrens" +NoMaximumFound = "Geen maximum gevonden" +NoMinimumFound = "Geen minimum gevonden" +NoZeroFound = "Geen nulpunt gevonden" +NoIntersectionFound = "Geen snijpunt gevonden" +NoPreimageFound = "Geen inverse beeld gevonden" +DerivativeFunctionColumn = "Afgeleide functie kolom" +HideDerivativeColumn = "Verberg de afgeleide functie" +AllowedCharactersAZaz09 = "Toegestane tekens: A-Z, a-z, 0-9, _" +ReservedName = "Voorbehouden naam" diff --git a/apps/home/base.nl.i18n b/apps/home/base.nl.i18n index 158fa3bda..94900c4b1 100644 --- a/apps/home/base.nl.i18n +++ b/apps/home/base.nl.i18n @@ -1,4 +1,4 @@ -Apps = "Applications" -AppsCapital = "APPLICATIONS" -ForbidenAppInExamMode1 = "This application is" -ForbidenAppInExamMode2 = "forbidden in exam mode" +Apps = "Applicaties" +AppsCapital = "APPLICATIES" +ForbidenAppInExamMode1 = "Deze applicatie is" +ForbidenAppInExamMode2 = "uitgesloten in examenstand" diff --git a/apps/on_boarding/base.nl.i18n b/apps/on_boarding/base.nl.i18n index b923a3291..ebd089a7d 100644 --- a/apps/on_boarding/base.nl.i18n +++ b/apps/on_boarding/base.nl.i18n @@ -1,13 +1,13 @@ -UpdateAvailable = "UPDATE AVAILABLE" -UpdateMessage1 = "There are important upgrades" -UpdateMessage2 = "for your calculator." -UpdateMessage3 = "Browse our page from your computer" +UpdateAvailable = "UPDATE BESCHIKBAAR" +UpdateMessage1 = "Er zijn belangrijke updates" +UpdateMessage2 = "voor je rekenmachine." +UpdateMessage3 = "Ga vanaf je computer naar onze pagina" UpdateMessage4 = "www.numworks.com/update" -BetaVersion = "BETA VERSION" +BetaVersion = "BÈTAVERSIE" BetaVersionMessage1 = "" -BetaVersionMessage2 = "Your device runs a beta software." -BetaVersionMessage3 = "You might run into bugs or glitches." +BetaVersionMessage2 = "Je apparaat draait op een bèta-software." +BetaVersionMessage3 = "Je komt mogelijk bugs of glitches tegen." BetaVersionMessage4 = "" -BetaVersionMessage5 = "Please send any feedback to" -BetaVersionMessage6 = "contact@numworks.com" -Skip = "Skip" +BetaVersionMessage5 = "Eventuele feedback kun je sturen naar" +BetaVersionMessage6 = "contact@numworks.nl" +Skip = "Verdergaan" diff --git a/apps/probability/base.nl.i18n b/apps/probability/base.nl.i18n index c05cf05bb..07ace7455 100644 --- a/apps/probability/base.nl.i18n +++ b/apps/probability/base.nl.i18n @@ -1,27 +1,27 @@ -ProbaApp = "Probability" -ProbaAppCapital = "PROBABILITY" -ChooseDistribution = "Choose the distribution" -Binomial = "Binomial" -Geometric = "Geometric" +ProbaApp = "Kansrekenen" +ProbaAppCapital = "KANSREKENEN" +ChooseDistribution = "Kies de kansverdeling" +Binomial = "Binomiaal" +Geometric = "Geometrisch" Uniforme = "Uniform" -Normal = "Normal" -ChiSquared = "Chi-squared" -UniformDistribution = "Uniform distribution" -ExponentialDistribution = "Exponential distribution" -GeometricDistribution = "Geometric distribution" -PoissonDistribution = "Poisson distribution" -ChiSquaredDistribution = "Chi-squared distribution" -StudentDistribution = "Student's distribution" -FisherDistribution = "F distribution" -ChooseParameters = "Choose parameters" -RepetitionNumber = "n: Number of trials" -SuccessProbability = "p: Success probability" +Normal = "Normaal" +ChiSquared = "Chi-kwadraat" +UniformDistribution = "Uniforme verdeling" +ExponentialDistribution = "Exponentiële verdeling" +GeometricDistribution = "Geometrische verdeling" +PoissonDistribution = "Poissonverdeling" +ChiSquaredDistribution = "Chi-kwadraatverdeling" +StudentDistribution = "Studentverdeling" +FisherDistribution = "F-verdeling" +ChooseParameters = "Bepaal de parameters" +RepetitionNumber = "n: Aantal proeven" +SuccessProbability = "p: Kans op succes" IntervalDefinition = "[a,b]: Interval" -LambdaExponentialDefinition = "λ: Rate parameter" -MeanDefinition = "μ: Mean" -DeviationDefinition = "σ: Standard deviation" +LambdaExponentialDefinition = "λ: Snelheidsparameter" +MeanDefinition = "μ: Gemiddelde" +DeviationDefinition = "σ: Standaardafwijking" LambdaPoissonDefinition = "λ: Parameter" -DegreesOfFreedomDefinition = "k: Degrees of freedom" -D1FisherDefinition = "d1: Degrees of freedom of the numerator" -D2FisherDefinition = "d2: Degrees of freedom of the denominator" -ComputeProbability = "Calculate probabilities" +DegreesOfFreedomDefinition = "k: Vrijheidsgraden" +D1FisherDefinition = "d1: Vrijheidsgraden in de teller" +D2FisherDefinition = "d2: Vrijheidsgraden in de noemer" +ComputeProbability = "Bereken kansen" diff --git a/apps/regression/base.nl.i18n b/apps/regression/base.nl.i18n index fc6f307f2..f5411a0a0 100644 --- a/apps/regression/base.nl.i18n +++ b/apps/regression/base.nl.i18n @@ -1,21 +1,21 @@ -RegressionApp = "Regression" -RegressionAppCapital = "REGRESSION" -Regression = "Regression" +RegressionApp = "Regressie" +RegressionAppCapital = "REGRESSIE" +Regression = "Regressie" Reg = "reg" -MeanDot = "mean" -RegressionCurve = "Regression curve" -XPrediction = "Prediction given X" -YPrediction = "Prediction given Y" -ValueNotReachedByRegression = "Value not reached in this window" -NumberOfDots = "Number of points" -Covariance = "Covariance" -Linear = "Linear" +MeanDot = "gemiddelde" +RegressionCurve = "Regressielijn" +XPrediction = "Voorspelling gegeven X" +YPrediction = "Voorspelling gegeven Y" +ValueNotReachedByRegression = "Waarde niet gevonden in dit venster" +NumberOfDots = "Aantal punten" +Covariance = "Covariantie" +Linear = "Lineair" Proportional = "Proportioneel" -Quadratic = "Quadratic" -Cubic = "Cubic" +Quadratic = "Kwadratisch" +Cubic = "Kubiek" Quartic = "Quartic" -Logarithmic = "Logarithmic" -Power = "Power" -Trigonometrical = "Trigonometric" -Logistic = "Logistic" -DataNotSuitableForRegression = " Data not suitable for this regression model" +Logarithmic = "Logaritmisch" +Power = "Macht" +Trigonometrical = "Trigonometrisch" +Logistic = "Logistiek" +DataNotSuitableForRegression = " Data niet geschikt voor dit regressiemodel" diff --git a/apps/sequence/base.nl.i18n b/apps/sequence/base.nl.i18n index e9917698c..f1a8c74e1 100644 --- a/apps/sequence/base.nl.i18n +++ b/apps/sequence/base.nl.i18n @@ -1,22 +1,22 @@ -SequenceApp = "Sequences" -SequenceAppCapital = "SEQUENCES" -SequenceTab = "Sequences" -AddSequence = "Add sequence" -ChooseSequenceType = "Choose sequence type" -SequenceType = "Sequence type" -Explicit = "Explicit expression" -SingleRecurrence = "Recursive first order" -DoubleRecurrence = "Recursive second order" -SequenceOptions = "Sequence options" -SequenceColor = "Sequence color" -DeleteSequence = "Delete sequence" -NoSequence = "No sequence" -NoActivatedSequence = "No sequence is turned on" -NStart = "N start" -NEnd = "N end" -TermSum = "Sum of terms" -SelectFirstTerm = "Select First Term " -SelectLastTerm = "Select last term " -ValueNotReachedBySequence = "Value not reached by sequence" -NColumn = "n column" -FirstTermIndex = "First term index" +SequenceApp = "Rijen" +SequenceAppCapital = "RIJEN" +SequenceTab = "Rijen" +AddSequence = "Rij toevoegen" +ChooseSequenceType = "Kies type rij" +SequenceType = "Rij-type" +Explicit = "Expliciete uitdrukking" +SingleRecurrence = "Recursief eerste orde" +DoubleRecurrence = "Recursief tweede orde" +SequenceOptions = "Rij-opties" +SequenceColor = "Rij-kleur" +DeleteSequence = "Rij verwijderen" +NoSequence = "Geen rij gegeven" +NoActivatedSequence = "Geen rij is ingeschakelt" +NStart = "N begin" +NEnd = "N einde" +TermSum = "Som van termen" +SelectFirstTerm = "Selecteer eerste term " +SelectLastTerm = "Selecteer laatste term " +ValueNotReachedBySequence = "Waarde niet bereikt door de rij" +NColumn = "n-kolom" +FirstTermIndex = "Eerste termindex" From 7f561b0a3ddaaaaafd8f3f1abb5d5c719c2a6dff Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Wed, 25 Mar 2020 18:15:44 +0100 Subject: [PATCH 079/453] [nl] Update translation Epsilon --- apps/settings/base.nl.i18n | 60 ++++++++-------- apps/solver/base.nl.i18n | 58 ++++++++-------- apps/statistics/base.nl.i18n | 42 ++++++------ apps/toolbox.nl.i18n | 128 +++++++++++++++++------------------ apps/usb/base.nl.i18n | 12 ++-- 5 files changed, 150 insertions(+), 150 deletions(-) diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n index 2434b8174..83c87ad3c 100644 --- a/apps/settings/base.nl.i18n +++ b/apps/settings/base.nl.i18n @@ -1,16 +1,16 @@ -SettingsApp = "Settings" -SettingsAppCapital = "SETTINGS" -AngleUnit = "Angle measure" -DisplayMode = "Result format" -EditionMode = "Writing format" -EditionLinear = "Linear " -Edition2D = "Natural " -ComplexFormat = "Complex format" -ExamMode = "Exam mode" -ExamModeActive = "Reactivate exam mode" -ToDeactivateExamMode1 = "To deactivate the exam mode," -ToDeactivateExamMode2 = "plug the calculator to a computer" -ToDeactivateExamMode3 = "or to a power socket." +SettingsApp = "Instellingen" +SettingsAppCapital = "INSTELLINGEN" +AngleUnit = "Hoekmaat" +DisplayMode = "Resultaat formaat" +EditionMode = "Schrijfformaat" +EditionLinear = "Lineair " +Edition2D = "Natuurlijk" +ComplexFormat = "Complex formaat" +ExamMode = "Examenstand" +ExamModeActive = "Herstart examenstand" +ToDeactivateExamMode1 = "Om de examenstand te verlaten," +ToDeactivateExamMode2 = "sluit de rekenmachine aan op een computer" +ToDeactivateExamMode3 = "of op een stopcontact." # --------------------- Please do not edit these messages - Discuss with Leo (remove this later) --------------------- ExamModeWarning1 = "Caution: compliance of this" ExamModeWarning2 = "unofficial software's exam mode" @@ -20,22 +20,22 @@ AboutWarning2 = "unofficial software version." AboutWarning3 = "NumWorks can't be held responsible" AboutWarning4 = "for any resulting damage." # ----------------------------------------------------------------------------- -About = "About" -Degrees = "Degrees " -Gradians = "Gradians " -Radian = "Radians " -Decimal = "Decimal " -Scientific = "Scientific " +About = "Over deze rekenmachine" +Degrees = "Graden " +Gradians = "Decimale graden " +Radian = "Radialen " +Decimal = "Decimaal " +Scientific = "Wetenschappelijk " Engineering = "Engineering " -SignificantFigures = "Significant figures " -Real = "Real " -Cartesian = "Cartesian " -Polar = "Polar " -Brightness = "Brightness" -FontSizes = "Python font size" -LargeFont = "Large " -SmallFont = "Small " -SoftwareVersion = "Software version" -SerialNumber = "Serial number" +SignificantFigures = "Significante cijfers " +Real = "Reëel " +Cartesian = "Cartesisch " +Polar = "Polair " +Brightness = "Helderheid" +FontSizes = "Python lettergrootte" +LargeFont = "Groot " +SmallFont = "Klein " +SoftwareVersion = "Softwareversie" +SerialNumber = "Serienummer" UpdatePopUp = "Update pop-up" -BetaPopUp = "Beta pop-up" +BetaPopUp = "Bèta pop-up" diff --git a/apps/solver/base.nl.i18n b/apps/solver/base.nl.i18n index 017cad04d..949aa9762 100644 --- a/apps/solver/base.nl.i18n +++ b/apps/solver/base.nl.i18n @@ -1,29 +1,29 @@ -SolverApp = "Equations" -SolverAppCapital = "EQUATIONS" -AddEquation = "Add equation" -ResolveEquation = "Solve the equation" -ResolveSystem = "Solve the system" -UseEquationModel = "Use an equation template" -RequireEquation = "The input must be an equation" -UnrealEquation = "Unreal equation" -UndefinedEquation = "Undefined equation" -TooManyVariables = "There are too many unknowns" -NonLinearSystem = "The system is not linear" -Solution = "Solution" -ApproximateSolution = "Approximate solution" -SearchInverval = "Search interval" -NoSolutionSystem = "The system has no solution" -NoSolutionEquation = "The equation has no solution" -NoSolutionInterval = "No solution found in the interval" -EnterEquation = "Enter an equation" -InfiniteNumberOfSolutions = "There are an infinite number of solutions" -ApproximateSolutionIntervalInstruction0= "Enter the interval to search" -ApproximateSolutionIntervalInstruction1= "for an approximate solution" -OnlyFirstSolutionsDisplayed0 = "Only the first 10 solutions" -OnlyFirstSolutionsDisplayed1 = "are displayed" -PolynomeHasNoRealSolution0 = "The polynomial has no" -PolynomeHasNoRealSolution1 = "real root" -PredefinedVariablesUsedLeft = "Used " -PredefinedVariablesUsedRight = "predefined variables" -PredefinedVariablesIgnoredLeft = "Ignored" -PredefinedVariablesIgnoredRight = " predefined variables" +SolverApp = "Vergelijkingen" +SolverAppCapital = "VERGELIJKINGEN" +AddEquation = "Vergelijking toevoegen" +ResolveEquation = "Vergelijking oplossen" +ResolveSystem = "Stelsel oplossen" +UseEquationModel = "Gebruik een vergelijkingstemplate" +RequireEquation = "De invoer moet een vergelijking zijn" +UnrealEquation = "Vergelijking is niet reëel" +UndefinedEquation = "Ongedefinieerde vergelijking" +TooManyVariables = "Er zijn te veel onbekenden" +NonLinearSystem = "Het stelsel is niet lineair" +Solution = "Oplossing" +ApproximateSolution = "Benaderende oplossing" +SearchInverval = "Zoekinterval" +NoSolutionSystem = "Het stelsel heeft geen oplossing" +NoSolutionEquation = "De vergelijking heeft geen oplossing" +NoSolutionInterval = "Geen oplossing gevonden binnen het interval" +EnterEquation = "Voer een vergelijking in" +InfiniteNumberOfSolutions = "Er is een oneindig aantal oplossingen" +ApproximateSolutionIntervalInstruction0= "Voer het interval in om in te zoeken" +ApproximateSolutionIntervalInstruction1= "naar een benaderende oplossing" +OnlyFirstSolutionsDisplayed0 = "Alleen de eerste tien oplossingen" +OnlyFirstSolutionsDisplayed1 = "worden weergegeven" +PolynomeHasNoRealSolution0 = "De polynoom heeft geen" +PolynomeHasNoRealSolution1 = "reële wortel" +PredefinedVariablesUsedLeft = "Gebruikte " +PredefinedVariablesUsedRight = "opgeslagen variabelen" +PredefinedVariablesIgnoredLeft = "Genegeerde" +PredefinedVariablesIgnoredRight = " opgeslagen variabelen" diff --git a/apps/statistics/base.nl.i18n b/apps/statistics/base.nl.i18n index 61091e835..c66afa64c 100644 --- a/apps/statistics/base.nl.i18n +++ b/apps/statistics/base.nl.i18n @@ -1,25 +1,25 @@ -StatsApp = "Statistics" -StatsAppCapital = "STATISTICS" +StatsApp = "Statistiek" +StatsAppCapital = "STATISTIEK" HistogramTab = "Histogram" BoxTab = "Box" -Values1 = "Values V1" -Values2 = "Values V2" -Values3 = "Values V3" -Sizes1 = "Sizes N1" -Sizes2 = "Sizes N2" -Sizes3 = "Sizes N3" -ImportList = "Import from a list" +Values1 = "Waarden V1" +Values2 = "Waarden V2" +Values3 = "Waarden V3" +Sizes1 = "Frequenties N1" +Sizes2 = "Frequenties N2" +Sizes3 = "Frequenties N3" +ImportList = "Importeren uit een lijst" Interval = " Interval " -Size = " Size" -Frequency = "Frequency" -HistogramSet = "Histogram settings" -RectangleWidth = "Bin width" +Size = " Frequentie" +Frequency = "Proportie" +HistogramSet = "Histogram instellingen" +RectangleWidth = "Kolombreedte" BarStart = "X start" -FirstQuartile = "First quartile" -Median = "Median" -ThirdQuartile = "Third quartile" -TotalSize = "Total size" -Range = "Range" -StandardDeviationSigma = "Standard deviation σ" -SampleStandardDeviationS = "Sample std deviation s" -InterquartileRange = "Interquartile range" +FirstQuartile = "Eerste kwartiel" +Median = "Mediaan" +ThirdQuartile = "Derde kwartiel" +TotalSize = "Totale omvang" +Range = "Bereik" +StandardDeviationSigma = "Standaardafwijking σ" +SampleStandardDeviationS = "Steekprf stand.afwijk. s" +InterquartileRange = "Interkwartielafstand" diff --git a/apps/toolbox.nl.i18n b/apps/toolbox.nl.i18n index c80a6038c..6ea333b61 100644 --- a/apps/toolbox.nl.i18n +++ b/apps/toolbox.nl.i18n @@ -1,17 +1,17 @@ -Unit = "Units" -UnitTimeMenu = "Time" -UnitTimeSecondMenu = "Second" -UnitTimeSecond = "Second" -UnitTimeSecondMilli = "Millisecond" -UnitTimeSecondMicro = "Microsecond" -UnitTimeSecondNano = "Nanosecond" -UnitTimeMinute = "Minute" -UnitTimeHour = "Hour" -UnitTimeDay = "Day" +Unit = "Eenheden" +UnitTimeMenu = "Tijd" +UnitTimeSecondMenu = "Seconde" +UnitTimeSecond = "Seconde" +UnitTimeSecondMilli = "MilliSeconde" +UnitTimeSecondMicro = "Microseconde" +UnitTimeSecondNano = "Nanoseconde" +UnitTimeMinute = "Minuut" +UnitTimeHour = "Uur" +UnitTimeDay = "Dag" UnitTimeWeek = "Week" -UnitTimeMonth = "Month" -UnitTimeYear = "Year" -UnitDistanceMenu = "Distance" +UnitTimeMonth = "Maand" +UnitTimeYear = "Jaar" +UnitDistanceMenu = "Afstand" UnitDistanceMeterMenu = "Meter" UnitDistanceMeterKilo = "Kilometer" UnitDistanceMeter = "Meter" @@ -19,81 +19,81 @@ UnitDistanceMeterMilli = "Millimeter" UnitDistanceMeterMicro = "Micrometer" UnitDistanceMeterNano = "Nanometer" UnitDistanceMeterPico = "Picometer" -UnitDistanceAstronomicalUnit = "Astronomical unit" -UnitDistanceLightYear = "Light year" +UnitDistanceAstronomicalUnit = "Astronomische eenheid" +UnitDistanceLightYear = "Lichtjaar" UnitDistanceParsec = "Parsec" -UnitMassMenu = "Mass" +UnitMassMenu = "Massa" UnitMassGramKilo = "Kilogram" UnitMassGram = "Gram" UnitMassGramMilli = "Milligram" UnitMassGramMicro = "Microgram" UnitMassGramNano = "Nanogram" -UnitMassTonne = "Tonne" -UnitCurrentMenu = "Electric current" -UnitCurrentAmpere = "Ampere" -UnitCurrentAmpereMilli = "Milliampere" -UnitCurrentAmpereMicro = "Microampere" -UnitTemperatureMenu = "Temperature" +UnitMassTonne = "Ton" +UnitCurrentMenu = "Elektrische stroom" +UnitCurrentAmpere = "Ampère" +UnitCurrentAmpereMilli = "Milliampère" +UnitCurrentAmpereMicro = "Microampère" +UnitTemperatureMenu = "Temperatuur" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "Amount of substance" -UnitAmountMole = "Mole" -UnitAmountMoleMilli = "Millimole" -UnitAmountMoleMicro = "Micromole" -UnitLuminousIntensityMenu = "Luminous intensity" +UnitAmountMenu = "hoeveelheid stof" +UnitAmountMole = "Mol" +UnitAmountMoleMilli = "Millimol" +UnitAmountMoleMicro = "Micromol" +UnitLuminousIntensityMenu = "Lichtsterkte" UnitLuminousIntensityCandela = "Candela" -UnitFrequencyMenu = "Frequency" +UnitFrequencyMenu = "Frequentie" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" UnitFrequencyHertz = "Hertz" -UnitForceMenu = "Force" +UnitForceMenu = "Kracht" UnitForceNewtonKilo = "Kilonewton" UnitForceNewton = "Newton" UnitForceNewtonMilli = "Millinewton" -UnitPressureMenu = "Pressure" +UnitPressureMenu = "Druk" UnitPressurePascal = "Pascal" UnitPressurePascalHecto = "Hectopascal" UnitPressureBar = "Bar" -UnitPressureAtm = "Atmosphere" -UnitEnergyMenu = "Energy" +UnitPressureAtm = "Atmosfeer" +UnitEnergyMenu = "Energie" UnitEnergyJouleMenu = "Joule" UnitEnergyJouleKilo = "Kilojoule" UnitEnergyJoule = "Joule" UnitEnergyJouleMilli = "Millijoule" -UnitEnergyEletronVoltMenu = "Electronvolt" -UnitEnergyElectronVoltMega = "Megaelectronvolt" -UnitEnergyElectronVoltKilo = "Kiloelectronvolt" -UnitEnergyElectronVolt = "Electronvolt" -UnitEnergyElectronVoltMilli = "Millielectronvolt" -UnitPowerMenu = "Power" +UnitEnergyEletronVoltMenu = "Elektronvolt" +UnitEnergyElectronVoltMega = "Megaelektronvolt" +UnitEnergyElectronVoltKilo = "Kiloelektronvolt" +UnitEnergyElectronVolt = "Elektronvolt" +UnitEnergyElectronVoltMilli = "Millielektronvolt" +UnitPowerMenu = "Vermogen" UnitPowerWattGiga = "Gigawatt" UnitPowerWattMega = "Megawatt" UnitPowerWattKilo = "Kilowatt" UnitPowerWatt = "Watt" UnitPowerWattMilli = "Milliwatt" UnitPowerWattMicro = "Microwatt" -UnitElectricChargeMenu = "Electric charge" +UnitElectricChargeMenu = "Elektrische lading" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "Electric potential" +UnitPotentialMenu = "elektrisch potentiaal" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" UnitPotentialVoltMilli = "Millivolt" UnitPotentialVoltMicro = "Microvolt" -UnitCapacitanceMenu = "Electrical capacitance" +UnitCapacitanceMenu = "Elektrische capaciteit" UnitCapacitanceFarad = "Farad" UnitCapacitanceFaradMilli = "Millifarad" UnitCapacitanceFaradMicro = "Microfarad" -UnitResistanceMenu = "Electrical resistance" +UnitResistanceMenu = "Elektrische weerstand" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "Electrical conductance" +UnitConductanceMenu = "elektrische geleidbaarheid" UnitConductanceSiemens = "Siemens" UnitConductanceSiemensMilli = "Millisiemens" -UnitMagneticFieldMenu = "Magnetic field" +UnitMagneticFieldMenu = "Magnetisch veld" UnitMagneticFieldTesla = "Tesla" -InductanceMenu = "Electrical inductance" +InductanceMenu = "Zelfinductie" UnitInductanceHenry = "Henry" -UnitSurfaceMenu = "Area" +UnitSurfaceMenu = "Oppervlakte" UnitSurfaceHectar = "Hectare" UnitVolumeMenu = "Volume" UnitVolumeLiter = "Liter" @@ -101,27 +101,27 @@ UnitVolumeLiterDeci = "Deciliter" UnitVolumeLiterCenti = "Centiliter" UnitVolumeLiterMilli = "Milliliter" Toolbox = "Toolbox" -AbsoluteValue = "Absolute value" -NthRoot = "nth-root" -BasedLogarithm = "Logarithm to base a" -Calculation = "Calculation" -ComplexNumber = "Complex numbers" -Combinatorics = "Combinatorics" -Arithmetic = "Arithmetic" +AbsoluteValue = "Absolute waarde" +NthRoot = "n-de-machtswortel" +BasedLogarithm = "Logaritme met grondtal a" +Calculation = "Calculatie" +ComplexNumber = "Complexe getallen" +Combinatorics = "Combinatoriek" +Arithmetic = "rekenkunde" Matrices = "Matrix" -NewMatrix = "New matrix" -Identity = "Identity matrix of size n" -Lists = "List" -HyperbolicTrigonometry = "Hyperbolic trigonometry" -Fluctuation = "Prediction Interval" -DerivateNumber = "Derivative" -Integral = "Integral" -Sum = "Sum" +NewMatrix = "Nieuw matrix" +Identity = "Eenheidsmatrix van formaat n" +Lists = "Lijst" +HyperbolicTrigonometry = "Hyperbolische meetkunde" +Fluctuation = "Voorspellingsinterval" +DerivateNumber = "Afgeleide" +Integral = "Integraal" +Sum = "Som" Product = "Product" -ComplexAbsoluteValue = "Absolute value" +ComplexAbsoluteValue = "Absolute waarde" Agument = "Argument" -RealPart = "Real part" -ImaginaryPart = "Imaginary part" +RealPart = "Reëel deel" +ImaginaryPart = "Imaginair deel" Conjugate = "Conjugate" Combination = "Combination" Permutation = "Permutation" diff --git a/apps/usb/base.nl.i18n b/apps/usb/base.nl.i18n index 60eae2214..35829bbdd 100644 --- a/apps/usb/base.nl.i18n +++ b/apps/usb/base.nl.i18n @@ -1,7 +1,7 @@ -USBConnected = "THE CALCULATOR IS CONNECTED" -ConnectedMessage1 = "To transfer data, browse" -ConnectedMessage2 = "our page from your computer" +USBConnected = "DE REKENMACHINE IS AANGESLOTEN" +ConnectedMessage1 = "Om gegevens op te slaan, " +ConnectedMessage2 = "ga naar onze webpagina" ConnectedMessage3 = "workshop.numworks.com" -ConnectedMessage4 = "Press the BACK key of your" -ConnectedMessage5 = "calculator or unplug it to" -ConnectedMessage6 = "disconnect it." +ConnectedMessage4 = "Druk op de TERUG toets van je" +ConnectedMessage5 = "rekenmachine of haal de kabel er " +ConnectedMessage6 = "uit om hem los te koppelen." From 08fe49526c9a9e7d7e8392999565ed3ca749a293 Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Thu, 26 Mar 2020 14:48:18 +0100 Subject: [PATCH 080/453] [nl] Epsilon translation update --- apps/shared.nl.i18n | 146 ++++++++++++++++++++--------------------- apps/toolbox.nl.i18n | 82 +++++++++++------------ apps/variables.nl.i18n | 18 ++--- 3 files changed, 123 insertions(+), 123 deletions(-) diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index 761eabbb9..dea008727 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -1,81 +1,81 @@ -ActivateDeactivate = "Turn on/off" -ActivateExamMode = "Activate exam mode" -ActivateDutchExamMode = "Activate Dutch exam mode" -ActiveExamModeMessage1 = "All your data will be " -ActiveExamModeMessage2 = "deleted when you activate " -ActiveExamModeMessage3 = "the exam mode." -ActiveDutchExamModeMessage1 = "All your data will be deleted when" -ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" -ActiveDutchExamModeMessage3 = "application will be unavailable." -Axis = "Axes" -Cancel = "Cancel" -ClearColumn = "Clear column" -ColumnOptions = "Column options" -CopyColumnInList = "Export the column to a list" -DataNotSuitable = "Data not suitable" -DataTab = "Data" -DefaultSetting = "Basic settings" +ActivateDeactivate = "Zet aan/uit" +ActivateExamMode = "Examenstand activeren" +ActivateDutchExamMode = "Nederlandse examenstand activeren" +ActiveExamModeMessage1 = "Al je gegevens worden " +ActiveExamModeMessage2 = "gewist wanneer je de " +ActiveExamModeMessage3 = "examenstand activeert." +ActiveDutchExamModeMessage1 = "Al je gegevens worden gewist wanneer" +ActiveDutchExamModeMessage2 = "je de examenstand activeert. De Python" +ActiveDutchExamModeMessage3 = "applicatie wordt uitgeschakelt." +Axis = "Assen" +Cancel = "Annuleer" +ClearColumn = "Wis kolom" +ColumnOptions = "Kolomopties" +CopyColumnInList = "Exporteer de kolom naar een lijst" +DataNotSuitable = "Gegevens niet geschikt" +DataTab = "Gegevens" +DefaultSetting = "standaardinstellingen" Deg = "deg" -Deviation = "Variance" -DisplayValues = "Display values" -Empty = "Empty" +Deviation = "Variantie" +DisplayValues = "Geef waarden weer" +Empty = "Leeg" Eng = "eng" -ExitExamMode1 = "Exit the exam " -ExitExamMode2 = "mode?" -Exponential = "Exponential" -FillWithFormula = "Fill with a formula" -ForbiddenValue = "Forbidden value" -FunctionColumn = "0(0) column" -FunctionOptions = "Function options" -Goto = "Go to" -GraphTab = "Graph" -HardwareTestLaunch1 = "You are starting the hardware" -HardwareTestLaunch2 = " test. At the end of the test, you" -HardwareTestLaunch3 = "will have to reset the device and" -HardwareTestLaunch4 = "all your data will be deleted." -Initialization = "Preadjustment" -IntervalSet = "Set the interval" -Language = "Language" -LowBattery = "Low battery" -Mean = "Mean" -Move = " Move: " -NameCannotStartWithNumber = "A name cannot start with a number" -NameTaken = "This name has already been taken" -NameTooLong = "This name is too long" -Next = "Next" -NoDataToPlot = "No data to draw" -NoFunctionToDelete = "No function to delete" -NoValueToCompute = "No values to calculate" -NEnd = "N end" -NStart = "N start" -Ok = "Confirm" -Or = " or " -Orthonormal = "Orthonormal" -Plot = "Plot graph" -PoolMemoryFull1 = "The working memory is full." -PoolMemoryFull2 = "Try again." +ExitExamMode1 = "Verlaat de " +ExitExamMode2 = "examenstand?" +Exponential = "Exponentieel" +FillWithFormula = "Vul met een formule" +ForbiddenValue = "Verboden waarde" +FunctionColumn = "0(0) kolom" +FunctionOptions = "Functie-opties" +Goto = "Ga naar" +GraphTab = "Grafiek" +HardwareTestLaunch1 = "Je start de hardware test. " +HardwareTestLaunch2 = "Aan het eind van de test moet " +HardwareTestLaunch3 = "je de rekenmachine resetten en " +HardwareTestLaunch4 = "worden al je gegevens verwijderd." +Initialization = "Voorgedefinieerd" +IntervalSet = "Stel het interval in" +Language = "Taal" +LowBattery = "Batterij bijna leeg" +Mean = "Gemiddelde" +Move = " Verplaats: " +NameCannotStartWithNumber = "Een naam kan niet beginnen met een nummer" +NameTaken = "Deze naam is al in gebruik" +NameTooLong = "Deze naam is te lang" +Next = "Volgende" +NoDataToPlot = "Geen gegevens om te tekenen" +NoFunctionToDelete = "Geen functie om te verwijderen" +NoValueToCompute = "Geen waarden om te berekenen" +NEnd = "N einde" +NStart = "N begin" +Ok = "Bevestig" +Or = " of " +Orthonormal = "Orthonormaal" +Plot = "Grafiek plotten" +PoolMemoryFull1 = "Het werkgeheugen is vol." +PoolMemoryFull2 = "Opnieuw proberen." Rad = "rad" -Rename = "Rename" -RoundAbscissa = "Integer" +Rename = "Hernoem" +RoundAbscissa = "Geheel getal" Sci = "sci" -SquareSum = "Sum of squares" -StandardDeviation = "Standard deviation" -StoreExpressionNotAllowed = "'store' is not allowed" +SquareSum = "Som van kwadraten" +StandardDeviation = "Standaardafwijking" +StoreExpressionNotAllowed = "'opslaan' is niet toegestaan" StatTab = "Stats" -Step = "Step" -StorageMemoryFull1 = "The memory is full." -StorageMemoryFull2 = "Erase data and try again." +Step = "Stap" +StorageMemoryFull1 = "Het geheugen is vol." +StorageMemoryFull2 = "Wis de gegevens en probeer opnieuw." SyntaxError = "Syntax error" -TEnd = "T end" -ThetaEnd = "θ end" -ThetaStart = "θ start" -TStart = "T start" +TEnd = "T einde" +ThetaEnd = "θ einde" +ThetaStart = "θ begin" +TStart = "T begin" ToZoom = "Zoom: " -Trigonometric = "Trigonometrical" -UndefinedValue = "Undefined value" -ValueNotReachedByFunction = "Value not reached by function" -ValuesTab = "Table" -Warning = "Warning" -XEnd = "X end" -XStart = "X start" +Trigonometric = "Goniometrische" +UndefinedValue = "Ongedefinieerde waarde" +ValueNotReachedByFunction = "Waarde niet bereikt door functie" +ValuesTab = "Tabel" +Warning = "Waarschuwing" +XEnd = "X einde" +XStart = "X begin" Zoom = "Zoom" diff --git a/apps/toolbox.nl.i18n b/apps/toolbox.nl.i18n index 6ea333b61..65ce2c17e 100644 --- a/apps/toolbox.nl.i18n +++ b/apps/toolbox.nl.i18n @@ -35,7 +35,7 @@ UnitCurrentAmpereMilli = "Milliampère" UnitCurrentAmpereMicro = "Microampère" UnitTemperatureMenu = "Temperatuur" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "hoeveelheid stof" +UnitAmountMenu = "Hoeveelheid stof" UnitAmountMole = "Mol" UnitAmountMoleMilli = "Millimol" UnitAmountMoleMicro = "Micromol" @@ -74,7 +74,7 @@ UnitPowerWattMilli = "Milliwatt" UnitPowerWattMicro = "Microwatt" UnitElectricChargeMenu = "Elektrische lading" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "elektrisch potentiaal" +UnitPotentialMenu = "Elektrisch potentiaal" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" UnitPotentialVoltMilli = "Millivolt" @@ -86,7 +86,7 @@ UnitCapacitanceFaradMicro = "Microfarad" UnitResistanceMenu = "Elektrische weerstand" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "elektrische geleidbaarheid" +UnitConductanceMenu = "Elektrische geleidbaarheid" UnitConductanceSiemens = "Siemens" UnitConductanceSiemensMilli = "Millisiemens" UnitMagneticFieldMenu = "Magnetisch veld" @@ -109,7 +109,7 @@ ComplexNumber = "Complexe getallen" Combinatorics = "Combinatoriek" Arithmetic = "rekenkunde" Matrices = "Matrix" -NewMatrix = "Nieuw matrix" +NewMatrix = "Nieuwe matrix" Identity = "Eenheidsmatrix van formaat n" Lists = "Lijst" HyperbolicTrigonometry = "Hyperbolische meetkunde" @@ -122,46 +122,46 @@ ComplexAbsoluteValue = "Absolute waarde" Agument = "Argument" RealPart = "Reëel deel" ImaginaryPart = "Imaginair deel" -Conjugate = "Conjugate" -Combination = "Combination" -Permutation = "Permutation" -GreatCommonDivisor = "GCD" -LeastCommonMultiple = "LCM" -Remainder = "Remainder division p by q" -Quotient = "Quotient division p by q" +Conjugate = "Geconjugeerde" +Combination = "Combinatie" +Permutation = "Permutatie" +GreatCommonDivisor = "GGD" +LeastCommonMultiple = "KGV" +Remainder = "Rest deling p door q" +Quotient = "Quotiënt deling p door q" Inverse = "Inverse" Determinant = "Determinant" -Transpose = "Transpose" -Trace = "Trace" -Dimension = "Size" -Sort = "Sort ascending " -InvSort = "Sort descending" +Transpose = "Getransponeerde" +Trace = "Spoor" +Dimension = "Afmeting" +Sort = "Sorteer oplopend " +InvSort = "Sort aflopend" Maximum = "Maximum" Minimum = "Minimum" Floor = "Floor" -FracPart = "Fractional part" +FracPart = "Fractioneel deel" Ceiling = "Ceiling" -Rounding = "Rounding to n digits" -HyperbolicCosine = "Hyperbolic cosine" -HyperbolicSine = "Hyperbolic sine" -HyperbolicTangent = "Hyperbolic tangent" -InverseHyperbolicCosine = "Inverse hyperbolic cosine" -InverseHyperbolicSine = "Inverse hyperbolic sine" -InverseHyperbolicTangent = "Inverse hyperbolic tangent" -Prediction95 = "Prediction interval 95%" -Prediction = "Simple prediction interval" -Confidence = "Confidence interval" -RandomAndApproximation = "Random and approximation" -RandomFloat = "Floating point number in [0,1[" -RandomInteger = "Random integer in [a,b]" -PrimeFactorDecomposition = "Integer factorization" -NormCDF = "P(X Date: Fri, 27 Mar 2020 10:19:20 +0100 Subject: [PATCH 081/453] [nl] Epsilon translation --- apps/settings/base.nl.i18n | 14 +++++++------- apps/variables.nl.i18n | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n index 83c87ad3c..6fb71a105 100644 --- a/apps/settings/base.nl.i18n +++ b/apps/settings/base.nl.i18n @@ -12,13 +12,13 @@ ToDeactivateExamMode1 = "Om de examenstand te verlaten," ToDeactivateExamMode2 = "sluit de rekenmachine aan op een computer" ToDeactivateExamMode3 = "of op een stopcontact." # --------------------- Please do not edit these messages - Discuss with Leo (remove this later) --------------------- -ExamModeWarning1 = "Caution: compliance of this" -ExamModeWarning2 = "unofficial software's exam mode" -ExamModeWarning3 = "is not guaranteed by NumWorks." -AboutWarning1 = "Caution: you're using an" -AboutWarning2 = "unofficial software version." -AboutWarning3 = "NumWorks can't be held responsible" -AboutWarning4 = "for any resulting damage." +ExamModeWarning1 = "Let op: naleving van de examenstand" +ExamModeWarning2 = "op deze onofficiële software wordt" +ExamModeWarning3 = "door NumWorks niet gegarandeerd." +AboutWarning1 = "Let op: je gebruikt een" +AboutWarning2 = "onofficiële softwareversie." +AboutWarning3 = "NumWorks is niet verantwoordelijk" +AboutWarning4 = "voor mogelijke resulterende schade" # ----------------------------------------------------------------------------- About = "Over deze rekenmachine" Degrees = "Graden " diff --git a/apps/variables.nl.i18n b/apps/variables.nl.i18n index 325f8a0f7..06305f239 100644 --- a/apps/variables.nl.i18n +++ b/apps/variables.nl.i18n @@ -7,4 +7,4 @@ EmptyExpressionBox1 = "Om een variabele to definiëren, typ:" EmptyFunctionBox1 = "Om een functie to definiëren, typ:" EmptyExpressionBox2 = "De naam van de variabele kan bevatten:" EmptyFunctionBox2 = "De naam van de functie kan bevatten:" -EnableCharacters = "A..Z, a..z, 0..9 and _" +EnableCharacters = "A..Z, a..z, 0..9 en _" From b1e737879ddb526beb29d195b27461e7ffbab9b2 Mon Sep 17 00:00:00 2001 From: Jorick Alberga Date: Thu, 2 Apr 2020 15:06:27 +0200 Subject: [PATCH 082/453] [nl] Translation Epsilon --- apps/graph/base.nl.i18n | 4 ++-- apps/on_boarding/base.nl.i18n | 2 +- apps/sequence/base.nl.i18n | 2 +- apps/settings/base.nl.i18n | 4 ++-- apps/shared.nl.i18n | 8 ++++---- apps/solver/base.nl.i18n | 4 ++-- apps/statistics/base.nl.i18n | 2 +- apps/usb/base.nl.i18n | 6 +++--- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/graph/base.nl.i18n b/apps/graph/base.nl.i18n index a1b24f965..a809429e5 100644 --- a/apps/graph/base.nl.i18n +++ b/apps/graph/base.nl.i18n @@ -20,8 +20,8 @@ Zeros = "Nulpunten" Tangent = "Tangens" Intersection = "Snijpunt" Preimage = "Inverse beeld" -SelectLowerBound = "Selecteer ondergrens" -SelectUpperBound = "Selecteer bovengrens" +SelectLowerBound = "Selecteer ondergrens " +SelectUpperBound = "Selecteer bovengrens " NoMaximumFound = "Geen maximum gevonden" NoMinimumFound = "Geen minimum gevonden" NoZeroFound = "Geen nulpunt gevonden" diff --git a/apps/on_boarding/base.nl.i18n b/apps/on_boarding/base.nl.i18n index ebd089a7d..7d9ce05b7 100644 --- a/apps/on_boarding/base.nl.i18n +++ b/apps/on_boarding/base.nl.i18n @@ -8,6 +8,6 @@ BetaVersionMessage1 = "" BetaVersionMessage2 = "Je apparaat draait op een bèta-software." BetaVersionMessage3 = "Je komt mogelijk bugs of glitches tegen." BetaVersionMessage4 = "" -BetaVersionMessage5 = "Eventuele feedback kun je sturen naar" +BetaVersionMessage5 = "Feedback kun je sturen naar" BetaVersionMessage6 = "contact@numworks.nl" Skip = "Verdergaan" diff --git a/apps/sequence/base.nl.i18n b/apps/sequence/base.nl.i18n index f1a8c74e1..507923183 100644 --- a/apps/sequence/base.nl.i18n +++ b/apps/sequence/base.nl.i18n @@ -10,7 +10,7 @@ DoubleRecurrence = "Recursief tweede orde" SequenceOptions = "Rij-opties" SequenceColor = "Rij-kleur" DeleteSequence = "Rij verwijderen" -NoSequence = "Geen rij gegeven" +NoSequence = "Geen rij ingevoerd" NoActivatedSequence = "Geen rij is ingeschakelt" NStart = "N begin" NEnd = "N einde" diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n index 6fb71a105..94f51de45 100644 --- a/apps/settings/base.nl.i18n +++ b/apps/settings/base.nl.i18n @@ -9,8 +9,8 @@ ComplexFormat = "Complex formaat" ExamMode = "Examenstand" ExamModeActive = "Herstart examenstand" ToDeactivateExamMode1 = "Om de examenstand te verlaten," -ToDeactivateExamMode2 = "sluit de rekenmachine aan op een computer" -ToDeactivateExamMode3 = "of op een stopcontact." +ToDeactivateExamMode2 = "sluit de rekenmachine aan op" +ToDeactivateExamMode3 = "een computer of stopcontact." # --------------------- Please do not edit these messages - Discuss with Leo (remove this later) --------------------- ExamModeWarning1 = "Let op: naleving van de examenstand" ExamModeWarning2 = "op deze onofficiële software wordt" diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index dea008727..87cf82d2e 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -14,10 +14,10 @@ ColumnOptions = "Kolomopties" CopyColumnInList = "Exporteer de kolom naar een lijst" DataNotSuitable = "Gegevens niet geschikt" DataTab = "Gegevens" -DefaultSetting = "standaardinstellingen" +DefaultSetting = "Standaardinstelling" Deg = "deg" Deviation = "Variantie" -DisplayValues = "Geef waarden weer" +DisplayValues = "Waarden weergeven" Empty = "Leeg" Eng = "eng" ExitExamMode1 = "Verlaat de " @@ -43,7 +43,7 @@ NameCannotStartWithNumber = "Een naam kan niet beginnen met een nummer" NameTaken = "Deze naam is al in gebruik" NameTooLong = "Deze naam is te lang" Next = "Volgende" -NoDataToPlot = "Geen gegevens om te tekenen" +NoDataToPlot = "Geen gegevens om te plotten" NoFunctionToDelete = "Geen functie om te verwijderen" NoValueToCompute = "Geen waarden om te berekenen" NEnd = "N einde" @@ -71,7 +71,7 @@ ThetaEnd = "θ einde" ThetaStart = "θ begin" TStart = "T begin" ToZoom = "Zoom: " -Trigonometric = "Goniometrische" +Trigonometric = "Goniometrisch" UndefinedValue = "Ongedefinieerde waarde" ValueNotReachedByFunction = "Waarde niet bereikt door functie" ValuesTab = "Tabel" diff --git a/apps/solver/base.nl.i18n b/apps/solver/base.nl.i18n index 949aa9762..adcfadc87 100644 --- a/apps/solver/base.nl.i18n +++ b/apps/solver/base.nl.i18n @@ -1,5 +1,5 @@ -SolverApp = "Vergelijkingen" -SolverAppCapital = "VERGELIJKINGEN" +SolverApp = "Vergelijking" +SolverAppCapital = "VERGELIJKING" AddEquation = "Vergelijking toevoegen" ResolveEquation = "Vergelijking oplossen" ResolveSystem = "Stelsel oplossen" diff --git a/apps/statistics/base.nl.i18n b/apps/statistics/base.nl.i18n index c66afa64c..3649387c1 100644 --- a/apps/statistics/base.nl.i18n +++ b/apps/statistics/base.nl.i18n @@ -21,5 +21,5 @@ ThirdQuartile = "Derde kwartiel" TotalSize = "Totale omvang" Range = "Bereik" StandardDeviationSigma = "Standaardafwijking σ" -SampleStandardDeviationS = "Steekprf stand.afwijk. s" +SampleStandardDeviationS = "Standaardafwijking s" InterquartileRange = "Interkwartielafstand" diff --git a/apps/usb/base.nl.i18n b/apps/usb/base.nl.i18n index 35829bbdd..ed8c78ca3 100644 --- a/apps/usb/base.nl.i18n +++ b/apps/usb/base.nl.i18n @@ -1,7 +1,7 @@ USBConnected = "DE REKENMACHINE IS AANGESLOTEN" -ConnectedMessage1 = "Om gegevens op te slaan, " +ConnectedMessage1 = "Om gegevens op te slaan," ConnectedMessage2 = "ga naar onze webpagina" ConnectedMessage3 = "workshop.numworks.com" ConnectedMessage4 = "Druk op de TERUG toets van je" -ConnectedMessage5 = "rekenmachine of haal de kabel er " -ConnectedMessage6 = "uit om hem los te koppelen." +ConnectedMessage5 = "rekenmachine of verwijder de" +ConnectedMessage6 = " kabel om hem los te koppelen." From a64ad8714644628b34cb900f4667b98aacf24e34 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 11:09:09 +0100 Subject: [PATCH 083/453] [pt] corrected settings and statistics --- apps/settings/base.pt.i18n | 24 ++++++++++++------------ apps/statistics/base.pt.i18n | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index d1b0793ab..4fc89203a 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -1,24 +1,24 @@ SettingsApp = "Configuração" SettingsAppCapital = "CONFIGURAÇÃO" -AngleUnit = "Valor do angulo" +AngleUnit = "Valor do ângulo" DisplayMode = "Formato numérico" EditionMode = "Formato escrita " EditionLinear = "Em linha " Edition2D = "Natural " ComplexFormat = "Complexos" ExamMode = "Modo de exame" -ExamModeActive = "Reactivar o modo de exame" -ToDeactivateExamMode1 = "Para desactivar o modo de exame," +ExamModeActive = "Reativar o modo de exame" +ToDeactivateExamMode1 = "Para desativar o modo de exame," ToDeactivateExamMode2 = "ligue a calculadora a um computador" -ToDeactivateExamMode3 = "ou a uma tomada eléctrica." +ToDeactivateExamMode3 = "ou a uma tomada elétrica." # --------------------- Please do not edit these messages --------------------- -ExamModeWarning1 = "Caution: compliance of this" -ExamModeWarning2 = "unofficial software's exam mode" -ExamModeWarning3 = "is not guaranteed by NumWorks." -AboutWarning1 = "Caution: you're using an" -AboutWarning2 = "unofficial software version." -AboutWarning3 = "NumWorks can't be held responsible" -AboutWarning4 = "for any resulting damage." +ExamModeWarning1 = "Cuidado: a conformidade deste" +ExamModeWarning2 = "software não oficial do modo de exame" +ExamModeWarning3 = "não é garantida pela NumWorks." +AboutWarning1 = "Cuidado: está a usar uma" +AboutWarning2 = "versão não oficial do software." +AboutWarning3 = "A NumWorks não pode ser responsável" +AboutWarning4 = "por qualquer dano resultante." # ----------------------------------------------------------------------------- About = "Acerca" Degrees = "Graus " @@ -27,7 +27,7 @@ Radian = "Radianos " Decimal = "Decimal " Scientific = "Científico " Engineering = "Engenharia " -SignificantFigures = "Algarismo significativo " +SignificantFigures = "Alg. significativos " Real = "Real " Cartesian = "Cartesiana " Polar = "Polar " diff --git a/apps/statistics/base.pt.i18n b/apps/statistics/base.pt.i18n index 5bb6e6044..3fd12f1e7 100644 --- a/apps/statistics/base.pt.i18n +++ b/apps/statistics/base.pt.i18n @@ -15,11 +15,11 @@ Frequency = "Relativa" HistogramSet = "Configurando o histograma" RectangleWidth = "Largura dos retângulos" BarStart = "Início da série" -FirstQuartile = "Quartil inferior" +FirstQuartile = "Primeiro quartil" Median = "Mediana" -ThirdQuartile = "Quartil superior" -TotalSize = "Número de itens" +ThirdQuartile = "Terceiro quartil" +TotalSize = "Dimensão" Range = "Amplitude" StandardDeviationSigma = "Desvio padrão σ" SampleStandardDeviationS = "Desvio padrão amostral s" -InterquartileRange = "Interquartil" +InterquartileRange = "Amplitude interquartil" From 1f54ddf2453bf961879932c1fe58d02f346fc148 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 11:39:12 +0100 Subject: [PATCH 084/453] [pt] changed settings again improved details --- apps/settings/base.pt.i18n | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 4fc89203a..ef3f5c451 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -12,8 +12,8 @@ ToDeactivateExamMode1 = "Para desativar o modo de exame," ToDeactivateExamMode2 = "ligue a calculadora a um computador" ToDeactivateExamMode3 = "ou a uma tomada elétrica." # --------------------- Please do not edit these messages --------------------- -ExamModeWarning1 = "Cuidado: a conformidade deste" -ExamModeWarning2 = "software não oficial do modo de exame" +ExamModeWarning1 = "Cuidado: a conformidade do" +ExamModeWarning2 = "modo exame deste software não oficial" ExamModeWarning3 = "não é garantida pela NumWorks." AboutWarning1 = "Cuidado: está a usar uma" AboutWarning2 = "versão não oficial do software." From d0a9dabd64c22af330efd32741480d13fb518629 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 11:42:09 +0100 Subject: [PATCH 085/453] [pt] changed details in home and probabilities --- apps/home/base.pt.i18n | 4 ++-- apps/probability/base.pt.i18n | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n index e6816935c..d49cc0b71 100644 --- a/apps/home/base.pt.i18n +++ b/apps/home/base.pt.i18n @@ -1,4 +1,4 @@ Apps = "Aplicações" AppsCapital = "APLICAÇÕES" -ForbidenAppInExamMode1 = "This application is" -ForbidenAppInExamMode2 = "forbidden in exam mode" +ForbidenAppInExamMode1 = "Esta aplicação é" +ForbidenAppInExamMode2 = "proibida no Modo de Exame" diff --git a/apps/probability/base.pt.i18n b/apps/probability/base.pt.i18n index 6e9071d74..f37757390 100644 --- a/apps/probability/base.pt.i18n +++ b/apps/probability/base.pt.i18n @@ -1,5 +1,5 @@ -ProbaApp = "Probabilidade" -ProbaAppCapital = "PROBABILIDADE" +ProbaApp = "Probabilidades" +ProbaAppCapital = "PROBABILIDADES" ChooseDistribution = "Selecionar a distribuição" Binomial = "Binomial" Geometric = "Geométrica" From ad348cb64ebf586050201ed7e7f63c4ab5740dae Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 11:49:31 +0100 Subject: [PATCH 086/453] [pt] changed graph mistakes --- apps/graph/base.pt.i18n | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/graph/base.pt.i18n b/apps/graph/base.pt.i18n index 449b4da90..707a10013 100644 --- a/apps/graph/base.pt.i18n +++ b/apps/graph/base.pt.i18n @@ -1,5 +1,5 @@ -FunctionApp = "Função" -FunctionAppCapital = "FUNÇÃO" +FunctionApp = "Funções" +FunctionAppCapital = "FUNÇÕES" FunctionTab = "Funções" AddFunction = "Adicionar uma função" DeleteFunction = "Eliminar a função" @@ -16,16 +16,16 @@ NoFunction = "Nenhuma função" NoActivatedFunction = "Sem função activada" PlotOptions = "Opções da curva" Compute = "Calcular" -Zeros = "Raízes" +Zeros = "Zeros" Tangent = "Tangente" -Intersection = "Intersecção" +Intersection = "Interseção" Preimage = "Imagem inversa" -SelectLowerBound = "Selecionar limite superior " -SelectUpperBound = "Selecionar limite inferior " +SelectLowerBound = "Selecionar limite inferior" +SelectUpperBound = "Selecionar limite superior" NoMaximumFound = "Nenhum máximo encontrado" NoMinimumFound = "Nenhum mínimo encontrado" NoZeroFound = "Nenhuma raiz encontrada" -NoIntersectionFound = "Nenhuma intersecção encontrada" +NoIntersectionFound = "Nenhuma interseção encontrada" NoPreimageFound = "Nenhuma imagem inversa encontrada" DerivativeFunctionColumn = "Coluna da função derivada" HideDerivativeColumn = "Esconder função derivada" From 9c2753148b04898a0ba5e335c3f390fb73006260 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 11:57:24 +0100 Subject: [PATCH 087/453] [pt] changed toolbox --- apps/code/toolbox.pt.i18n | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/code/toolbox.pt.i18n b/apps/code/toolbox.pt.i18n index 178d42b7b..6bfd6c5da 100644 --- a/apps/code/toolbox.pt.i18n +++ b/apps/code/toolbox.pt.i18n @@ -1,4 +1,4 @@ -Functions = "Functions" -Catalog = "Catalog" -Modules = "Modules" -LoopsAndTests = "Loops and tests" +Functions = "Funções" +Catalog = "Catálogo" +Modules = "Módulos" +LoopsAndTests = "Laços e testes" From b9ce07b24d0f2aae987585e7f86dbff1f6782d15 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 15:55:23 +0100 Subject: [PATCH 088/453] [pt] translated catalog - python --- apps/code/catalog.pt.i18n | 366 +++++++++++++++++++------------------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index f9cce93fc..428ab928f 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -1,196 +1,196 @@ -PythonPound = "Comment" -PythonPercent = "Modulo" -Python1J = "Imaginary i" -PythonLF = "Line feed" -PythonTab = "Tabulation" -PythonAmpersand = "Bitwise and" -PythonSymbolExp = "Bitwise exclusive or" -PythonVerticalBar = "Bitwise or" -PythonSingleQuote = "Single quote" -PythonImag = "Imaginary part of z" -PythonReal = "Real part of z" -PythonAbs = "Absolute value/Magnitude" -PythonAcos = "Arc cosine" -PythonAcosh = "Arc hyperbolic cosine" -PythonAppend = "Add x to the end of the list" +PythonPound = "Comentário" +PythonPercent = "Módulo" +Python1J = "i Complexo" +PythonLF = "Nova linha" +PythonTab = "Tabulação" +PythonAmpersand = "Operador binário and" +PythonSymbolExp = "Operador binário exclusivo or" +PythonVerticalBar = "Operador binário or" +PythonSingleQuote = "Apóstrofo" +PythonImag = "Parte imaginária de z" +PythonReal = "Parte real de z" +PythonAbs = "Valor absoluto/módulo" +PythonAcos = "Arco cosseno" +PythonAcosh = "Arco cosseno hiperbólico" +PythonAppend = "Adicionar x no fim da lista" PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)" -PythonAsin = "Arc sine" -PythonAsinh = "Arc hyperbolic sine" -PythonAtan = "Arc tangent" -PythonAtan2 = "Return atan(y/x)" -PythonAtanh = "Arc hyperbolic tangent" +PythonAsin = "Arco seno" +PythonAsinh = "Arco seno hiperbólico" +PythonAtan = "Arco tangente" +PythonAtan2 = "Cálculo de atan(y/x)" +PythonAtanh = "Arco tangente hiperbólica" PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)" PythonBar = "Draw a bar plot with x values" -PythonBin = "Convert integer to binary" -PythonCeil = "Ceiling" -PythonChoice = "Random number in the list" -PythonClear = "Empty the list" -PythonCmathFunction = "cmath module function prefix" -PythonColor = "Define a rgb color" -PythonComplex = "Return a+ib" -PythonCopySign = "Return x with the sign of y" -PythonCos = "Cosine" -PythonCosh = "Hyperbolic cosine" -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" -PythonErf = "Error function" -PythonErfc = "Complementary error function" -PythonEval = "Return the evaluated expression" -PythonExp = "Exponential function" -PythonExpm1 = "Compute exp(x)-1" -PythonFabs = "Absolute value" -PythonFillRect = "Fill a rectangle at pixel (x,y)" -PythonFloat = "Convert x to a float" -PythonFloor = "Floor" -PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" -PythonGamma = "Gamma function" -PythonGetPixel = "Return pixel (x,y) color" -PythonGetrandbits = "Integer with k random bits" +PythonBin = "Converter número inteiro em binário" +PythonCeil = "Teto" +PythonChoice = "Número aleatório na lista" +PythonClear = "Esvaziar a lista" +PythonCmathFunction = "Prefixo da função do módulo cmath" +PythonColor = "Define uma cor rgb" +PythonComplex = "Devolve a+ib" +PythonCopySign = "Devolve x com o sinal de y" +PythonCos = "Cosseno" +PythonCosh = "Cosseno hiperbólico" +PythonCount = "Contar as ocorrências de x" +PythonDegrees = "Converter x de radianos para graus" +PythonDivMod = "Quociente e resto" +PythonDrawString = "Mostrar o texto do pixel (x,y)" +PythonErf = "Função erro" +PythonErfc = "Função erro complementar" +PythonEval = "Devolve a expressão avaliada" +PythonExp = "Função exponencial" +PythonExpm1 = "Calcular exp(x)-1" +PythonFabs = "Valor absoluto" +PythonFillRect = "Preenche um retângulo no pixel (x,y)" +PythonFloat = "Converter x num flutuante" +PythonFloor = "Parte inteira" +PythonFmod = "a módulo b" +PythonFrExp = "Coeficiente e expoente de x" +PythonGamma = "Função gama" +PythonGetPixel = "Devolve a cor do pixel (x,y)" +PythonGetrandbits = "Número inteiro aleatório com k bits" PythonGrid = "Toggle the visibility of the grid" -PythonHex = "Convert integer to hexadecimal" +PythonHex = "Converter inteiro em hexadecimal" PythonHist = "Draw the histogram of x" -PythonImportCmath = "Import cmath module" -PythonImportIon = "Import ion module" -PythonImportKandinsky = "Import kandinsky module" -PythonImportRandom = "Import random module" -PythonImportMath = "Import math module" +PythonImportCmath = "Importar módulo cmath" +PythonImportIon = "Importar módulo ion" +PythonImportKandinsky = "Importar módulo kandinsky" +PythonImportRandom = "Importar módulo random" +PythonImportMath = "Importar módulo math" PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" -PythonImportTime = "Import time module" -PythonImportTurtle = "Import turtle module" -PythonIndex = "Index of the first x occurrence" -PythonInput = "Prompt a value" -PythonInsert = "Insert x at index i in the list" -PythonInt = "Convert x to an integer" -PythonIonFunction = "ion module function prefix" -PythonIsFinite = "Check if x is finite" -PythonIsInfinite = "Check if x is infinity" -PythonIsKeyDown = "Return True if the k key is down" -PythonIsNaN = "Check if x is a NaN" -PythonKandinskyFunction = "kandinsky module function prefix" -PythonKeyLeft = "LEFT ARROW key" -PythonKeyUp = "UP ARROW key" -PythonKeyDown = "DOWN ARROW key" -PythonKeyRight = "RIGHT ARROW key" -PythonKeyOk = "OK key" -PythonKeyBack = "BACK key" -PythonKeyHome = "HOME key" -PythonKeyOnOff = "ON/OFF key" -PythonKeyShift = "SHIFT key" -PythonKeyAlpha = "ALPHA key" -PythonKeyXnt = "X,N,T key" -PythonKeyVar = "VAR key" -PythonKeyToolbox = "TOOLBOX key" -PythonKeyBackspace = "BACKSPACE key" -PythonKeyExp = "EXPONENTIAL key" -PythonKeyLn = "NATURAL LOGARITHM key" -PythonKeyLog = "DECIMAL LOGARITHM key" -PythonKeyImaginary = "IMAGINARY I key" -PythonKeyComma = "COMMA key" -PythonKeyPower = "POWER key" -PythonKeySine = "SINE key" -PythonKeyCosine = "COSINE key" -PythonKeyTangent = "TANGENT key" -PythonKeyPi = "PI key" -PythonKeySqrt = "SQUARE ROOT key" -PythonKeySquare = "SQUARE key" -PythonKeySeven = "7 key" -PythonKeyEight = "8 key" -PythonKeyNine = "9 key" -PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" -PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" -PythonKeyFour = "4 key" -PythonKeyFive = "5 key" -PythonKeySix = "6 key" -PythonKeyMultiplication = "MULTIPLICATION key" -PythonKeyDivision = "DIVISION key" -PythonKeyOne = "1 key" -PythonKeyTwo = "2 key" -PythonKeyThree = "3 key" -PythonKeyPlus = "PLUS key" -PythonKeyMinus = "MINUS key" -PythonKeyZero = "0 key" -PythonKeyDot = "DOT key" -PythonKeyEe = "10 POWER X key" -PythonKeyAns = "ANS key" -PythonKeyExe = "EXE key" -PythonLdexp = "Return x*(2**i), inverse of frexp" -PythonLength = "Length of an object" -PythonLgamma = "Log-gamma function" -PythonLog = "Logarithm to base a" -PythonLog10 = "Logarithm to base 10" -PythonLog2 = "Logarithm to base 2" -PythonMathFunction = "math module function prefix" +PythonImportTime = "Importar módulo time" +PythonImportTurtle = "Importar módulo turtle" +PythonIndex = "Índice da primeira ocorrência de x" +PythonInput = "Adicionar um valor" +PythonInsert = "Inserir x no índice i na lista" +PythonInt = "Converter x num número inteiro" +PythonIonFunction = "Prefixo da função módulo ion" +PythonIsFinite = "Verificar se x é finito" +PythonIsInfinite = "Verificar se x é infinito" +PythonIsKeyDown = "Devolve True se a tecla k for pressionada" +PythonIsNaN = "Verificar se x é um NaN" +PythonKandinskyFunction = "Prefixo da função módulo kandinsky" +PythonKeyLeft = "tecla SETA ESQUERDA" +PythonKeyUp = "tecla SETA CIMA " +PythonKeyDown = "tecla SETA BAIXO" +PythonKeyRight = "tecla SETA DIREITA" +PythonKeyOk = "tecla OK" +PythonKeyBack = "tecla VOLTAR" +PythonKeyHome = "tecla HOME" +PythonKeyOnOff = "tecla ON/OFF" +PythonKeyShift = "tecla SHIFT" +PythonKeyAlpha = "tecla ALPHA" +PythonKeyXnt = "tecla X,N,T" +PythonKeyVar = "tecla VAR" +PythonKeyToolbox = "tecla CAIXA DE FERRAMENTAS" +PythonKeyBackspace = "tecla APAGAR" +PythonKeyExp = "tecla EXPONENCIAL" +PythonKeyLn = "tecla LOGARITMO NATURAL" +PythonKeyLog = "tecla LOGARITMO DECIMAL" +PythonKeyImaginary = "tecla I IMAGINÁRIO" +PythonKeyComma = "tecla VÍRGULA" +PythonKeyPower = "tecla EXPOENTE" +PythonKeySine = "tecla SENO" +PythonKeyCosine = "tecla COSSENO" +PythonKeyTangent = "tecla TANGENTE" +PythonKeyPi = "tecla PI" +PythonKeySqrt = "tecla RAIZ QUADRADA" +PythonKeySquare = "tecla AO QUADRADO" +PythonKeySeven = "tecla 7" +PythonKeyEight = "tecla 8" +PythonKeyNine = "tecla 9" +PythonKeyLeftParenthesis = "tecla PARÊNTESE ESQUERDO" +PythonKeyRightParenthesis = "tecla PARÊNTESE DIREITO" +PythonKeyFour = "tecla 4" +PythonKeyFive = "tecla 5" +PythonKeySix = "tecla 6" +PythonKeyMultiplication = "tecla MULTIPLICAÇÃO" +PythonKeyDivision = "tecla DIVISÃO" +PythonKeyOne = "tecla 1" +PythonKeyTwo = "tecla 2" +PythonKeyThree = "tecla 3" +PythonKeyPlus = "tecla MAIS" +PythonKeyMinus = "tecla MENOS" +PythonKeyZero = "tecla 0" +PythonKeyDot = "tecla PONTO" +PythonKeyEe = "tecla 10 expoente X" +PythonKeyAns = "tecla ANS" +PythonKeyExe = "tecla EXE" +PythonLdexp = "Devolve x*(2**i), inverso de frexp" +PythonLength = "Comprimento de um objeto" +PythonLgamma = "Logaritmo da função gama" +PythonLog = "Logaritmo de base a" +PythonLog10 = "Logaritmo de base 10" +PythonLog2 = "Logaritmo de base 2" +PythonMathFunction = "Prefixo do módulo da função math" PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" -PythonMax = "Maximum" -PythonMin = "Minimum" -PythonModf = "Fractional and integer parts of x" -PythonMonotonic = "Value of a monotonic clock" -PythonOct = "Convert integer to octal" -PythonPhase = "Phase of z" +PythonMax = "Máximo" +PythonMin = "Mínimo" +PythonModf = "Partes inteira e frácionária de x" +PythonMonotonic = "Devolve o valor do relógio" +PythonOct = "Converter número inteiro em octal" +PythonPhase = "Argumento de z" PythonPlot = "Plot y versus x as lines" -PythonPolar = "z in polar coordinates" -PythonPop = "Remove and return the last item" -PythonPower = "x raised to the power y" -PythonPrint = "Print object" -PythonRadians = "Convert x from degrees to radians" -PythonRandint = "Random integer in [a,b]" -PythonRandom = "Floating point number in [0,1[" -PythonRandomFunction = "random module function prefix" -PythonRandrange = "Random number in range(start,stop)" -PythonRangeStartStop = "List from start to stop-1" -PythonRangeStop = "List from 0 to stop-1" -PythonRect = "Convert to cartesian coordinates" -PythonRemove = "Remove the first occurrence of x" -PythonReverse = "Reverse the elements of the list" -PythonRound = "Round to n digits" +PythonPolar = "z em coordenadas polares" +PythonPop = "Remover o último item" +PythonPower = "x levantado a y" +PythonPrint = "Mostrar o objeto" +PythonRadians = "Converter x de graus para radianos" +PythonRandint = "Número inteiro aleatório em [a,b]" +PythonRandom = "Número decimal em [0,1[" +PythonRandomFunction = "Prefixo do módulo da função random" +PythonRandrange = "Número aleatório no intervalo (start,stop)" +PythonRangeStartStop = "Lista de start a stop-1" +PythonRangeStop = "Lista de 0 a stop-1" +PythonRect = "z em coordenadas cartesianas" +PythonRemove = "Remover a primeira ocorrência de x" +PythonReverse = "Inverter os elementos da lista" +PythonRound = "Arredondar para n dígitos" PythonScatter = "Draw a scatter plot of y versus x" -PythonSeed = "Initialize random number generator" -PythonSetPixel = "Color pixel (x,y)" +PythonSeed = "Iniciar gerador aleatório de números" +PythonSetPixel = "Cor do pixel (x,y)" PythonShow = "Display the figure" -PythonSin = "Sine" -PythonSinh = "Hyperbolic sine" -PythonSleep = "Suspend the execution for t seconds" -PythonSort = "Sort the list" -PythonSqrt = "Square root" -PythonSum = "Sum the items of a list" -PythonTan = "Tangent" -PythonTanh = "Hyperbolic tangent" +PythonSin = "Seno" +PythonSinh = "Seno hiperbólico" +PythonSleep = "Suspender a execução por t segundos" +PythonSort = "Ordenar a lista" +PythonSqrt = "Raiz quadrada" +PythonSum = "Soma dos itens da lista" +PythonTan = "Tangente" +PythonTanh = "Tangente hiperbólica" PythonText = "Display a text at (x,y) coordinates" -PythonTimeFunction = "time module function prefix" -PythonTrunc = "x truncated to an integer" -PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" -PythonTurtleCircle = "Circle of radius r pixels" -PythonTurtleColor = "Set the pen color" +PythonTimeFunction = "Prefixo da função módulo time" +PythonTrunc = "x truncado a um número inteiro" +PythonTurtleBackward = "Recuar x pixels" +PythonTurtleBlack = "Cor preta" +PythonTurtleBlue = "Cor azul" +PythonTurtleBrown = "Cor castanha" +PythonTurtleCircle = "Desenhar uma circunferência de raio r pixels" +PythonTurtleColor = "Definir a cor da caneta" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" -PythonTurtleForward = "Move forward by x pixels" -PythonTurtleFunction = "turtle module function prefix" -PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" -PythonTurtleHeading = "Return the current heading" -PythonTurtleHideturtle = "Hide the turtle" -PythonTurtleIsdown = "Return True if the pen is down" -PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" -PythonTurtlePendown = "Pull the pen down" -PythonTurtlePensize = "Set the line thickness to x pixels" -PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" -PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" -PythonTurtleReset = "Reset the drawing" -PythonTurtleRight = "Turn right by a degrees" -PythonTurtleSetheading = "Set the orientation to a degrees" +PythonTurtleForward = "Avançar x pixels" +PythonTurtleFunction = "Prefixo da função módulo turtle" +PythonTurtleGoto = "Ir paras as coordenadas (x,y)" +PythonTurtleGreen = "Cor verde" +PythonTurtleGrey = "Cor cinzenta" +PythonTurtleHeading = "Voltar para a orientação atual" +PythonTurtleHideturtle = "Esconder o turtle" +PythonTurtleIsdown = "Devolve True se a caneta está pressionada" +PythonTurtleLeft = "Vira à esquerda por a graus" +PythonTurtleOrange = "Cor laranja" +PythonTurtlePendown = "Puxar a caneta para baixo" +PythonTurtlePensize = "Definir a espessura para x pixels" +PythonTurtlePenup = "Puxar a caneta para cima" +PythonTurtlePink = "Cor rosa" +PythonTurtlePosition = "Devolve a posição atual (x,y)" +PythonTurtlePurple = "Cor roxa" +PythonTurtleRed = "Cor vermelha" +PythonTurtleReset = "Reiniciar o desenho" +PythonTurtleRight = "Virar à esquerda por a graus" +PythonTurtleSetheading = "Definir a orientação por a graus" PythonTurtleSetposition = "Positionne la tortue" -PythonTurtleShowturtle = "Show the turtle" -PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" -PythonUniform = "Floating point number in [a,b]" +PythonTurtleShowturtle = "Mostrar o turtle" +PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10" +PythonTurtleWhite = "Cor branca" +PythonTurtleYellow = "Cor amarela" +PythonUniform = "Número decimal em [a,b]" From 578c8be8574d1b665829cf133dadf79aab6260d7 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 16:21:13 +0100 Subject: [PATCH 089/453] [pt] corrected shared and base --- apps/shared.pt.i18n | 42 ++++++++++++++++++++-------------------- apps/solver/base.pt.i18n | 8 ++++---- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 355f56e9a..b1f1261b8 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -1,8 +1,8 @@ -ActivateDeactivate = "Activar/Desactivar" -ActivateExamMode = "Activar o modo de exame" +ActivateDeactivate = "Ativar/Desativar" +ActivateExamMode = "Ativar o modo de exame" ActivateDutchExamMode = "Activate Dutch exam mode" ActiveExamModeMessage1 = "Todos os seus dados serão " -ActiveExamModeMessage2 = "apagados se você ligar " +ActiveExamModeMessage2 = "apagados se ativar " ActiveExamModeMessage3 = "o modo de exame." ActiveDutchExamModeMessage1 = "All your data will be deleted when" ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" @@ -11,16 +11,16 @@ Axis = "Eixos" Cancel = "Cancelar" ClearColumn = "Excluir coluna" ColumnOptions = "Opções de coluna" -CopyColumnInList = "Copie a coluna em uma lista" +CopyColumnInList = "Copiar a coluna para uma lista" DataNotSuitable = "Dados não adequados" DataTab = "Dados" -DefaultSetting = "Configurações basicas" +DefaultSetting = "Configurações básicas" Deg = "gra" -Deviation = "Variancia" +Deviation = "Variância" DisplayValues = "Exibir os valores" -Empty = "Vácuo" +Empty = "Vazio" Eng = "eng" -ExitExamMode1 = "Você quer sair do modo de " +ExitExamMode1 = "Deseja sair do modo de " ExitExamMode2 = "exame ?" Exponential = "Exponencial" FillWithFormula = "Preencher com uma fórmula" @@ -29,25 +29,25 @@ FunctionColumn = "Coluna 0(0)" FunctionOptions = "Opções de função" Goto = "Ir a" GraphTab = "Gráfico" -HardwareTestLaunch1 = "Você vai executar o teste da planta." -HardwareTestLaunch2 = "Para sair você tem que executar" -HardwareTestLaunch3 = "uma redefinição, que ira apagar" -HardwareTestLaunch4 = "seus dados." +HardwareTestLaunch1 = "Vai executar o teste da planta." +HardwareTestLaunch2 = "Para sair tem que executar" +HardwareTestLaunch3 = "uma redefinição, que irá apagar" +HardwareTestLaunch4 = "os seus dados." Initialization = "Inicialização" IntervalSet = "Ajustar o intervalo" Language = "Idioma" LowBattery = "Bateria fraca" Mean = "Média" Move = " Mover : " -NameCannotStartWithNumber = "Um nome não pode começar com um número" -NameTaken = "Este nome é já usado" +NameCannotStartWithNumber = "O nome não pode começar com um número" +NameTaken = "Este nome já está a ser usado" NameTooLong = "Este nome é muito longo" NEnd = "N fim" Next = "Seguinte" -NoDataToPlot = "Não ha dados para desenhar" +NoDataToPlot = "Não há dados para desenhar" NoFunctionToDelete = "Sem função para eliminar" -NoValueToCompute = "Nenhuma quantidade para calcular" -NStart = "N inicio" +NoValueToCompute = "Não há dados para calcular" +NStart = "N início" Ok = "Confirmar" Or = " ou " Orthonormal = "Ortonormado" @@ -62,14 +62,14 @@ SquareSum = "Soma dos quadrados" StandardDeviation = "Desvio padrão" StatTab = "Estat" Step = "Passo" -StorageMemoryFull1 = "A memoria esta cheia." +StorageMemoryFull1 = "A memória esta cheia." StorageMemoryFull2 = "Apage dados e tente novamente." StoreExpressionNotAllowed = "'store' não está permitido" SyntaxError = "Erro de sintaxe" TEnd = "T fim" ThetaEnd = "θ fim" -ThetaStart = "θ inicio" -TStart = "T inicio" +ThetaStart = "θ início" +TStart = "T início" ToZoom = "Zoom : " Trigonometric = "Trigonométrico" UndefinedValue = "Valor indefinido" @@ -77,5 +77,5 @@ ValueNotReachedByFunction = "O valor não é alcançado pela função" ValuesTab = "Tabela" Warning = "Atenção" XEnd = "X fim" -XStart = "X inicio" +XStart = "X início" Zoom = "Zoom" diff --git a/apps/solver/base.pt.i18n b/apps/solver/base.pt.i18n index 94b3df314..356eaa24f 100644 --- a/apps/solver/base.pt.i18n +++ b/apps/solver/base.pt.i18n @@ -11,17 +11,17 @@ TooManyVariables = "Existem muitas incógnitas" NonLinearSystem = "O sistema não é linear" Solution = "Solução" ApproximateSolution = "Solução aproximada" -SearchInverval = "Intervalo de busca" +SearchInverval = "Intervalo de pesquisa" NoSolutionSystem = "O sistema não tem solução" NoSolutionEquation = "A equação não tem solução" -NoSolutionInterval = "Nenhuma solução encontrada em el intervalo" +NoSolutionInterval = "Nenhuma solução encontrada no intervalo" EnterEquation = "Digite uma equação" InfiniteNumberOfSolutions = "Existe uma infinidade de soluções" ApproximateSolutionIntervalInstruction0= "Digite o intervalo para procurar" ApproximateSolutionIntervalInstruction1= "uma solução aproximada" -OnlyFirstSolutionsDisplayed0 = "Somente as 10 primeiras" +OnlyFirstSolutionsDisplayed0 = "Apenas as 10 primeiras" OnlyFirstSolutionsDisplayed1 = "soluções são exibidas" -PolynomeHasNoRealSolution0 = "O polinômio não tem" +PolynomeHasNoRealSolution0 = "O polinómio não tem" PolynomeHasNoRealSolution1 = "nenhuma raiz real" PredefinedVariablesUsedLeft = "Variáveis " PredefinedVariablesUsedRight = "pré-definidas utilizadas" From ff0fb4b4c217f9664fc53a64f7fe2b9adad536ec Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 16:23:22 +0100 Subject: [PATCH 090/453] [pt] corrected typos in usb --- apps/usb/base.pt.i18n | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/usb/base.pt.i18n b/apps/usb/base.pt.i18n index 0a8d365d8..5e6c3cea7 100644 --- a/apps/usb/base.pt.i18n +++ b/apps/usb/base.pt.i18n @@ -1,7 +1,7 @@ USBConnected = "A CALCULADORA ESTÁ CONECTADA" ConnectedMessage1 = "Para transferir dados, navegue" -ConnectedMessage2 = "na nossa pagina no seu computador" +ConnectedMessage2 = "na nossa página no seu computador" ConnectedMessage3 = "workshop.numworks.com" ConnectedMessage4 = "Pressione o botão RETURN na" -ConnectedMessage5 = "calculadora ou desligue-la para" -ConnectedMessage6 = "desconectar-la." +ConnectedMessage5 = "calculadora ou desligue-a para a" +ConnectedMessage6 = "desconectar." From e26739d4ad91e271503b19572941393e1b28f67b Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 17:42:20 +0100 Subject: [PATCH 091/453] [pt] corrected toolbox --- apps/toolbox.pt.i18n | 134 +++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 51c74171d..37e91706b 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -1,112 +1,112 @@ -Unit = "Units" -UnitTimeMenu = "Time" -UnitTimeSecondMenu = "Second" -UnitTimeSecond = "Second" -UnitTimeSecondMilli = "Millisecond" -UnitTimeSecondMicro = "Microsecond" -UnitTimeSecondNano = "Nanosecond" -UnitTimeMinute = "Minute" -UnitTimeHour = "Hour" -UnitTimeDay = "Day" -UnitTimeWeek = "Week" -UnitTimeMonth = "Month" -UnitTimeYear = "Year" -UnitDistanceMenu = "Distance" -UnitDistanceMeterMenu = "Meter" -UnitDistanceMeterKilo = "Kilometer" -UnitDistanceMeter = "Meter" -UnitDistanceMeterMilli = "Millimeter" -UnitDistanceMeterMicro = "Micrometer" -UnitDistanceMeterNano = "Nanometer" -UnitDistanceMeterPico = "Picometer" -UnitDistanceAstronomicalUnit = "Astronomical unit" -UnitDistanceLightYear = "Light year" +Unit = "Unidade" +UnitTimeMenu = "Tempo" +UnitTimeSecondMenu = "Segundo" +UnitTimeSecond = "Segundo" +UnitTimeSecondMilli = "Milisegundo" +UnitTimeSecondMicro = "Microsegundo" +UnitTimeSecondNano = "Nanosegundo" +UnitTimeMinute = "Minuto" +UnitTimeHour = "Hora" +UnitTimeDay = "Dia" +UnitTimeWeek = "Semana" +UnitTimeMonth = "Mês" +UnitTimeYear = "Ano" +UnitDistanceMenu = "Distância" +UnitDistanceMeterMenu = "Metro" +UnitDistanceMeterKilo = "Quilómetro" +UnitDistanceMeter = "Metro" +UnitDistanceMeterMilli = "Milímetro" +UnitDistanceMeterMicro = "Micrómetro" +UnitDistanceMeterNano = "Nanómetro" +UnitDistanceMeterPico = "Picómetro" +UnitDistanceAstronomicalUnit = "Unidade astronómica" +UnitDistanceLightYear = "Ano-luz" UnitDistanceParsec = "Parsec" -UnitMassMenu = "Mass" -UnitMassGramKilo = "Kilogram" -UnitMassGram = "Gram" -UnitMassGramMilli = "Milligram" -UnitMassGramMicro = "Microgram" -UnitMassGramNano = "Nanogram" -UnitMassTonne = "Tonne" -UnitCurrentMenu = "Electric current" +UnitMassMenu = "Massa" +UnitMassGramKilo = "Quilograma" +UnitMassGram = "Grama" +UnitMassGramMilli = "Miligrama" +UnitMassGramMicro = "Micrograma" +UnitMassGramNano = "Nanograma" +UnitMassTonne = "Tonelada" +UnitCurrentMenu = "Intensiadade da currente elétrica" UnitCurrentAmpere = "Ampere" -UnitCurrentAmpereMilli = "Milliampere" +UnitCurrentAmpereMilli = "Miliampere" UnitCurrentAmpereMicro = "Microampere" -UnitTemperatureMenu = "Temperature" +UnitTemperatureMenu = "Temperatura" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "Amount of substance" +UnitAmountMenu = "Quantidade da substância" UnitAmountMole = "Mole" -UnitAmountMoleMilli = "Millimole" +UnitAmountMoleMilli = "Milimole" UnitAmountMoleMicro = "Micromole" -UnitLuminousIntensityMenu = "Luminous intensity" +UnitLuminousIntensityMenu = "Intensidade luminosa" UnitLuminousIntensityCandela = "Candela" UnitFrequencyMenu = "Frequency" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" UnitFrequencyHertz = "Hertz" -UnitForceMenu = "Force" +UnitForceMenu = "Força" UnitForceNewtonKilo = "Kilonewton" UnitForceNewton = "Newton" -UnitForceNewtonMilli = "Millinewton" -UnitPressureMenu = "Pressure" +UnitForceNewtonMilli = "Milinewton" +UnitPressureMenu = "Pressão" UnitPressurePascal = "Pascal" UnitPressurePascalHecto = "Hectopascal" UnitPressureBar = "Bar" -UnitPressureAtm = "Atmosphere" -UnitEnergyMenu = "Energy" +UnitPressureAtm = "Atmosfera" +UnitEnergyMenu = "Energia" UnitEnergyJouleMenu = "Joule" UnitEnergyJouleKilo = "Kilojoule" UnitEnergyJoule = "Joule" -UnitEnergyJouleMilli = "Millijoule" -UnitEnergyEletronVoltMenu = "Electronvolt" -UnitEnergyElectronVoltMega = "Megaelectronvolt" -UnitEnergyElectronVoltKilo = "Kiloelectronvolt" -UnitEnergyElectronVolt = "Electronvolt" -UnitEnergyElectronVoltMilli = "Millielectronvolt" -UnitPowerMenu = "Power" +UnitEnergyJouleMilli = "Milijoule" +UnitEnergyEletronVoltMenu = "Eletrão-volt" +UnitEnergyElectronVoltMega = "Megaeletrão-volt" +UnitEnergyElectronVoltKilo = "Kiloeletrão-volt" +UnitEnergyElectronVolt = "Eletrão-volt" +UnitEnergyElectronVoltMilli = "Milieletrão-volt" +UnitPowerMenu = "Potência" UnitPowerWattGiga = "Gigawatt" UnitPowerWattMega = "Megawatt" UnitPowerWattKilo = "Kilowatt" UnitPowerWatt = "Watt" -UnitPowerWattMilli = "Milliwatt" +UnitPowerWattMilli = "Miliwatt" UnitPowerWattMicro = "Microwatt" -UnitElectricChargeMenu = "Electric charge" +UnitElectricChargeMenu = "Carga elétrica" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "Electric potential" +UnitPotentialMenu = "Potência elétrica" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" -UnitPotentialVoltMilli = "Millivolt" +UnitPotentialVoltMilli = "Milivolt" UnitPotentialVoltMicro = "Microvolt" -UnitCapacitanceMenu = "Electrical capacitance" +UnitCapacitanceMenu = "Capacidade elétrica" UnitCapacitanceFarad = "Farad" -UnitCapacitanceFaradMilli = "Millifarad" +UnitCapacitanceFaradMilli = "Milifarad" UnitCapacitanceFaradMicro = "Microfarad" -UnitResistanceMenu = "Electrical resistance" +UnitResistanceMenu = "Resistência elétrica" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "Electrical conductance" +UnitConductanceMenu = "Condutância elétrica" UnitConductanceSiemens = "Siemens" -UnitConductanceSiemensMilli = "Millisiemens" -UnitMagneticFieldMenu = "Magnetic field" +UnitConductanceSiemensMilli = "Milisiemens" +UnitMagneticFieldMenu = "Campo magnético" UnitMagneticFieldTesla = "Tesla" -InductanceMenu = "Electrical inductance" +InductanceMenu = "Indutância" UnitInductanceHenry = "Henry" -UnitSurfaceMenu = "Area" +UnitSurfaceMenu = "Área" UnitSurfaceHectar = "Hectare" UnitVolumeMenu = "Volume" -UnitVolumeLiter = "Liter" -UnitVolumeLiterDeci = "Deciliter" -UnitVolumeLiterCenti = "Centiliter" -UnitVolumeLiterMilli = "Milliliter" +UnitVolumeLiter = "Litro" +UnitVolumeLiterDeci = "Decilitro" +UnitVolumeLiterCenti = "Centilitro" +UnitVolumeLiterMilli = "Mililitro" Toolbox = "Caixa de ferramentas" AbsoluteValue = "Valor absoluto" -NthRoot = "Radiciacao" +NthRoot = "Raiz de índice n" BasedLogarithm = "Logaritmo na base a" Calculation = "Cálculo" ComplexNumber = "Números complexos" -Combinatorics = "Combinatoria" +Combinatorics = "Combinatória" Arithmetic = "Aritmética" Matrices = "Matrizes" NewMatrix = "Nova matriz" @@ -140,7 +140,7 @@ Maximum = "Máximo" Minimum = "Mínimo" Floor = "Parte inteira" FracPart = "Parte fraccionaria" -Ceiling = "Tecto" +Ceiling = "Teto" Rounding = "Arredondar" HyperbolicCosine = "Cosseno hiperbólico" HyperbolicSine = "Seno hiperbólico" From 4802299f3cfc30cc9ec87d74e8cf7d2c5acdc008 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 17:46:08 +0100 Subject: [PATCH 092/453] [pt] corrected regression and sequences --- apps/regression/base.pt.i18n | 4 ++-- apps/sequence/base.pt.i18n | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/regression/base.pt.i18n b/apps/regression/base.pt.i18n index 4ff5a3eaf..e5db50f79 100644 --- a/apps/regression/base.pt.i18n +++ b/apps/regression/base.pt.i18n @@ -2,13 +2,13 @@ RegressionApp = "Regressão" RegressionAppCapital = "REGRESSÃO" Regression = "Regressão" Reg = "reg" -MeanDot = "media" +MeanDot = "média" RegressionCurve = "Curva de regressão" XPrediction = "Predição dado X" YPrediction = "Predição dado Y" ValueNotReachedByRegression = "Valor não alcançado nesta janela" NumberOfDots = "Número de pontos" -Covariance = "Covariancia" +Covariance = "Covariância" Linear = "Linear" Proportional = "Proporcional" Quadratic = "Quadrática" diff --git a/apps/sequence/base.pt.i18n b/apps/sequence/base.pt.i18n index cb0d9caec..97f6580f8 100644 --- a/apps/sequence/base.pt.i18n +++ b/apps/sequence/base.pt.i18n @@ -1,5 +1,5 @@ -SequenceApp = "Sequência" -SequenceAppCapital = "SEQUÊNCIA" +SequenceApp = "Sequências" +SequenceAppCapital = "SEQUÊNCIAS" SequenceTab = "Sequências" AddSequence = "Adicionar uma sequência" ChooseSequenceType = "Escolha o tipo de sequência" @@ -11,7 +11,7 @@ SequenceOptions = "Opções de sequência" SequenceColor = "Cor da sequência" DeleteSequence = "Eliminar a sequência" NoSequence = "Sem sequência" -NoActivatedSequence = "Sem sequência activada" +NoActivatedSequence = "Sem sequência ativada" NStart = "N início" NEnd = "N fim" TermSum = "Soma dos termos" From e880dfe4b431d3e2c2d9a76061eaa3e5ee3bb037 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Thu, 12 Mar 2020 17:55:42 +0100 Subject: [PATCH 093/453] [pt] corrected base --- apps/on_boarding/base.pt.i18n | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/on_boarding/base.pt.i18n b/apps/on_boarding/base.pt.i18n index db822f4b6..c99440636 100644 --- a/apps/on_boarding/base.pt.i18n +++ b/apps/on_boarding/base.pt.i18n @@ -1,13 +1,13 @@ UpdateAvailable = "ATUALIZAÇÃO DISPONÍVEL" UpdateMessage1 = "Existem melhorias significativas" UpdateMessage2 = "para a sua calculadora." -UpdateMessage3 = "Navegue na nossa página do seu computador" +UpdateMessage3 = "Navegue na nossa página no seu computador" UpdateMessage4 = "www.numworks.com/update" BetaVersion = "BETA VERSION" BetaVersionMessage1 = "" -BetaVersionMessage2 = "Your device runs a beta software." -BetaVersionMessage3 = "You might run into bugs or glitches." +BetaVersionMessage2 = "O seu dispositivo está a executar um software beta." +BetaVersionMessage3 = "Pode encontrar bugs ou falhas." BetaVersionMessage4 = "" -BetaVersionMessage5 = "Please send any feedback to" +BetaVersionMessage5 = "Por favor envie-nos o seu feedback para" BetaVersionMessage6 = "contact@numworks.com" -Skip = "Pular" +Skip = "Saltar" From 7aecec705ef12e867c959d0167f0b10a2bf7b932 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Fri, 13 Mar 2020 15:53:49 +0100 Subject: [PATCH 094/453] [pt] shorten too long lines and other details --- apps/code/catalog.pt.i18n | 26 +++++++++++++------------- apps/settings/base.pt.i18n | 6 +++--- apps/shared.pt.i18n | 2 +- apps/toolbox.pt.i18n | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 428ab928f..d991fb104 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -41,11 +41,11 @@ PythonEval = "Devolve a expressão avaliada" PythonExp = "Função exponencial" PythonExpm1 = "Calcular exp(x)-1" PythonFabs = "Valor absoluto" -PythonFillRect = "Preenche um retângulo no pixel (x,y)" +PythonFillRect = "Preencher um retângulo em (x,y)" PythonFloat = "Converter x num flutuante" PythonFloor = "Parte inteira" PythonFmod = "a módulo b" -PythonFrExp = "Coeficiente e expoente de x" +PythonFrExp = "Coeficiente e expoente de x: (m, e)" PythonGamma = "Função gama" PythonGetPixel = "Devolve a cor do pixel (x,y)" PythonGetrandbits = "Número inteiro aleatório com k bits" @@ -64,12 +64,12 @@ PythonIndex = "Índice da primeira ocorrência de x" PythonInput = "Adicionar um valor" PythonInsert = "Inserir x no índice i na lista" PythonInt = "Converter x num número inteiro" -PythonIonFunction = "Prefixo da função módulo ion" +PythonIonFunction = "Prefixo da função do módulo ion" PythonIsFinite = "Verificar se x é finito" PythonIsInfinite = "Verificar se x é infinito" -PythonIsKeyDown = "Devolve True se a tecla k for pressionada" +PythonIsKeyDown = "Devolve True se tecla k pressionada" PythonIsNaN = "Verificar se x é um NaN" -PythonKandinskyFunction = "Prefixo da função módulo kandinsky" +PythonKandinskyFunction = "Prefixo da função do módulo kandinsky" PythonKeyLeft = "tecla SETA ESQUERDA" PythonKeyUp = "tecla SETA CIMA " PythonKeyDown = "tecla SETA BAIXO" @@ -122,7 +122,7 @@ PythonLgamma = "Logaritmo da função gama" PythonLog = "Logaritmo de base a" PythonLog10 = "Logaritmo de base 10" PythonLog2 = "Logaritmo de base 2" -PythonMathFunction = "Prefixo do módulo da função math" +PythonMathFunction = "Prefixo da função do módulo math" PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" PythonMax = "Máximo" PythonMin = "Mínimo" @@ -138,8 +138,8 @@ PythonPrint = "Mostrar o objeto" PythonRadians = "Converter x de graus para radianos" PythonRandint = "Número inteiro aleatório em [a,b]" PythonRandom = "Número decimal em [0,1[" -PythonRandomFunction = "Prefixo do módulo da função random" -PythonRandrange = "Número aleatório no intervalo (start,stop)" +PythonRandomFunction = "Prefixo da função do módulo random" +PythonRandrange = "Número aleatório em [start,stop-1]" PythonRangeStartStop = "Lista de start a stop-1" PythonRangeStop = "Lista de 0 a stop-1" PythonRect = "z em coordenadas cartesianas" @@ -147,7 +147,7 @@ PythonRemove = "Remover a primeira ocorrência de x" PythonReverse = "Inverter os elementos da lista" PythonRound = "Arredondar para n dígitos" PythonScatter = "Draw a scatter plot of y versus x" -PythonSeed = "Iniciar gerador aleatório de números" +PythonSeed = "Iniciar gerador aleatório" PythonSetPixel = "Cor do pixel (x,y)" PythonShow = "Display the figure" PythonSin = "Seno" @@ -159,23 +159,23 @@ PythonSum = "Soma dos itens da lista" PythonTan = "Tangente" PythonTanh = "Tangente hiperbólica" PythonText = "Display a text at (x,y) coordinates" -PythonTimeFunction = "Prefixo da função módulo time" +PythonTimeFunction = "Prefixo da função do módulo time" PythonTrunc = "x truncado a um número inteiro" PythonTurtleBackward = "Recuar x pixels" PythonTurtleBlack = "Cor preta" PythonTurtleBlue = "Cor azul" PythonTurtleBrown = "Cor castanha" -PythonTurtleCircle = "Desenhar uma circunferência de raio r pixels" +PythonTurtleCircle = "Circunferência de raio r pixels" PythonTurtleColor = "Definir a cor da caneta" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" PythonTurtleForward = "Avançar x pixels" -PythonTurtleFunction = "Prefixo da função módulo turtle" +PythonTurtleFunction = "Prefixo da função do módulo turtle" PythonTurtleGoto = "Ir paras as coordenadas (x,y)" PythonTurtleGreen = "Cor verde" PythonTurtleGrey = "Cor cinzenta" PythonTurtleHeading = "Voltar para a orientação atual" PythonTurtleHideturtle = "Esconder o turtle" -PythonTurtleIsdown = "Devolve True se a caneta está pressionada" +PythonTurtleIsdown = "True se a caneta está pressionada" PythonTurtleLeft = "Vira à esquerda por a graus" PythonTurtleOrange = "Cor laranja" PythonTurtlePendown = "Puxar a caneta para baixo" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index ef3f5c451..c46e9265a 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -12,9 +12,9 @@ ToDeactivateExamMode1 = "Para desativar o modo de exame," ToDeactivateExamMode2 = "ligue a calculadora a um computador" ToDeactivateExamMode3 = "ou a uma tomada elétrica." # --------------------- Please do not edit these messages --------------------- -ExamModeWarning1 = "Cuidado: a conformidade do" -ExamModeWarning2 = "modo exame deste software não oficial" -ExamModeWarning3 = "não é garantida pela NumWorks." +ExamModeWarning1 = "Cuidado: o software que está a utilizar" +ExamModeWarning2 = "não é oficial. A sua conformidade com o" +ExamModeWarning3 = "Modo de Exame não é garantida pela NumWorks." AboutWarning1 = "Cuidado: está a usar uma" AboutWarning2 = "versão não oficial do software." AboutWarning3 = "A NumWorks não pode ser responsável" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index b1f1261b8..7dced5099 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -27,7 +27,7 @@ FillWithFormula = "Preencher com uma fórmula" ForbiddenValue = "Valor proibido" FunctionColumn = "Coluna 0(0)" FunctionOptions = "Opções de função" -Goto = "Ir a" +Goto = "Ir para" GraphTab = "Gráfico" HardwareTestLaunch1 = "Vai executar o teste da planta." HardwareTestLaunch2 = "Para sair tem que executar" diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 37e91706b..92b497134 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -41,7 +41,7 @@ UnitAmountMoleMilli = "Milimole" UnitAmountMoleMicro = "Micromole" UnitLuminousIntensityMenu = "Intensidade luminosa" UnitLuminousIntensityCandela = "Candela" -UnitFrequencyMenu = "Frequency" +UnitFrequencyMenu = "Frequência" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" @@ -133,7 +133,7 @@ Inverse = "Matriz inversa" Determinant = "Determinante" Transpose = "Matriz transposta" Trace = "Traço" -Dimension = "Tamanho" +Dimension = "Dimensão" Sort = "Ordem crescente" InvSort = "Ordem decrescente" Maximum = "Máximo" From b1e8f65a67047dd2da736b948b23354afa4df03d Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Fri, 13 Mar 2020 16:07:20 +0100 Subject: [PATCH 095/453] [pt] corrected typo --- apps/toolbox.pt.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 92b497134..6660625a9 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -29,7 +29,7 @@ UnitMassGramMilli = "Miligrama" UnitMassGramMicro = "Micrograma" UnitMassGramNano = "Nanograma" UnitMassTonne = "Tonelada" -UnitCurrentMenu = "Intensiadade da currente elétrica" +UnitCurrentMenu = "Intensidade da currente elétrica" UnitCurrentAmpere = "Ampere" UnitCurrentAmpereMilli = "Miliampere" UnitCurrentAmpereMicro = "Microampere" From 834a8784c95d2e7a5a350a1640c58286c289d8cb Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Fri, 13 Mar 2020 16:41:15 +0100 Subject: [PATCH 096/453] [pt] chaged settings name --- apps/settings/base.pt.i18n | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index c46e9265a..5117db576 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -1,5 +1,5 @@ -SettingsApp = "Configuração" -SettingsAppCapital = "CONFIGURAÇÃO" +SettingsApp = "Definições" +SettingsAppCapital = "DEFINIÇÕES" AngleUnit = "Valor do ângulo" DisplayMode = "Formato numérico" EditionMode = "Formato escrita " From 3ef28ec155469c9a8b9706de413e886caaf040a0 Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 10 Mar 2020 17:32:49 +0100 Subject: [PATCH 097/453] [it] new translation files --- apps/calculation/base.it.i18n | 9 ++ apps/code/base.it.i18n | 8 ++ apps/code/catalog.it.i18n | 185 ++++++++++++++++++++++++++++++++ apps/code/toolbox.it.i18n | 4 + apps/graph/base.it.i18n | 33 ++++++ apps/home/base.it.i18n | 4 + apps/language_it.universal.i18n | 1 + apps/on_boarding/base.it.i18n | 13 +++ apps/probability/base.it.i18n | 27 +++++ apps/regression/base.it.i18n | 21 ++++ apps/sequence/base.it.i18n | 22 ++++ apps/settings/base.it.i18n | 41 +++++++ apps/shared.it.i18n | 81 ++++++++++++++ apps/solver/base.it.i18n | 29 +++++ apps/statistics/base.it.i18n | 25 +++++ apps/toolbox.it.i18n | 167 ++++++++++++++++++++++++++++ apps/usb/base.it.i18n | 7 ++ apps/variables.it.i18n | 10 ++ 18 files changed, 687 insertions(+) create mode 100644 apps/calculation/base.it.i18n create mode 100644 apps/code/base.it.i18n create mode 100644 apps/code/catalog.it.i18n create mode 100644 apps/code/toolbox.it.i18n create mode 100644 apps/graph/base.it.i18n create mode 100644 apps/home/base.it.i18n create mode 100644 apps/language_it.universal.i18n create mode 100644 apps/on_boarding/base.it.i18n create mode 100644 apps/probability/base.it.i18n create mode 100644 apps/regression/base.it.i18n create mode 100644 apps/sequence/base.it.i18n create mode 100644 apps/settings/base.it.i18n create mode 100644 apps/shared.it.i18n create mode 100644 apps/solver/base.it.i18n create mode 100644 apps/statistics/base.it.i18n create mode 100644 apps/toolbox.it.i18n create mode 100644 apps/usb/base.it.i18n create mode 100644 apps/variables.it.i18n diff --git a/apps/calculation/base.it.i18n b/apps/calculation/base.it.i18n new file mode 100644 index 000000000..ca8e28739 --- /dev/null +++ b/apps/calculation/base.it.i18n @@ -0,0 +1,9 @@ +CalculApp = "Calculs" +CalculAppCapital = "CALCULS" +AdditionalResults = "Résultats complémentaires" +DecimalBase = "Décimal" +HexadecimalBase = "Hexadécimal" +BinaryBase = "Binaire" +PrimeFactors = "Facteurs premiers" +MixedFraction = "Fraction mixte" +EuclideanDivision = "Division euclidienne" diff --git a/apps/code/base.it.i18n b/apps/code/base.it.i18n new file mode 100644 index 000000000..253989ab2 --- /dev/null +++ b/apps/code/base.it.i18n @@ -0,0 +1,8 @@ +Console = "Console d'exécution" +AddScript = "Ajouter un script" +ScriptOptions = "Options de script" +ExecuteScript = "Exécuter le script" +AutoImportScript = "Importation auto dans la console" +DeleteScript = "Supprimer le script" +FunctionsAndVariables = "Fonctions et variables" +AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n new file mode 100644 index 000000000..5f6bc9416 --- /dev/null +++ b/apps/code/catalog.it.i18n @@ -0,0 +1,185 @@ +PythonPound = "Comment" +PythonPercent = "Modulo" +Python1J = "Imaginary i" +PythonLF = "Line feed" +PythonTab = "Tabulation" +PythonAmpersand = "Bitwise and" +PythonSymbolExp = "Bitwise exclusive or" +PythonVerticalBar = "Bitwise or" +PythonImag = "Imaginary part of z" +PythonReal = "Real part of z" +PythonSingleQuote = "Single quote" +PythonAbs = "Absolute value/Magnitude" +PythonAcos = "Arc cosine" +PythonAcosh = "Arc hyperbolic cosine" +PythonAppend = "Add x to the end of the list" +PythonAsin = "Arc sine" +PythonAsinh = "Arc hyperbolic sine" +PythonAtan = "Arc tangent" +PythonAtan2 = "Return atan(y/x)" +PythonAtanh = "Arc hyperbolic tangent" +PythonBin = "Convert integer to binary" +PythonCeil = "Ceiling" +PythonChoice = "Random number in the list" +PythonClear = "Empty the list" +PythonCmathFunction = "cmath module function prefix" +PythonColor = "Define a rgb color" +PythonComplex = "Return a+ib" +PythonCopySign = "Return x with the sign of y" +PythonCos = "Cosine" +PythonCosh = "Hyperbolic cosine" +PythonCount = "Count the occurrences of x" +PythonDegrees = "Convert x from radians to degrees" +PythonDivMod = "Quotient and remainder" +PythonDrawString = "Display a text from pixel (x,y)" +PythonErf = "Error function" +PythonErfc = "Complementary error function" +PythonEval = "Return the evaluated expression" +PythonExp = "Exponential function" +PythonExpm1 = "Compute exp(x)-1" +PythonFabs = "Absolute value" +PythonFillRect = "Fill a rectangle at pixel (x,y)" +PythonFloat = "Convert x to a float" +PythonFloor = "Floor" +PythonFmod = "a modulo b" +PythonFrExp = "Mantissa and exponent of x" +PythonGamma = "Gamma function" +PythonGetPixel = "Return pixel (x,y) color" +PythonGetrandbits = "Integer with k random bits" +PythonHex = "Convert integer to hexadecimal" +PythonImportCmath = "Import cmath module" +PythonImportIon = "Import ion module" +PythonImportKandinsky = "Import kandinsky module" +PythonImportRandom = "Import random module" +PythonImportMath = "Import math module" +PythonImportTime = "Import time module" +PythonImportTurtle = "Import turtle module" +PythonIndex = "Index of the first x occurrence" +PythonInput = "Prompt a value" +PythonInsert = "Insert x at index i in the list" +PythonInt = "Convert x to an integer" +PythonIonFunction = "ion module function prefix" +PythonIsFinite = "Check if x is finite" +PythonIsInfinite = "Check if x is infinity" +PythonIsKeyDown = "Return True if the k key is down" +PythonIsNaN = "Check if x is a NaN" +PythonKandinskyFunction = "kandinsky module function prefix" +PythonKeyLeft = "LEFT ARROW key" +PythonKeyUp = "UP ARROW key" +PythonKeyDown = "DOWN ARROW key" +PythonKeyRight = "RIGHT ARROW key" +PythonKeyOk = "OK key" +PythonKeyBack = "BACK key" +PythonKeyHome = "HOME key" +PythonKeyOnOff = "ON/OFF key" +PythonKeyShift = "SHIFT key" +PythonKeyAlpha = "ALPHA key" +PythonKeyXnt = "X,N,T key" +PythonKeyVar = "VAR key" +PythonKeyToolbox = "TOOLBOX key" +PythonKeyBackspace = "BACKSPACE key" +PythonKeyExp = "EXPONENTIAL key" +PythonKeyLn = "NATURAL LOGARITHM key" +PythonKeyLog = "DECIMAL LOGARITHM key" +PythonKeyImaginary = "IMAGINARY I key" +PythonKeyComma = "COMMA key" +PythonKeyPower = "POWER key" +PythonKeySine = "SINE key" +PythonKeyCosine = "COSINE key" +PythonKeyTangent = "TANGENT key" +PythonKeyPi = "PI key" +PythonKeySqrt = "SQUARE ROOT key" +PythonKeySquare = "SQUARE key" +PythonKeySeven = "7 key" +PythonKeyEight = "8 key" +PythonKeyNine = "9 key" +PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" +PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" +PythonKeyFour = "4 key" +PythonKeyFive = "5 key" +PythonKeySix = "6 key" +PythonKeyMultiplication = "MULTIPLICATION key" +PythonKeyDivision = "DIVISION key" +PythonKeyOne = "1 key" +PythonKeyTwo = "2 key" +PythonKeyThree = "3 key" +PythonKeyPlus = "PLUS key" +PythonKeyMinus = "MINUS key" +PythonKeyZero = "0 key" +PythonKeyDot = "DOT key" +PythonKeyEe = "10 POWER X key" +PythonKeyAns = "ANS key" +PythonKeyExe = "EXE key" +PythonLdexp = "Return x*(2**i), inverse of frexp" +PythonLength = "Length of an object" +PythonLgamma = "Log-gamma function" +PythonLog = "Logarithm to base a" +PythonLog10 = "Logarithm to base 10" +PythonLog2 = "Logarithm to base 2" +PythonMathFunction = "math module function prefix" +PythonMax = "Maximum" +PythonMin = "Minimum" +PythonModf = "Fractional and integer parts of x" +PythonMonotonic = "Value of a monotonic clock" +PythonOct = "Convert integer to octal" +PythonPhase = "Phase of z" +PythonPolar = "z in polar coordinates" +PythonPop = "Remove and return the last item" +PythonPower = "x raised to the power y" +PythonPrint = "Print object" +PythonRadians = "Convert x from degrees to radians" +PythonRandint = "Random integer in [a,b]" +PythonRandom = "Floating point number in [0,1[" +PythonRandomFunction = "random module function prefix" +PythonRandrange = "Random number in range(start, stop)" +PythonRangeStartStop = "List from start to stop-1" +PythonRangeStop = "List from 0 to stop-1" +PythonRect = "z in cartesian coordinates" +PythonRemove = "Remove the first occurrence of x" +PythonReverse = "Reverse the elements of the list" +PythonRound = "Round to n digits" +PythonSeed = "Initialize random number generator" +PythonSetPixel = "Color pixel (x,y)" +PythonSin = "Sine" +PythonSinh = "Hyperbolic sine" +PythonSleep = "Suspend the execution for t seconds" +PythonSort = "Sort the list" +PythonSqrt = "Square root" +PythonSum = "Sum the items of a list" +PythonTan = "Tangent" +PythonTanh = "Hyperbolic tangent" +PythonTimeFunction = "time module function prefix" +PythonTrunc = "x truncated to an integer" +PythonTurtleBackward = "Move backward by x pixels" +PythonTurtleBlack = "Black color" +PythonTurtleBlue = "Blue color" +PythonTurtleBrown = "Brown color" +PythonTurtleCircle = "Circle of radius r pixels" +PythonTurtleColor = "Set the pen color" +PythonTurtleColorMode = "Set the color mode to 1.0 or 255" +PythonTurtleForward = "Move forward by x pixels" +PythonTurtleFunction = "turtle module function prefix" +PythonTurtleGoto = "Move to (x,y) coordinates" +PythonTurtleGreen = "Green color" +PythonTurtleGrey = "Grey color" +PythonTurtleHeading = "Return the current heading" +PythonTurtleHideturtle = "Hide the turtle" +PythonTurtleIsdown = "Return True if the pen is down" +PythonTurtleLeft = "Turn left by a degrees" +PythonTurtleOrange = "Orange color" +PythonTurtlePendown = "Pull the pen down" +PythonTurtlePensize = "Set the line thickness to x pixels" +PythonTurtlePenup = "Pull the pen up" +PythonTurtlePink = "Pink color" +PythonTurtlePosition = "Return the current (x,y) location" +PythonTurtlePurple = "Purple color" +PythonTurtleRed = "Red color" +PythonTurtleReset = "Reset the drawing" +PythonTurtleRight = "Turn right by a degrees" +PythonTurtleSetheading = "Set the orientation to a degrees" +PythonTurtleSetposition = "Positionne la tortue" +PythonTurtleShowturtle = "Show the turtle" +PythonTurtleSpeed = "Drawing speed between 0 and 10" +PythonTurtleWhite = "White color" +PythonTurtleYellow = "Yellow color" +PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/toolbox.it.i18n b/apps/code/toolbox.it.i18n new file mode 100644 index 000000000..6442521cc --- /dev/null +++ b/apps/code/toolbox.it.i18n @@ -0,0 +1,4 @@ +Functions = "Fonctions" +Catalog = "Catalogue" +Modules = "Modules" +LoopsAndTests = "Boucles et tests" diff --git a/apps/graph/base.it.i18n b/apps/graph/base.it.i18n new file mode 100644 index 000000000..d95a5ae63 --- /dev/null +++ b/apps/graph/base.it.i18n @@ -0,0 +1,33 @@ +FunctionApp = "Fonctions" +FunctionAppCapital = "FONCTIONS" +FunctionTab = "Fonctions" +AddFunction = "Ajouter une fonction" +DeleteFunction = "Supprimer la fonction" +CurveType = "Type de courbe" +CartesianType = "Cartésien " +PolarType = "Polaire " +ParametricType = "Paramétrique " +IntervalT = "Intervalle t" +IntervalTheta = "Intervalle θ" +IntervalX = "Intervalle x" +FunctionDomain = "Domaine de tracé" +FunctionColor = "Couleur de la fonction" +NoFunction = "Aucune fonction" +NoActivatedFunction = "Aucune fonction activée" +PlotOptions = "Options de la courbe" +Compute = "Calculer" +Zeros = "Zéros" +Tangent = "Tangente" +Intersection = "Intersection" +Preimage = "Antécédent" +SelectLowerBound = "Sélectionner la borne inférieure" +SelectUpperBound = "Sélectionner la borne supérieure" +NoMaximumFound = "Aucun maximum trouvé" +NoMinimumFound = "Aucun minimum trouvé" +NoZeroFound = "Aucun zéro trouvé" +NoIntersectionFound = "Aucune intersection trouvée" +NoPreimageFound = "Aucun antécédent trouvé" +DerivativeFunctionColumn = "Colonne de la fonction dérivée" +HideDerivativeColumn = "Masquer la fonction dérivée" +AllowedCharactersAZaz09 = "Caractères autorisés : A-Z, a-z, 0-9, _" +ReservedName = "Nom réservé" diff --git a/apps/home/base.it.i18n b/apps/home/base.it.i18n new file mode 100644 index 000000000..158fa3bda --- /dev/null +++ b/apps/home/base.it.i18n @@ -0,0 +1,4 @@ +Apps = "Applications" +AppsCapital = "APPLICATIONS" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/language_it.universal.i18n b/apps/language_it.universal.i18n new file mode 100644 index 000000000..5914a13e6 --- /dev/null +++ b/apps/language_it.universal.i18n @@ -0,0 +1 @@ +LanguageIT = "Italiano " diff --git a/apps/on_boarding/base.it.i18n b/apps/on_boarding/base.it.i18n new file mode 100644 index 000000000..fdd2dca84 --- /dev/null +++ b/apps/on_boarding/base.it.i18n @@ -0,0 +1,13 @@ +UpdateAvailable = "MISE À JOUR DISPONIBLE" +UpdateMessage1 = "Des améliorations importantes existent" +UpdateMessage2 = "pour votre calculatrice." +UpdateMessage3 = "Connectez-vous depuis votre ordinateur" +UpdateMessage4 = "www.numworks.com/update" +BetaVersion = "VERSION BÊTA" +BetaVersionMessage1 = "Votre appareil dispose d'une version bêta" +BetaVersionMessage2 = "du logiciel. Il est possible que certains" +BetaVersionMessage3 = "bugs apparaissent." +BetaVersionMessage4 = "Vous pouvez nous écrire pour nous" +BetaVersionMessage5 = "faire part de vos retours à" +BetaVersionMessage6 = "contact@numworks.com" +Skip = "Passer" diff --git a/apps/probability/base.it.i18n b/apps/probability/base.it.i18n new file mode 100644 index 000000000..056fa00f6 --- /dev/null +++ b/apps/probability/base.it.i18n @@ -0,0 +1,27 @@ +ProbaApp = "Probabilités" +ProbaAppCapital = "PROBABILITÉS" +ChooseDistribution = "Choisir le type de loi" +Binomial = "Binomiale" +Geometric = "Géométrique" +Uniforme = "Uniforme" +Normal = "Normale" +ChiSquared = "Chi2" +UniformDistribution = "Loi uniforme" +ExponentialDistribution = "Loi exponentielle" +GeometricDistribution = "Loi géométrique" +PoissonDistribution = "Loi de Poisson" +ChiSquaredDistribution = "Loi du chi2" +StudentDistribution = "Loi de Student" +FisherDistribution = "Loi de Fisher" +ChooseParameters = "Choisir les paramètres" +RepetitionNumber = "n : Nombre de répétitions" +SuccessProbability = "p : Probabilité de succès" +IntervalDefinition = "[a,b] : Intervalle" +LambdaExponentialDefinition = "λ : Paramètre" +MeanDefinition = "μ : Espérance ou moyenne" +DeviationDefinition = "σ : Écart type" +LambdaPoissonDefinition = "λ : Paramètre" +DegreesOfFreedomDefinition = "k : Degrés de liberté" +D1FisherDefinition = "d1 : Degrés de liberté du numérateur" +D2FisherDefinition = "d2 : Degrés de liberté du dénominateur" +ComputeProbability = "Calculer les probabilités" diff --git a/apps/regression/base.it.i18n b/apps/regression/base.it.i18n new file mode 100644 index 000000000..3339f6901 --- /dev/null +++ b/apps/regression/base.it.i18n @@ -0,0 +1,21 @@ +RegressionApp = "Régressions" +RegressionAppCapital = "RÉGRESSIONS" +Regression = "Régression" +Reg = "reg" +MeanDot = "moyen" +RegressionCurve = "Courbe de régression" +XPrediction = "Prédiction sachant X" +YPrediction = "Prédiction sachant Y" +ValueNotReachedByRegression = "Valeur non atteinte dans cette fenêtre" +NumberOfDots = "Nombre de points" +Covariance = "Covariance" +Linear = "Linéaire" +Proportional = "Proporzionale" +Quadratic = "Quadratique" +Cubic = "Cubique" +Quartic = "Quartique" +Logarithmic = "Logarithmique" +Power = "Puissance" +Trigonometrical = "Trigonométrique" +Logistic = "Logistique" +DataNotSuitableForRegression = "Les données ne conviennent pas" diff --git a/apps/sequence/base.it.i18n b/apps/sequence/base.it.i18n new file mode 100644 index 000000000..3772efb47 --- /dev/null +++ b/apps/sequence/base.it.i18n @@ -0,0 +1,22 @@ +SequenceApp = "Suites" +SequenceAppCapital = "SUITES" +SequenceTab = "Suites" +AddSequence = "Ajouter une suite" +ChooseSequenceType = "Choisir le type de suite" +SequenceType = "Type de suite" +Explicit = "Explicite" +SingleRecurrence = "Récurrente d'ordre 1" +DoubleRecurrence = "Récurrente d'ordre 2" +SequenceOptions = "Options de la suite" +SequenceColor = "Couleur de la suite" +DeleteSequence = "Supprimer la suite" +NoSequence = "Aucune suite" +NoActivatedSequence = "Aucune suite activée" +NStart = "N début" +NEnd = "N fin" +TermSum = "Somme des termes" +SelectFirstTerm = "Sélectionner le premier terme " +SelectLastTerm = "Sélectionner le dernier terme " +ValueNotReachedBySequence = "Valeur non atteinte par la suite" +NColumn = "Colonne n" +FirstTermIndex = "Indice premier terme" diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n new file mode 100644 index 000000000..389710fad --- /dev/null +++ b/apps/settings/base.it.i18n @@ -0,0 +1,41 @@ +SettingsApp = "Paramètres" +SettingsAppCapital = "PARAMÈTRES" +AngleUnit = "Unité d'angle" +DisplayMode = "Format résultat" +EditionMode = "Format écriture" +EditionLinear = "En ligne " +Edition2D = "Naturelle " +ComplexFormat = "Forme complexe" +ExamMode = "Mode examen" +ExamModeActive = "Réactiver le mode examen" +ToDeactivateExamMode1 = "Pour désactiver le mode examen," +ToDeactivateExamMode2 = "brancher la calculatrice à un" +ToDeactivateExamMode3 = "ordinateur ou à une prise de courant." +# --------------------- Please do not edit these messages --------------------- +ExamModeWarning1 = "Attention, la conformité du mode" +ExamModeWarning2 = "examen de ce logiciel non officiel" +ExamModeWarning3 = "n'est pas garantie par NumWorks." +AboutWarning1 = "Attention, vous utilisez une version" +AboutWarning2 = "non officielle du logiciel. NumWorks" +AboutWarning3 = "ne saurait être tenu responsable des" +AboutWarning4 = "problèmes que cela pourrait entraîner." +# ----------------------------------------------------------------------------- +About = "À propos" +Degrees = "Degrés " +Gradians = "Grades " +Radian = "Radians " +Decimal = "Décimal " +Scientific = "Scientifique " +Engineering = "Ingénieur " +SignificantFigures = "Chiffres significatifs " +Real = "Réel " +Cartesian = "Algébrique " +Polar = "Exponentielle " +Brightness = "Luminosité" +FontSizes = "Police Python" +LargeFont = "Grand " +SmallFont = "Petit " +SoftwareVersion = "Version du logiciel" +SerialNumber = "Numéro série" +UpdatePopUp = "Rappel mise à jour" +BetaPopUp = "Rappel version bêta" diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n new file mode 100644 index 000000000..22842405f --- /dev/null +++ b/apps/shared.it.i18n @@ -0,0 +1,81 @@ +ActivateDeactivate = "Activer/Désactiver" +ActivateExamMode = "Activer le mode examen" +ActivateDutchExamMode = "Activate Dutch exam mode" +ActiveExamModeMessage1 = "Toutes vos données seront " +ActiveExamModeMessage2 = "supprimées si vous activez " +ActiveExamModeMessage3 = "le mode examen." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." +Axis = "Axes" +Cancel = "Annuler" +ClearColumn = "Effacer la colonne" +ColumnOptions = "Options de la colonne" +CopyColumnInList = "Copier la colonne dans une liste" +DataNotSuitable = "Les données ne conviennent pas" +DataTab = "Données" +DefaultSetting = "Réglages de base" +Deg = "deg" +Deviation = "Variance" +DisplayValues = "Afficher les valeurs" +Empty = "Vide" +Eng = "ing" +ExitExamMode1 = "Voulez-vous sortir " +ExitExamMode2 = "du mode examen ?" +Exponential = "Exponentielle" +FillWithFormula = "Remplir avec une formule" +ForbiddenValue = "Valeur interdite" +FunctionColumn = "Colonne 0(0)" +FunctionOptions = "Options de la fonction" +Goto = "Aller à" +GraphTab = "Graphique" +HardwareTestLaunch1 = "Vous allez lancer le test usine." +HardwareTestLaunch2 = "Pour en sortir vous devrez" +HardwareTestLaunch3 = "appuyer sur le bouton reset" +HardwareTestLaunch4 = "ce qui supprimera vos données." +Initialization = "Initialisation" +IntervalSet = "Régler l'intervalle" +Language = "Langue" +LowBattery = "Batterie faible" +Mean = "Moyenne" +Move = " Déplacer : " +NameCannotStartWithNumber = "Un nom ne peut pas commencer par un chiffre" +NameTaken = "Ce nom est déjà utilisé" +NameTooLong = "Ce nom est trop long" +Next = "Suivant" +NEnd = "N fin" +NoDataToPlot = "Aucune donnée à tracer" +NoFunctionToDelete = "Pas de fonction à supprimer" +NoValueToCompute = "Aucune grandeur à calculer" +NStart = "N début" +Ok = "Valider" +Or = " ou " +Orthonormal = "Orthonormé" +Plot = "Tracer le graphique" +PoolMemoryFull1 = "La mémoire de travail est pleine." +PoolMemoryFull2 = "Réessayez." +Rad = "rad" +Rename = "Renommer" +RoundAbscissa = "Abscisses entières" +Sci = "sci" +SquareSum = "Somme des carrés" +StandardDeviation = "Écart type" +StatTab = "Stats" +Step = "Pas" +StorageMemoryFull1 = "La mémoire est pleine." +StorageMemoryFull2 = "Effacez des données et réessayez." +StoreExpressionNotAllowed = "'store' n'est pas autorisé" +SyntaxError = "Attention à la syntaxe" +TEnd = "T fin" +ThetaEnd = "θ fin" +ThetaStart = "θ début" +TStart = "T début" +ToZoom = "Zoomer : " +Trigonometric = "Trigonométrique" +UndefinedValue = "Valeur non définie" +ValueNotReachedByFunction = "Valeur non atteinte par la fonction" +ValuesTab = "Tableau" +Warning = "Attention" +XEnd = "X fin" +XStart = "X début" +Zoom = "Zoom" diff --git a/apps/solver/base.it.i18n b/apps/solver/base.it.i18n new file mode 100644 index 000000000..c337a0525 --- /dev/null +++ b/apps/solver/base.it.i18n @@ -0,0 +1,29 @@ +SolverApp = "Équations" +SolverAppCapital = "ÉQUATIONS" +AddEquation = "Ajouter une équation" +ResolveEquation = "Résoudre l'équation" +ResolveSystem = "Résoudre le système" +UseEquationModel = "Utiliser un modèle d'équation" +RequireEquation = "L'entrée doit être une équation" +UndefinedEquation = "Une équation est indéfinie" +UnrealEquation = "Une équation n'est pas réelle" +TooManyVariables = "Le nombre d'inconnues est trop grand" +NonLinearSystem = "Le système n'est pas linéaire" +Solution = "Solution" +ApproximateSolution = "Solution approchée" +SearchInverval = "Intervalle de recherche" +NoSolutionSystem = "Le système n'admet aucune solution" +NoSolutionEquation = "L'équation n'admet aucune solution" +NoSolutionInterval = "Aucune solution trouvée dans cet intervalle" +EnterEquation = "Entrez une équation" +InfiniteNumberOfSolutions = "Le système admet une infinité de solutions" +ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" +ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée" +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" +PolynomeHasNoRealSolution0 = "Le polynôme n'admet pas" +PolynomeHasNoRealSolution1 = "de racine réelle" +PredefinedVariablesUsedLeft = "Variable" +PredefinedVariablesUsedRight = "s prédéfinies utilisées" +PredefinedVariablesIgnoredLeft = "Variable" +PredefinedVariablesIgnoredRight = "s prédéfinies ignorées" diff --git a/apps/statistics/base.it.i18n b/apps/statistics/base.it.i18n new file mode 100644 index 000000000..f90b4d60b --- /dev/null +++ b/apps/statistics/base.it.i18n @@ -0,0 +1,25 @@ +StatsApp = "Statistiques" +StatsAppCapital = "STATISTIQUES" +HistogramTab = "Histogramme" +BoxTab = "Boîte" +Values1 = "Valeurs V1" +Values2 = "Valeurs V2" +Values3 = "Valeurs V3" +Sizes1 = "Effectifs N1" +Sizes2 = "Effectifs N2" +Sizes3 = "Effectifs N3" +ImportList = "Importer une liste" +Interval = " Intervalle " +Size = " Effectif" +Frequency = "Fréquence" +HistogramSet = "Réglage de l'histogramme" +RectangleWidth = "Largeur des rectangles" +BarStart = "Début de la série" +FirstQuartile = "Premier quartile" +Median = "Médiane" +ThirdQuartile = "Troisième quartile" +TotalSize = "Effectif total" +Range = "Étendue" +StandardDeviationSigma = "Écart type" +SampleStandardDeviationS = "Écart type échantillon" +InterquartileRange = "Écart interquartile" diff --git a/apps/toolbox.it.i18n b/apps/toolbox.it.i18n new file mode 100644 index 000000000..0a67a6b24 --- /dev/null +++ b/apps/toolbox.it.i18n @@ -0,0 +1,167 @@ +Unit = "Unités" +UnitTimeMenu = "Temps" +UnitTimeSecondMenu = "Seconde" +UnitTimeSecond = "Seconde" +UnitTimeSecondMilli = "Milliseconde" +UnitTimeSecondMicro = "Microseconde" +UnitTimeSecondNano = "Nanoseconde" +UnitTimeMinute = "Minute" +UnitTimeHour = "Heure" +UnitTimeDay = "Jour" +UnitTimeWeek = "Semaine" +UnitTimeMonth = "Mois" +UnitTimeYear = "Année" +UnitDistanceMenu = "Distance" +UnitDistanceMeterMenu = "Mètre" +UnitDistanceMeterKilo = "Kilomètre" +UnitDistanceMeter = "Mètre" +UnitDistanceMeterMilli = "Millimètre" +UnitDistanceMeterMicro = "Micromètre" +UnitDistanceMeterNano = "Nanomètre" +UnitDistanceMeterPico = "Picomètre" +UnitDistanceAstronomicalUnit = "Unité astronomique" +UnitDistanceLightYear = "Année lumière" +UnitDistanceParsec = "Parsec" +UnitMassMenu = "Masse" +UnitMassGramKilo = "Kilogramme" +UnitMassGram = "Gramme" +UnitMassGramMilli = "Milligramme" +UnitMassGramMicro = "Microgramme" +UnitMassGramNano = "Nanogramme" +UnitMassTonne = "Tonne" +UnitCurrentMenu = "Intensité du courant électrique" +UnitCurrentAmpere = "Ampère" +UnitCurrentAmpereMilli = "Milliampère" +UnitCurrentAmpereMicro = "Microampère" +UnitTemperatureMenu = "Température" +UnitTemperatureKelvin = "Kelvin" +UnitAmountMenu = "Quantité de matière" +UnitAmountMole = "Mole" +UnitAmountMoleMilli = "Millimole" +UnitAmountMoleMicro = "Micromole" +UnitLuminousIntensityMenu = "Intensité lumineuse" +UnitLuminousIntensityCandela = "Candela" +UnitFrequencyMenu = "Fréquence" +UnitFrequencyHertzGiga = "Gigahertz" +UnitFrequencyHertzMega = "Megahertz" +UnitFrequencyHertzKilo = "Kilohertz" +UnitFrequencyHertz = "Hertz" +UnitForceMenu = "Force" +UnitForceNewtonKilo = "Kilonewton" +UnitForceNewton = "Newton" +UnitForceNewtonMilli = "Millinewton" +UnitPressureMenu = "Pression" +UnitPressurePascal = "Pascal" +UnitPressurePascalHecto = "Hectopascal" +UnitPressureBar = "Bar" +UnitPressureAtm = "Atmosphère" +UnitEnergyMenu = "Énergie" +UnitEnergyJouleMenu = "Joule" +UnitEnergyJouleKilo = "Kilojoule" +UnitEnergyJoule = "Joule" +UnitEnergyJouleMilli = "Millijoule" +UnitEnergyEletronVoltMenu = "Electronvolt" +UnitEnergyElectronVoltMega = "Megaelectronvolt" +UnitEnergyElectronVoltKilo = "Kiloelectronvolt" +UnitEnergyElectronVolt = "Electronvolt" +UnitEnergyElectronVoltMilli = "Millielectronvolt" +UnitPowerMenu = "Puissance" +UnitPowerWattGiga = "Gigawatt" +UnitPowerWattMega = "Megawatt" +UnitPowerWattKilo = "Kilowatt" +UnitPowerWatt = "Watt" +UnitPowerWattMilli = "Milliwatt" +UnitPowerWattMicro = "Microwatt" +UnitElectricChargeMenu = "Charge électrique" +UnitChargeCoulomb = "Coulomb" +UnitPotentialMenu = "Tension électrique" +UnitPotentialVoltKilo = "Kilovolt" +UnitPotentialVolt = "Volt" +UnitPotentialVoltMilli = "Millivolt" +UnitPotentialVoltMicro = "Microvolt" +UnitCapacitanceMenu = "Capacité électrique" +UnitCapacitanceFarad = "Farad" +UnitCapacitanceFaradMilli = "Millifarad" +UnitCapacitanceFaradMicro = "Microfarad" +UnitResistanceMenu = "Résistance électrique" +UnitResistanceOhmKilo = "Kiloohm" +UnitResistanceOhm = "Ohm" +UnitConductanceMenu = "Conductance électrique" +UnitConductanceSiemens = "Siemens" +UnitConductanceSiemensMilli = "Millisiemens" +UnitMagneticFieldMenu = "Induction électromagnétique" +UnitMagneticFieldTesla = "Tesla" +InductanceMenu = "Inductance" +UnitInductanceHenry = "Henry" +UnitSurfaceMenu = "Superficie" +UnitSurfaceHectar = "Hectare" +UnitVolumeMenu = "Volume" +UnitVolumeLiter = "Litre" +UnitVolumeLiterDeci = "Decilitre" +UnitVolumeLiterCenti = "Centilitre" +UnitVolumeLiterMilli = "Millilitre" +Toolbox = "Boîte à outils" +AbsoluteValue = "Valeur absolue" +NthRoot = "Racine n-ième" +BasedLogarithm = "Logarithme base a" +Calculation = "Calcul" +ComplexNumber = "Nombres complexes" +Combinatorics = "Dénombrement" +Arithmetic = "Arithmétique" +Matrices = "Matrices" +NewMatrix = "Nouvelle matrice" +Identity = "Matrice identité de taille n" +Lists = "Listes" +HyperbolicTrigonometry = "Trigonométrie hyperbolique" +Fluctuation = "Intervalle de fluctuation" +DerivateNumber = "Nombre derivé" +Integral = "Intégrale" +Sum = "Somme" +Product = "Produit" +ComplexAbsoluteValue = "Module" +Agument = "Argument" +RealPart = "Partie réelle" +ImaginaryPart = "Partie imaginaire" +Conjugate = "Conjugué" +Combination = "k parmi n" +Permutation = "Arrangement" +GreatCommonDivisor = "PGCD" +LeastCommonMultiple = "PPCM" +Remainder = "Reste de la division de p par q" +Quotient = "Quotient de la division de p par q" +Inverse = "Inverse" +Determinant = "Déterminant" +Transpose = "Transposée" +Trace = "Trace" +Dimension = "Taille" +Sort = "Tri croissant" +InvSort = "Tri décroissant" +Maximum = "Maximum" +Minimum = "Minimum" +Floor = "Partie entière" +FracPart = "Partie fractionnaire" +Ceiling = "Plafond" +Rounding = "Arrondi à n décimales" +HyperbolicCosine = "Cosinus hyperbolique" +HyperbolicSine = "Sinus hyperbolique" +HyperbolicTangent = "Tangente hyperbolique" +InverseHyperbolicCosine = "Argument cosinus hyperbolique" +InverseHyperbolicSine = "Argument sinus hyperbolique" +InverseHyperbolicTangent = "Argument tangente hyperbolique" +Prediction95 = "Intervalle fluctuation 95% (Term)" +Prediction = "Intervalle fluctuation simple (2de)" +Confidence = "Intervalle de confiance" +RandomAndApproximation = "Aléatoire et approximation" +RandomFloat = "Nombre décimal dans [0,1[" +RandomInteger = "Entier aléatoire dans [a,b]" +PrimeFactorDecomposition = "Décomposition en facteurs premiers" +NormCDF = "P(X Date: Tue, 10 Mar 2020 17:50:53 +0100 Subject: [PATCH 098/453] [it] Add i18n files to Makefiles --- apps/Makefile | 3 + apps/calculation/Makefile | 1 + apps/calculation/base.it.i18n | 18 +- apps/code/Makefile | 3 + apps/code/base.it.i18n | 16 +- apps/code/catalog.en.i18n | 2 +- apps/code/catalog.it.i18n | 364 +++++++++++++++++----------------- apps/code/toolbox.it.i18n | 8 +- apps/graph/Makefile | 1 + apps/graph/base.it.i18n | 64 +++--- apps/home/Makefile | 1 + apps/home/base.it.i18n | 8 +- apps/on_boarding/Makefile | 1 + apps/on_boarding/base.it.i18n | 22 +- apps/probability/Makefile | 1 + apps/probability/base.it.i18n | 46 ++--- apps/regression/Makefile | 1 + apps/regression/base.it.i18n | 38 ++-- apps/sequence/Makefile | 1 + apps/sequence/base.it.i18n | 44 ++-- apps/settings/Makefile | 1 + apps/settings/base.it.i18n | 78 ++++---- apps/shared.it.i18n | 142 ++++++------- apps/solver/Makefile | 1 + apps/solver/base.it.i18n | 58 +++--- apps/statistics/Makefile | 1 + apps/statistics/base.it.i18n | 50 ++--- apps/toolbox.it.i18n | 240 +++++++++++----------- apps/usb/Makefile | 1 + apps/usb/base.it.i18n | 12 +- apps/variables.it.i18n | 20 +- build/config.mak | 2 +- 32 files changed, 633 insertions(+), 616 deletions(-) diff --git a/apps/Makefile b/apps/Makefile index ffcf1794c..9fc12513d 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -65,6 +65,7 @@ i18n_files += $(addprefix apps/,\ shared.en.i18n\ shared.es.i18n\ shared.fr.i18n\ + shared.it.i18n\ shared.nl.i18n\ shared.pt.i18n\ shared.universal.i18n\ @@ -72,12 +73,14 @@ i18n_files += $(addprefix apps/,\ toolbox.en.i18n\ toolbox.es.i18n\ toolbox.fr.i18n\ + toolbox.it.i18n\ toolbox.nl.i18n\ toolbox.pt.i18n\ variables.de.i18n\ variables.en.i18n\ variables.es.i18n\ variables.fr.i18n\ + variables.it.i18n\ variables.nl.i18n\ variables.pt.i18n\ ) diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index 89e83582b..9ae808006 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -38,6 +38,7 @@ i18n_files += $(addprefix apps/calculation/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/calculation/base.it.i18n b/apps/calculation/base.it.i18n index ca8e28739..351858f44 100644 --- a/apps/calculation/base.it.i18n +++ b/apps/calculation/base.it.i18n @@ -1,9 +1,9 @@ -CalculApp = "Calculs" -CalculAppCapital = "CALCULS" -AdditionalResults = "Résultats complémentaires" -DecimalBase = "Décimal" -HexadecimalBase = "Hexadécimal" -BinaryBase = "Binaire" -PrimeFactors = "Facteurs premiers" -MixedFraction = "Fraction mixte" -EuclideanDivision = "Division euclidienne" +CalculApp = "Calcolo" +CalculAppCapital = "CALCOLO" +AdditionalResults = "Ulteriori risultati" +DecimalBase = "Decimale" +HexadecimalBase = "Esadecimale" +BinaryBase = "Binario" +PrimeFactors = "Fattori primi" +MixedFraction = "Frazione mista" +EuclideanDivision = "Divisione euclidea" diff --git a/apps/code/Makefile b/apps/code/Makefile index b3140cfea..edbb6a3bf 100644 --- a/apps/code/Makefile +++ b/apps/code/Makefile @@ -34,6 +34,7 @@ i18n_files += $(addprefix apps/code/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ @@ -41,6 +42,7 @@ i18n_files += $(addprefix apps/code/,\ catalog.en.i18n\ catalog.es.i18n\ catalog.fr.i18n\ + catalog.it.i18n\ catalog.nl.i18n\ catalog.pt.i18n\ catalog.universal.i18n\ @@ -48,6 +50,7 @@ i18n_files += $(addprefix apps/code/,\ toolbox.en.i18n\ toolbox.es.i18n\ toolbox.fr.i18n\ + toolbox.it.i18n\ toolbox.nl.i18n\ toolbox.pt.i18n\ toolbox.universal.i18n\ diff --git a/apps/code/base.it.i18n b/apps/code/base.it.i18n index 253989ab2..aafac90a4 100644 --- a/apps/code/base.it.i18n +++ b/apps/code/base.it.i18n @@ -1,8 +1,8 @@ -Console = "Console d'exécution" -AddScript = "Ajouter un script" -ScriptOptions = "Options de script" -ExecuteScript = "Exécuter le script" -AutoImportScript = "Importation auto dans la console" -DeleteScript = "Supprimer le script" -FunctionsAndVariables = "Fonctions et variables" -AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" +Console = "Console d'esecuzione" +AddScript = "Aggiungere script" +ScriptOptions = "Opzioni dello script" +ExecuteScript = "Eseguire lo script" +AutoImportScript = "Importazione automatica dello script" +DeleteScript = "Eliminare lo script" +FunctionsAndVariables = "Funzioni e variabili" +AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index a480d11b1..90c1903f9 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -1,7 +1,7 @@ PythonPound = "Comment" PythonPercent = "Modulo" Python1J = "Imaginary i" -PythonLF = "Line feed" +PythonLF = "line feed" PythonTab = "Tabulation" PythonAmpersand = "Bitwise and" PythonSymbolExp = "Bitwise exclusive or" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 5f6bc9416..5628eff94 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -1,185 +1,185 @@ -PythonPound = "Comment" +PythonPound = "Commento" PythonPercent = "Modulo" -Python1J = "Imaginary i" -PythonLF = "Line feed" -PythonTab = "Tabulation" -PythonAmpersand = "Bitwise and" -PythonSymbolExp = "Bitwise exclusive or" -PythonVerticalBar = "Bitwise or" -PythonImag = "Imaginary part of z" -PythonReal = "Real part of z" -PythonSingleQuote = "Single quote" -PythonAbs = "Absolute value/Magnitude" -PythonAcos = "Arc cosine" -PythonAcosh = "Arc hyperbolic cosine" -PythonAppend = "Add x to the end of the list" -PythonAsin = "Arc sine" -PythonAsinh = "Arc hyperbolic sine" -PythonAtan = "Arc tangent" -PythonAtan2 = "Return atan(y/x)" -PythonAtanh = "Arc hyperbolic tangent" -PythonBin = "Convert integer to binary" -PythonCeil = "Ceiling" -PythonChoice = "Random number in the list" -PythonClear = "Empty the list" -PythonCmathFunction = "cmath module function prefix" -PythonColor = "Define a rgb color" -PythonComplex = "Return a+ib" -PythonCopySign = "Return x with the sign of y" -PythonCos = "Cosine" -PythonCosh = "Hyperbolic cosine" -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" -PythonErf = "Error function" -PythonErfc = "Complementary error function" -PythonEval = "Return the evaluated expression" -PythonExp = "Exponential function" -PythonExpm1 = "Compute exp(x)-1" -PythonFabs = "Absolute value" -PythonFillRect = "Fill a rectangle at pixel (x,y)" -PythonFloat = "Convert x to a float" -PythonFloor = "Floor" +Python1J = "Unità immaginaria" +PythonLF = "Nuova riga" +PythonTab = "Tabulazione" +PythonAmpersand = "Congiunzione" +PythonSymbolExp = "Disgiunzione esclusiva" +PythonVerticalBar = "Disgiunzione" +PythonImag = "Parte immaginaria di z" +PythonReal = "Parte reale di z" +PythonSingleQuote = "Apostrofo" +PythonAbs = "Valore assoluto/Modulo" +PythonAcos = "Coseno d’arco" +PythonAcosh = "Coseno iperbolico inverso" +PythonAppend = "Inserisce x alla fine della lista" +PythonAsin = "Arco sinusoidale" +PythonAsinh = "Arco sinusoidale iperbolico" +PythonAtan = "Arco tangente" +PythonAtan2 = "Calcolo di atan(y/x)" +PythonAtanh = "Arco tangente iperbolico" +PythonBin = "Converte un intero in binario" +PythonCeil = "Parte intera superiore" +PythonChoice = "Numero aleatorio nella lista" +PythonClear = "Svuota la lista" +PythonCmathFunction = "Funzione prefissata del modulo cmath" +PythonColor = "Definisci un colore rvb" +PythonComplex = "Restituisce a+ib" +PythonCopySign = "Restituisce x avec le signe de y" +PythonCos = "Coseno" +PythonCosh = "Coseno iperbolico" +PythonCount = "Compte les occurrences de x" +PythonDegrees = "Conversione di radianti in gradi" +PythonDivMod = "Quoziente e resto" +PythonDrawString = "Visualizza il text dal pixel x,y" +PythonErf = "Funzione d'errore" +PythonErfc = "Funzione d'errore complementare" +PythonEval = "Valuta l'espressione nell'argomento " +PythonExp = "Funzione esponenziale" +PythonExpm1 = "Calcola exp(x)-1" +PythonFabs = "Valore assoluto" +PythonFillRect = "Riempie un rettangolo" +PythonFloat = "Conversion en flottant" +PythonFloor = "Parte intera" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" -PythonGamma = "Gamma function" -PythonGetPixel = "Return pixel (x,y) color" -PythonGetrandbits = "Integer with k random bits" -PythonHex = "Convert integer to hexadecimal" -PythonImportCmath = "Import cmath module" -PythonImportIon = "Import ion module" -PythonImportKandinsky = "Import kandinsky module" -PythonImportRandom = "Import random module" -PythonImportMath = "Import math module" -PythonImportTime = "Import time module" -PythonImportTurtle = "Import turtle module" -PythonIndex = "Index of the first x occurrence" -PythonInput = "Prompt a value" -PythonInsert = "Insert x at index i in the list" -PythonInt = "Convert x to an integer" -PythonIonFunction = "ion module function prefix" -PythonIsFinite = "Check if x is finite" -PythonIsInfinite = "Check if x is infinity" -PythonIsKeyDown = "Return True if the k key is down" -PythonIsNaN = "Check if x is a NaN" -PythonKandinskyFunction = "kandinsky module function prefix" -PythonKeyLeft = "LEFT ARROW key" -PythonKeyUp = "UP ARROW key" -PythonKeyDown = "DOWN ARROW key" -PythonKeyRight = "RIGHT ARROW key" -PythonKeyOk = "OK key" -PythonKeyBack = "BACK key" -PythonKeyHome = "HOME key" -PythonKeyOnOff = "ON/OFF key" -PythonKeyShift = "SHIFT key" -PythonKeyAlpha = "ALPHA key" -PythonKeyXnt = "X,N,T key" -PythonKeyVar = "VAR key" -PythonKeyToolbox = "TOOLBOX key" -PythonKeyBackspace = "BACKSPACE key" -PythonKeyExp = "EXPONENTIAL key" -PythonKeyLn = "NATURAL LOGARITHM key" -PythonKeyLog = "DECIMAL LOGARITHM key" -PythonKeyImaginary = "IMAGINARY I key" -PythonKeyComma = "COMMA key" -PythonKeyPower = "POWER key" -PythonKeySine = "SINE key" -PythonKeyCosine = "COSINE key" -PythonKeyTangent = "TANGENT key" -PythonKeyPi = "PI key" -PythonKeySqrt = "SQUARE ROOT key" -PythonKeySquare = "SQUARE key" -PythonKeySeven = "7 key" -PythonKeyEight = "8 key" -PythonKeyNine = "9 key" -PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" -PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" -PythonKeyFour = "4 key" -PythonKeyFive = "5 key" -PythonKeySix = "6 key" -PythonKeyMultiplication = "MULTIPLICATION key" -PythonKeyDivision = "DIVISION key" -PythonKeyOne = "1 key" -PythonKeyTwo = "2 key" -PythonKeyThree = "3 key" -PythonKeyPlus = "PLUS key" -PythonKeyMinus = "MINUS key" -PythonKeyZero = "0 key" -PythonKeyDot = "DOT key" -PythonKeyEe = "10 POWER X key" -PythonKeyAns = "ANS key" -PythonKeyExe = "EXE key" -PythonLdexp = "Return x*(2**i), inverse of frexp" -PythonLength = "Length of an object" -PythonLgamma = "Log-gamma function" -PythonLog = "Logarithm to base a" -PythonLog10 = "Logarithm to base 10" -PythonLog2 = "Logarithm to base 2" -PythonMathFunction = "math module function prefix" -PythonMax = "Maximum" -PythonMin = "Minimum" -PythonModf = "Fractional and integer parts of x" -PythonMonotonic = "Value of a monotonic clock" -PythonOct = "Convert integer to octal" -PythonPhase = "Phase of z" -PythonPolar = "z in polar coordinates" -PythonPop = "Remove and return the last item" -PythonPower = "x raised to the power y" -PythonPrint = "Print object" -PythonRadians = "Convert x from degrees to radians" -PythonRandint = "Random integer in [a,b]" -PythonRandom = "Floating point number in [0,1[" -PythonRandomFunction = "random module function prefix" -PythonRandrange = "Random number in range(start, stop)" -PythonRangeStartStop = "List from start to stop-1" -PythonRangeStop = "List from 0 to stop-1" -PythonRect = "z in cartesian coordinates" -PythonRemove = "Remove the first occurrence of x" -PythonReverse = "Reverse the elements of the list" -PythonRound = "Round to n digits" -PythonSeed = "Initialize random number generator" -PythonSetPixel = "Color pixel (x,y)" -PythonSin = "Sine" -PythonSinh = "Hyperbolic sine" -PythonSleep = "Suspend the execution for t seconds" -PythonSort = "Sort the list" -PythonSqrt = "Square root" -PythonSum = "Sum the items of a list" -PythonTan = "Tangent" -PythonTanh = "Hyperbolic tangent" -PythonTimeFunction = "time module function prefix" -PythonTrunc = "x truncated to an integer" -PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" -PythonTurtleCircle = "Circle of radius r pixels" -PythonTurtleColor = "Set the pen color" +PythonFrExp = "Mantissa ed esponente di x : (m,e)" +PythonGamma = "Funzione gamma" +PythonGetPixel = "Restituisce il colore del pixel(x,y)" +PythonGetrandbits = "Numero aleatorio con k bit" +PythonHex = "Conversione intero in esadecimale" +PythonImportCmath = "Importazione del modulo cmath" +PythonImportIon = "Importazione del modulo ion" +PythonImportKandinsky = "Importazione del modulo kandinsky" +PythonImportRandom = "Importazione del modulo random" +PythonImportMath = "Importazione del modulo math" +PythonImportTurtle = "Importazione del modulo turtle" +PythonImportTime = "Importazione del modulo time" +PythonIndex = "Indice prima occorrenza di x" +PythonInput = "Inserire un valore" +PythonInsert = "Inserire x in posizione i-esima" +PythonInt = "Conversione in intero" +PythonIonFunction = "Prefisso di funzione modulo ion" +PythonIsFinite = "Testa se x è finito" +PythonIsInfinite = "Testa se x est infinito" +PythonIsKeyDown = "Restituisce True se viene premuto il tasto k" +PythonIsNaN = "Testa se x è NaN" +PythonKandinskyFunction = "Prefisso di funzione modulo kandinsky" +PythonKeyLeft = "Tasto FRECCIA SINISTRA" +PythonKeyUp = "Tasto FRECCIA ALTO" +PythonKeyDown = "Tasto FRECCIA BASSO" +PythonKeyRight = "Tasto FRECCIA DESTRA" +PythonKeyOk = "Tasto OK" +PythonKeyBack = "Tasto INDIETRO" +PythonKeyHome = "Tasto CASA" +PythonKeyOnOff = "Tasto ON/OFF" +PythonKeyShift = "Tasto SHIFT" +PythonKeyAlpha = "Tasto ALPHA" +PythonKeyXnt = "Tasto X,N,T" +PythonKeyVar = "Tasto VAR" +PythonKeyToolbox = "Tasto TOOLBOX" +PythonKeyBackspace = "Tasto CANCELLA" +PythonKeyExp = "Tasto ESPONENZIALE" +PythonKeyLn = "Tasto LOGARITMO NEPERIANO" +PythonKeyLog = "Tasto LOGARITMO DECIMALE" +PythonKeyImaginary = "Tasto I IMMAGINE" +PythonKeyComma = "Tasto VIRGOLA" +PythonKeyPower = "Tasto POTENZA" +PythonKeySine = "Tasto SENO" +PythonKeyCosine = "Tasto COSENO" +PythonKeyTangent = "Tasto TANGENTE" +PythonKeyPi = "Tasto PI" +PythonKeySqrt = "Tasto RADICE QUADRATA" +PythonKeySquare = "Tasto QUADRATO" +PythonKeySeven = "Tasto 7" +PythonKeyEight = "Tasto 8" +PythonKeyNine = "Tasto 9" +PythonKeyLeftParenthesis = "Tasto PARENTESI SINISTRA" +PythonKeyRightParenthesis = "Tasto PARENTESI DESTRA" +PythonKeyFour = "Tasto 4" +PythonKeyFive = "Tasto 5" +PythonKeySix = "Tasto 6" +PythonKeyMultiplication = "Tasto MOLTIPLICAZIONE" +PythonKeyDivision = "Tasto DIVISIONE" +PythonKeyOne = "Tasto 1" +PythonKeyTwo = "Tasto 2" +PythonKeyThree = "Tasto 3" +PythonKeyPlus = "Tasto PIÙ" +PythonKeyMinus = "Tasto MENO" +PythonKeyZero = "Tasto 0" +PythonKeyDot = "Tasto PUNTO" +PythonKeyEe = "Tasto 10 POTENZA X" +PythonKeyAns = "Tasto ANS" +PythonKeyExe = "Tasto EXE" +PythonLdexp = "Inversa di frexp : x*(2**i)" +PythonLength = "Longhezza di un oggetto" +PythonLgamma = "Logaritmo della funzione gamma" +PythonLog = "Logaritmo di base a" +PythonLog10 = "Logaritmo decimale" +PythonLog2 = "Logaritmo di base 2" +PythonMathFunction = "Prefisso funzione del modulo math" +PythonMax = "Massimo" +PythonMin = "Minimo" +PythonModf = "Parti frazionarie e intere" +PythonMonotonic = "Restituisce il valore dell'orologio" +PythonOct = "Conversione in ottale" +PythonPhase = "Argomento di z" +PythonPolar = "Conversione in polare" +PythonPop = "Cancella l'ultimo elemento" +PythonPower = "x alla potenza y" +PythonPrint = "Visualizza l'oggetto" +PythonRadians = "Conversione da gradi a radianti" +PythonRandint = "Intero aleatorio in [a,b]" +PythonRandom = "Numero aleatorio in [0,1[" +PythonRandomFunction = "Prefisso di funzione del modulo casuale" +PythonRandrange = "Numero dentro il range(start, stop)" +PythonRangeStartStop = "Lista da start a stop-1" +PythonRangeStop = "Lista da 0 a stop-1" +PythonRect = "Conversione in coordinate algebriche" +PythonRemove = "Cancella la prima x dalla liste" +PythonReverse = "Inverte gli elementi della lista" +PythonRound = "Arrotondato a n cifre decimali" +PythonSeed = "Inizializza il generatore random" +PythonSetPixel = "Colora il pixel (x,y)" +PythonSin = "Seno" +PythonSinh = "Seno iperbolico" +PythonSleep = "Sospende l'esecuzione t secondi" +PythonSort = "Ordina l'elenco" +PythonSqrt = "Radice quadrata" +PythonSum = "Somma degli elementi della lista" +PythonTan = "Tangente" +PythonTanh = "Tangente iperbolica" +PythonTimeFunction = "Prefisso funzione modulo time" +PythonTrunc = "Troncamento intero" +PythonTurtleBackward = "Indietreggia di x pixels" +PythonTurtleBlack = "Colore nero" +PythonTurtleBlue = "Colore blu" +PythonTurtleBrown = "Colore marrone" +PythonTurtleCircle = "Cerchio di raggio r pixel" +PythonTurtleColor = "Modifica il colore del tratto" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" -PythonTurtleForward = "Move forward by x pixels" -PythonTurtleFunction = "turtle module function prefix" -PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" -PythonTurtleHeading = "Return the current heading" -PythonTurtleHideturtle = "Hide the turtle" -PythonTurtleIsdown = "Return True if the pen is down" -PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" -PythonTurtlePendown = "Pull the pen down" -PythonTurtlePensize = "Set the line thickness to x pixels" -PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" -PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" -PythonTurtleReset = "Reset the drawing" -PythonTurtleRight = "Turn right by a degrees" -PythonTurtleSetheading = "Set the orientation to a degrees" -PythonTurtleSetposition = "Positionne la tortue" -PythonTurtleShowturtle = "Show the turtle" -PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" -PythonUniform = "Floating point number in [a,b]" +PythonTurtleForward = "Avancza di x pixel" +PythonTurtleFunction = "Prefisso di funzione del modello turtle" +PythonTurtleGoto = "Spostati alle coordinate (x,y)" +PythonTurtleGreen = "Colore verde" +PythonTurtleGrey = "Colore grigio" +PythonTurtleHeading = "Restituisce l’orientamento attuale" +PythonTurtleHideturtle = "Nascondi la tartaruga" +PythonTurtleIsdown = "True se la penna è abbassata" +PythonTurtleLeft = "Ruota di a gradi a sinistra" +PythonTurtleOrange = "Colore arancione" +PythonTurtlePendown = "Abbassa la penna" +PythonTurtlePensize = "Dimensione del tratto in pixel" +PythonTurtlePenup = "Solleva la penna" +PythonTurtlePink = "Colore rosa" +PythonTurtlePosition = "Restituisce la posizione corrente (x,y)" +PythonTurtlePurple = "Colore viola" +PythonTurtleRed = "Colore rosso" +PythonTurtleReset = "Azzera il disegno" +PythonTurtleRight = "Ruota di a gradi a destra" +PythonTurtleSetheading = "Imposta l’orientamento per a gradi" +PythonTurtleSetposition = "Posiziona la tartaruga" +PythonTurtleShowturtle = "Mostra la tartaruga" +PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)" +PythonTurtleWhite = "Colore bianco" +PythonTurtleYellow = "Colore giallo" +PythonUniform = "Numero decimale tra [a,b]" diff --git a/apps/code/toolbox.it.i18n b/apps/code/toolbox.it.i18n index 6442521cc..5fd875949 100644 --- a/apps/code/toolbox.it.i18n +++ b/apps/code/toolbox.it.i18n @@ -1,4 +1,4 @@ -Functions = "Fonctions" -Catalog = "Catalogue" -Modules = "Modules" -LoopsAndTests = "Boucles et tests" +Functions = "Funzioni" +Catalog = "Catalogo" +Modules = "Moduli" +LoopsAndTests = "Loops e test" diff --git a/apps/graph/Makefile b/apps/graph/Makefile index d4fdfdb9a..580cabcfc 100644 --- a/apps/graph/Makefile +++ b/apps/graph/Makefile @@ -38,6 +38,7 @@ i18n_files += $(addprefix apps/graph/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/graph/base.it.i18n b/apps/graph/base.it.i18n index d95a5ae63..99fabd636 100644 --- a/apps/graph/base.it.i18n +++ b/apps/graph/base.it.i18n @@ -1,33 +1,33 @@ -FunctionApp = "Fonctions" -FunctionAppCapital = "FONCTIONS" -FunctionTab = "Fonctions" -AddFunction = "Ajouter une fonction" -DeleteFunction = "Supprimer la fonction" -CurveType = "Type de courbe" -CartesianType = "Cartésien " -PolarType = "Polaire " -ParametricType = "Paramétrique " -IntervalT = "Intervalle t" -IntervalTheta = "Intervalle θ" -IntervalX = "Intervalle x" -FunctionDomain = "Domaine de tracé" -FunctionColor = "Couleur de la fonction" -NoFunction = "Aucune fonction" -NoActivatedFunction = "Aucune fonction activée" -PlotOptions = "Options de la courbe" -Compute = "Calculer" -Zeros = "Zéros" +FunctionApp = "Funzioni" +FunctionAppCapital = "FUNZIONI" +FunctionTab = "Funzioni" +AddFunction = "Aggiungi funzione" +DeleteFunction = "Cancella funzione" +CurveType = "Tipo di curva" +CartesianType = "Cartesiana " +PolarType = "Polare " +ParametricType = "Parametrica " +IntervalT = "Intervallo t" +IntervalTheta = "Intervallo θ" +IntervalX = "Intervallo x" +FunctionDomain = "Area di tracciamento" +FunctionColor = "Colore della funzione" +NoFunction = "Nessuna funzione" +NoActivatedFunction = "Nessuna funzione attivata" +PlotOptions = "Opzioni della curva" +Compute = "Calcolare" +Zeros = "Zeri" Tangent = "Tangente" -Intersection = "Intersection" -Preimage = "Antécédent" -SelectLowerBound = "Sélectionner la borne inférieure" -SelectUpperBound = "Sélectionner la borne supérieure" -NoMaximumFound = "Aucun maximum trouvé" -NoMinimumFound = "Aucun minimum trouvé" -NoZeroFound = "Aucun zéro trouvé" -NoIntersectionFound = "Aucune intersection trouvée" -NoPreimageFound = "Aucun antécédent trouvé" -DerivativeFunctionColumn = "Colonne de la fonction dérivée" -HideDerivativeColumn = "Masquer la fonction dérivée" -AllowedCharactersAZaz09 = "Caractères autorisés : A-Z, a-z, 0-9, _" -ReservedName = "Nom réservé" +Intersection = "Intersezione" +Preimage = "Immagine" +SelectLowerBound = "Scegliere il limite inferiore" +SelectUpperBound = "Scegliere il limite superiore" +NoMaximumFound = "Nessun massimo trovato" +NoMinimumFound = "Nessun minimo trovato" +NoZeroFound = "Nessuno zero trovato" +NoIntersectionFound = "Nessuna intersezione trovata" +NoPreimageFound = "Nessuna immagine trovata" +DerivativeFunctionColumn = "Colonna della funzione derivata" +HideDerivativeColumn = "Nascondere la funzione derivata" +AllowedCharactersAZaz09 = "Caratteri consentiti : A-Z, a-z, 0-9, _" +ReservedName = "Nome riservato" diff --git a/apps/home/Makefile b/apps/home/Makefile index 691a6ac86..7a2004e2a 100644 --- a/apps/home/Makefile +++ b/apps/home/Makefile @@ -11,6 +11,7 @@ i18n_files += $(addprefix apps/home/,\ base.en.i18n \ base.es.i18n \ base.fr.i18n \ + base.it.i18n\ base.nl.i18n \ base.pt.i18n \ ) diff --git a/apps/home/base.it.i18n b/apps/home/base.it.i18n index 158fa3bda..cfd37f3df 100644 --- a/apps/home/base.it.i18n +++ b/apps/home/base.it.i18n @@ -1,4 +1,4 @@ -Apps = "Applications" -AppsCapital = "APPLICATIONS" -ForbidenAppInExamMode1 = "This application is" -ForbidenAppInExamMode2 = "forbidden in exam mode" +Apps = "Applicazioni" +AppsCapital = "APPLICAZIONI" +ForbidenAppInExamMode1 = "Questa applicazione è" +ForbidenAppInExamMode2 = "proibita nella modalità d'esame" diff --git a/apps/on_boarding/Makefile b/apps/on_boarding/Makefile index 06f95ba74..9941b02d7 100644 --- a/apps/on_boarding/Makefile +++ b/apps/on_boarding/Makefile @@ -14,6 +14,7 @@ i18n_files += $(addprefix apps/on_boarding/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/on_boarding/base.it.i18n b/apps/on_boarding/base.it.i18n index fdd2dca84..1ea96faea 100644 --- a/apps/on_boarding/base.it.i18n +++ b/apps/on_boarding/base.it.i18n @@ -1,13 +1,13 @@ -UpdateAvailable = "MISE À JOUR DISPONIBLE" -UpdateMessage1 = "Des améliorations importantes existent" -UpdateMessage2 = "pour votre calculatrice." -UpdateMessage3 = "Connectez-vous depuis votre ordinateur" +UpdateAvailable = "AGGIORNAMENTO DISPONIBILE" +UpdateMessage1 = "Esistono miglioramenti significativi" +UpdateMessage2 = "per la vostra calcolatrice." +UpdateMessage3 = "Connettetevi dal vostro computer" UpdateMessage4 = "www.numworks.com/update" -BetaVersion = "VERSION BÊTA" -BetaVersionMessage1 = "Votre appareil dispose d'une version bêta" -BetaVersionMessage2 = "du logiciel. Il est possible que certains" -BetaVersionMessage3 = "bugs apparaissent." -BetaVersionMessage4 = "Vous pouvez nous écrire pour nous" -BetaVersionMessage5 = "faire part de vos retours à" +BetaVersion = "VERSIONE BETA" +BetaVersionMessage1 = "Il vostro dispositivo dispone di una versione beta" +BetaVersionMessage2 = "del software. È possibile che compaiano" +BetaVersionMessage3 = "alcuni bugs." +BetaVersionMessage4 = "Per comunicarci un riscontro" +BetaVersionMessage5 = "potete scriverci a" BetaVersionMessage6 = "contact@numworks.com" -Skip = "Passer" +Skip = "Saltare" diff --git a/apps/probability/Makefile b/apps/probability/Makefile index b9b5c189c..72f2ee19d 100644 --- a/apps/probability/Makefile +++ b/apps/probability/Makefile @@ -45,6 +45,7 @@ i18n_files += $(addprefix apps/probability/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ diff --git a/apps/probability/base.it.i18n b/apps/probability/base.it.i18n index 056fa00f6..443229b53 100644 --- a/apps/probability/base.it.i18n +++ b/apps/probability/base.it.i18n @@ -1,27 +1,27 @@ -ProbaApp = "Probabilités" -ProbaAppCapital = "PROBABILITÉS" -ChooseDistribution = "Choisir le type de loi" +ProbaApp = "Probabilità" +ProbaAppCapital = "PROBABILITA" +ChooseDistribution = "Scegliere il tipo di distribuzione" Binomial = "Binomiale" -Geometric = "Géométrique" +Geometric = "Geometrica" Uniforme = "Uniforme" Normal = "Normale" ChiSquared = "Chi2" -UniformDistribution = "Loi uniforme" -ExponentialDistribution = "Loi exponentielle" -GeometricDistribution = "Loi géométrique" -PoissonDistribution = "Loi de Poisson" -ChiSquaredDistribution = "Loi du chi2" -StudentDistribution = "Loi de Student" -FisherDistribution = "Loi de Fisher" -ChooseParameters = "Choisir les paramètres" -RepetitionNumber = "n : Nombre de répétitions" -SuccessProbability = "p : Probabilité de succès" -IntervalDefinition = "[a,b] : Intervalle" -LambdaExponentialDefinition = "λ : Paramètre" -MeanDefinition = "μ : Espérance ou moyenne" -DeviationDefinition = "σ : Écart type" -LambdaPoissonDefinition = "λ : Paramètre" -DegreesOfFreedomDefinition = "k : Degrés de liberté" -D1FisherDefinition = "d1 : Degrés de liberté du numérateur" -D2FisherDefinition = "d2 : Degrés de liberté du dénominateur" -ComputeProbability = "Calculer les probabilités" +UniformDistribution = "Distribuzione uniforme" +ExponentialDistribution = "Distribuzione esponenziale" +GeometricDistribution = "Distribuzione geometrica" +PoissonDistribution = "Distribuzione di Poisson" +ChiSquaredDistribution = "Distribuzione chi2" +StudentDistribution = "Distribuzione Student" +FisherDistribution = "Distribuzione di Fisher" +ChooseParameters = "Scegliere i parametri" +RepetitionNumber = "n : Numero di prove" +SuccessProbability = "p : Probabilità di successo" +IntervalDefinition = "[a,b] : Intervallo" +LambdaExponentialDefinition = "λ : Parametro" +MeanDefinition = "μ : Media" +DeviationDefinition = "σ : Deviazione standard" +LambdaPoissonDefinition = "λ : Parametro" +DegreesOfFreedomDefinition = "k : Gradi di libertà" +D1FisherDefinition = "d1 : Gradi di libertà del numeratore" +D2FisherDefinition = "d2 : Gradi di libertà del denominatore" +ComputeProbability = "Calcolare le probabilità" diff --git a/apps/regression/Makefile b/apps/regression/Makefile index 239cf0376..117279718 100644 --- a/apps/regression/Makefile +++ b/apps/regression/Makefile @@ -45,6 +45,7 @@ i18n_files += $(addprefix apps/regression/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ base.universal.i18n\ diff --git a/apps/regression/base.it.i18n b/apps/regression/base.it.i18n index 3339f6901..06976e196 100644 --- a/apps/regression/base.it.i18n +++ b/apps/regression/base.it.i18n @@ -1,21 +1,21 @@ -RegressionApp = "Régressions" -RegressionAppCapital = "RÉGRESSIONS" -Regression = "Régression" +RegressionApp = "Regressione" +RegressionAppCapital = "REGRESSIONE" +Regression = "Regressione" Reg = "reg" -MeanDot = "moyen" -RegressionCurve = "Courbe de régression" -XPrediction = "Prédiction sachant X" -YPrediction = "Prédiction sachant Y" -ValueNotReachedByRegression = "Valeur non atteinte dans cette fenêtre" -NumberOfDots = "Nombre de points" -Covariance = "Covariance" -Linear = "Linéaire" +MeanDot = "media" +RegressionCurve = "Curva di regressione" +XPrediction = "Previsione data X" +YPrediction = "Previsione data Y" +ValueNotReachedByRegression = "Valore non raggiunto in questa finestra" +NumberOfDots = "Numero di punti" +Covariance = "Covarianza" +Linear = "Lineare" Proportional = "Proporzionale" -Quadratic = "Quadratique" -Cubic = "Cubique" -Quartic = "Quartique" -Logarithmic = "Logarithmique" -Power = "Puissance" -Trigonometrical = "Trigonométrique" -Logistic = "Logistique" -DataNotSuitableForRegression = "Les données ne conviennent pas" +Quadratic = "Quadratica" +Cubic = "Cubica" +Quartic = "Quartica" +Logarithmic = "Logaritmica" +Power = "Potenza" +Trigonometrical = "Trigonometrica" +Logistic = "Logistica" +DataNotSuitableForRegression = "I dati non sono adeguati" diff --git a/apps/sequence/Makefile b/apps/sequence/Makefile index ee1b38ee5..818166e6f 100644 --- a/apps/sequence/Makefile +++ b/apps/sequence/Makefile @@ -33,6 +33,7 @@ i18n_files += $(addprefix apps/sequence/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/sequence/base.it.i18n b/apps/sequence/base.it.i18n index 3772efb47..40e6bd81c 100644 --- a/apps/sequence/base.it.i18n +++ b/apps/sequence/base.it.i18n @@ -1,22 +1,22 @@ -SequenceApp = "Suites" -SequenceAppCapital = "SUITES" -SequenceTab = "Suites" -AddSequence = "Ajouter une suite" -ChooseSequenceType = "Choisir le type de suite" -SequenceType = "Type de suite" -Explicit = "Explicite" -SingleRecurrence = "Récurrente d'ordre 1" -DoubleRecurrence = "Récurrente d'ordre 2" -SequenceOptions = "Options de la suite" -SequenceColor = "Couleur de la suite" -DeleteSequence = "Supprimer la suite" -NoSequence = "Aucune suite" -NoActivatedSequence = "Aucune suite activée" -NStart = "N début" -NEnd = "N fin" -TermSum = "Somme des termes" -SelectFirstTerm = "Sélectionner le premier terme " -SelectLastTerm = "Sélectionner le dernier terme " -ValueNotReachedBySequence = "Valeur non atteinte par la suite" -NColumn = "Colonne n" -FirstTermIndex = "Indice premier terme" +SequenceApp = "Successioni" +SequenceAppCapital = "SUCCESSIONI" +SequenceTab = "Successioni" +AddSequence = "Aggiungi successione" +ChooseSequenceType = "Scegliere il tipo di successione" +SequenceType = "Tipo di successione" +Explicit = "Esplicito" +SingleRecurrence = "Ricorrente d'ordine 1" +DoubleRecurrence = "Ricorrente d'ordine 2" +SequenceOptions = "Opzioni della successione" +SequenceColor = "Colore della successione" +DeleteSequence = "Cancella la successione" +NoSequence = "Nessuna successione" +NoActivatedSequence = "Nessuna successione attiva" +NStart = "N iniziale" +NEnd = "N finale" +TermSum = "Somma dei termini" +SelectFirstTerm = "Selezionare il primo termine " +SelectLastTerm = "Selezionare l'ultimo termine " +ValueNotReachedBySequence = "Valore non raggiunto dalla successione" +NColumn = "Colonna n" +FirstTermIndex = "Indice del primo termine" diff --git a/apps/settings/Makefile b/apps/settings/Makefile index bd65b2692..e05c24692 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -30,6 +30,7 @@ i18n_files += $(addprefix apps/settings/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n index 389710fad..bf81e9990 100644 --- a/apps/settings/base.it.i18n +++ b/apps/settings/base.it.i18n @@ -1,41 +1,41 @@ -SettingsApp = "Paramètres" -SettingsAppCapital = "PARAMÈTRES" -AngleUnit = "Unité d'angle" -DisplayMode = "Format résultat" -EditionMode = "Format écriture" -EditionLinear = "En ligne " -Edition2D = "Naturelle " -ComplexFormat = "Forme complexe" -ExamMode = "Mode examen" -ExamModeActive = "Réactiver le mode examen" -ToDeactivateExamMode1 = "Pour désactiver le mode examen," -ToDeactivateExamMode2 = "brancher la calculatrice à un" -ToDeactivateExamMode3 = "ordinateur ou à une prise de courant." +SettingsApp = "Impostazioni" +SettingsAppCapital = "IMPOSTAZIONI" +AngleUnit = "Misura angolo" +DisplayMode = "Formato risultato" +EditionMode = "Formato scrittura" +EditionLinear = "Lineare " +Edition2D = "Naturale " +ComplexFormat = "Formato complesso" +ExamMode = "Modalità Esame" +ExamModeActive = "Riattivare modalità Esame" +ToDeactivateExamMode1 = "Per disattivare la modalità esame," +ToDeactivateExamMode2 = "collegare la calcolatrice a un" +ToDeactivateExamMode3 = "computer o a una presa di corrente." # --------------------- Please do not edit these messages --------------------- -ExamModeWarning1 = "Attention, la conformité du mode" -ExamModeWarning2 = "examen de ce logiciel non officiel" -ExamModeWarning3 = "n'est pas garantie par NumWorks." -AboutWarning1 = "Attention, vous utilisez une version" -AboutWarning2 = "non officielle du logiciel. NumWorks" -AboutWarning3 = "ne saurait être tenu responsable des" -AboutWarning4 = "problèmes que cela pourrait entraîner." +ExamModeWarning1 = "Attenzione, la conformità della modalità" +ExamModeWarning2 = "esame di questo software non ufficiale" +ExamModeWarning3 = "non è garantita da NumWorks." +AboutWarning1 = "Attenzione, voi utilizzate una versione" +AboutWarning2 = "non ufficiale del software. NumWorks" +AboutWarning3 = "non potrà essere ritenuto responsabile dei" +AboutWarning4 = "problemi che questo potrebbe comportare." # ----------------------------------------------------------------------------- -About = "À propos" -Degrees = "Degrés " -Gradians = "Grades " -Radian = "Radians " -Decimal = "Décimal " -Scientific = "Scientifique " -Engineering = "Ingénieur " -SignificantFigures = "Chiffres significatifs " -Real = "Réel " -Cartesian = "Algébrique " -Polar = "Exponentielle " -Brightness = "Luminosité" -FontSizes = "Police Python" -LargeFont = "Grand " -SmallFont = "Petit " -SoftwareVersion = "Version du logiciel" -SerialNumber = "Numéro série" -UpdatePopUp = "Rappel mise à jour" -BetaPopUp = "Rappel version bêta" +About = "Informazioni su" +Degrees = "Gradi " +Gradians = "Gradienti " +Radian = "Radianti " +Decimal = "Decimale " +Scientific = "Scientifico " +Engineering = "Engineering " +SignificantFigures = "Cifre significative " +Real = "Reale " +Cartesian = "Algebrico " +Polar = "Esponenziale " +Brightness = "Luminosità" +FontSizes = "Carattere Python" +LargeFont = "Grande " +SmallFont = "Piccolo " +SoftwareVersion = "Versione software" +SerialNumber = "Numero di serie" +UpdatePopUp = "Promemoria aggiornamento" +BetaPopUp = "Promemoria beta" diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n index 22842405f..adde7f9d8 100644 --- a/apps/shared.it.i18n +++ b/apps/shared.it.i18n @@ -1,81 +1,81 @@ -ActivateDeactivate = "Activer/Désactiver" -ActivateExamMode = "Activer le mode examen" +ActivateDeactivate = "Attivare/Disattivare" +ActivateExamMode = "Attivare modalità d'esame" ActivateDutchExamMode = "Activate Dutch exam mode" -ActiveExamModeMessage1 = "Toutes vos données seront " -ActiveExamModeMessage2 = "supprimées si vous activez " -ActiveExamModeMessage3 = "le mode examen." +ActiveExamModeMessage1 = "Tutti i vostri dati saranno " +ActiveExamModeMessage2 = "cancellati se attivate " +ActiveExamModeMessage3 = "la modalità d'esame." ActiveDutchExamModeMessage1 = "All your data will be deleted when" ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" ActiveDutchExamModeMessage3 = "application will be unavailable." -Axis = "Axes" -Cancel = "Annuler" -ClearColumn = "Effacer la colonne" -ColumnOptions = "Options de la colonne" -CopyColumnInList = "Copier la colonne dans une liste" -DataNotSuitable = "Les données ne conviennent pas" -DataTab = "Données" -DefaultSetting = "Réglages de base" +Axis = "Assi" +Cancel = "Annullare" +ClearColumn = "Cancella la colonna" +ColumnOptions = "Opzioni colonna" +CopyColumnInList = "Copia colonna in una lista" +DataNotSuitable = "I dati non sono adeguati" +DataTab = "Dati" +DefaultSetting = "Impostazioni di base" Deg = "deg" -Deviation = "Variance" -DisplayValues = "Afficher les valeurs" -Empty = "Vide" -Eng = "ing" -ExitExamMode1 = "Voulez-vous sortir " -ExitExamMode2 = "du mode examen ?" -Exponential = "Exponentielle" -FillWithFormula = "Remplir avec une formule" -ForbiddenValue = "Valeur interdite" -FunctionColumn = "Colonne 0(0)" -FunctionOptions = "Options de la fonction" -Goto = "Aller à" -GraphTab = "Graphique" -HardwareTestLaunch1 = "Vous allez lancer le test usine." -HardwareTestLaunch2 = "Pour en sortir vous devrez" -HardwareTestLaunch3 = "appuyer sur le bouton reset" -HardwareTestLaunch4 = "ce qui supprimera vos données." -Initialization = "Initialisation" -IntervalSet = "Régler l'intervalle" -Language = "Langue" -LowBattery = "Batterie faible" -Mean = "Moyenne" -Move = " Déplacer : " -NameCannotStartWithNumber = "Un nom ne peut pas commencer par un chiffre" -NameTaken = "Ce nom est déjà utilisé" -NameTooLong = "Ce nom est trop long" -Next = "Suivant" -NEnd = "N fin" -NoDataToPlot = "Aucune donnée à tracer" -NoFunctionToDelete = "Pas de fonction à supprimer" -NoValueToCompute = "Aucune grandeur à calculer" -NStart = "N début" -Ok = "Valider" -Or = " ou " -Orthonormal = "Orthonormé" -Plot = "Tracer le graphique" -PoolMemoryFull1 = "La mémoire de travail est pleine." -PoolMemoryFull2 = "Réessayez." +Deviation = "Varianza" +DisplayValues = "Mostra valori" +Empty = "Vuoto" +Eng = "eng" +ExitExamMode1 = "Volete uscire " +ExitExamMode2 = "dalla modalità d'esame ?" +Exponential = "Esponenziale" +FillWithFormula = "Compilare con una formula" +ForbiddenValue = "Valore non consentito" +FunctionColumn = "Colonna 0(0)" +FunctionOptions = "Opzioni della funzione" +Goto = "Andare a" +GraphTab = "Grafico" +HardwareTestLaunch1 = "Farete il test hardware." +HardwareTestLaunch2 = "Per uscire dovrete" +HardwareTestLaunch3 = "premere il tasto reset" +HardwareTestLaunch4 = "che cancellerà i vostri dati." +Initialization = "Pre-regolazione" +IntervalSet = "Imposta l'intervallo" +Language = "Lingua" +LowBattery = "Batteria bassa" +Mean = "Media" +Move = " Spostare : " +NameCannotStartWithNumber = "Un nome non può cominciare con un numero" +NameTaken = "Questo nome è già utilizzato" +NameTooLong = "Questo nome è troppo lungo" +Next = "Successivo" +NEnd = "N finale" +NoDataToPlot = "Nessun dato da tracciare" +NoFunctionToDelete = "Nessuna funzione da cancellare" +NoValueToCompute = "Nessun valore da calcolare" +NStart = "N iniziale" +Ok = "Conferma" +Or = " o " +Orthonormal = "Ortogonale" +Plot = "Traccia grafico" +PoolMemoryFull1 = "La memoria di lavoro è piena." +PoolMemoryFull2 = "Riprovare." Rad = "rad" -Rename = "Renommer" -RoundAbscissa = "Abscisses entières" +Rename = "Rinominare" +RoundAbscissa = "Ascisse intere" Sci = "sci" -SquareSum = "Somme des carrés" -StandardDeviation = "Écart type" +SquareSum = "Somma dei quadrati" +StandardDeviation = "Deviazione standard" StatTab = "Stats" Step = "Pas" -StorageMemoryFull1 = "La mémoire est pleine." -StorageMemoryFull2 = "Effacez des données et réessayez." -StoreExpressionNotAllowed = "'store' n'est pas autorisé" -SyntaxError = "Attention à la syntaxe" -TEnd = "T fin" -ThetaEnd = "θ fin" -ThetaStart = "θ début" -TStart = "T début" -ToZoom = "Zoomer : " -Trigonometric = "Trigonométrique" -UndefinedValue = "Valeur non définie" -ValueNotReachedByFunction = "Valeur non atteinte par la fonction" -ValuesTab = "Tableau" -Warning = "Attention" -XEnd = "X fin" -XStart = "X début" +StorageMemoryFull1 = "La memoria è piena." +StorageMemoryFull2 = "Cancellate i dati e riprovate." +StoreExpressionNotAllowed = "'store' non è consentito" +SyntaxError = "Sintassi errata" +TEnd = "T finale" +ThetaEnd = "θ finale" +ThetaStart = "θ iniziale" +TStart = "T iniziale" +ToZoom = "Ingrandire : " +Trigonometric = "Trigonometrica" +UndefinedValue = "Valore non definito" +ValueNotReachedByFunction = "Valore non raggiunto dalla funzione" +ValuesTab = "Tabella" +Warning = "Attenzione" +XEnd = "X finale" +XStart = "X iniziale" Zoom = "Zoom" diff --git a/apps/solver/Makefile b/apps/solver/Makefile index e85014c6c..ef9ca6700 100644 --- a/apps/solver/Makefile +++ b/apps/solver/Makefile @@ -23,6 +23,7 @@ i18n_files += $(addprefix apps/solver/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/solver/base.it.i18n b/apps/solver/base.it.i18n index c337a0525..5b6f79dbf 100644 --- a/apps/solver/base.it.i18n +++ b/apps/solver/base.it.i18n @@ -1,29 +1,29 @@ -SolverApp = "Équations" -SolverAppCapital = "ÉQUATIONS" -AddEquation = "Ajouter une équation" -ResolveEquation = "Résoudre l'équation" -ResolveSystem = "Résoudre le système" -UseEquationModel = "Utiliser un modèle d'équation" -RequireEquation = "L'entrée doit être une équation" -UndefinedEquation = "Une équation est indéfinie" -UnrealEquation = "Une équation n'est pas réelle" -TooManyVariables = "Le nombre d'inconnues est trop grand" -NonLinearSystem = "Le système n'est pas linéaire" -Solution = "Solution" -ApproximateSolution = "Solution approchée" -SearchInverval = "Intervalle de recherche" -NoSolutionSystem = "Le système n'admet aucune solution" -NoSolutionEquation = "L'équation n'admet aucune solution" -NoSolutionInterval = "Aucune solution trouvée dans cet intervalle" -EnterEquation = "Entrez une équation" -InfiniteNumberOfSolutions = "Le système admet une infinité de solutions" -ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" -ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée" -OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" -OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" -PolynomeHasNoRealSolution0 = "Le polynôme n'admet pas" -PolynomeHasNoRealSolution1 = "de racine réelle" -PredefinedVariablesUsedLeft = "Variable" -PredefinedVariablesUsedRight = "s prédéfinies utilisées" -PredefinedVariablesIgnoredLeft = "Variable" -PredefinedVariablesIgnoredRight = "s prédéfinies ignorées" +SolverApp = "Equazioni" +SolverAppCapital = "EQUAZIONI" +AddEquation = "Aggiungi equazione" +ResolveEquation = "Risolvi l'equazione" +ResolveSystem = "Risolvi il sistema" +UseEquationModel = "Utilizza un modello di equazione" +RequireEquation = "L'input deve essere un'equazione" +UndefinedEquation = "Un'equazione è indefinita'" +UnrealEquation = "Un'equazione non è reale" +TooManyVariables = "Il numero di incognite è troppo elevato" +NonLinearSystem = "Il sistema non è lineare" +Solution = "Soluzione" +ApproximateSolution = "Soluzione approssimata" +SearchInverval = "Intervallo di ricerca" +NoSolutionSystem = "Il sistema non ammette nessuna soluzione" +NoSolutionEquation = "L'equazione non ammette nessuna soluzione" +NoSolutionInterval = "Nessuna soluzione trovata dentro questo intervallo" +EnterEquation = "Inserire un'equazione" +InfiniteNumberOfSolutions = "Il sistema ammette un'infinità di soluzioni" +ApproximateSolutionIntervalInstruction0= "Inserire l'intervallo dentro al quale" +ApproximateSolutionIntervalInstruction1= "ricercare una soluzione approssimata" +OnlyFirstSolutionsDisplayed0 = "Solamente le prime 10" +OnlyFirstSolutionsDisplayed1 = "soluzioni sono mostrate" +PolynomeHasNoRealSolution0 = "Il polinomio non ammette" +PolynomeHasNoRealSolution1 = "una radice reale" +PredefinedVariablesUsedLeft = "Variabili" +PredefinedVariablesUsedRight = " predefinite utilizzate" +PredefinedVariablesIgnoredLeft = "Variabil" +PredefinedVariablesIgnoredRight = "i predefinite ignorate" diff --git a/apps/statistics/Makefile b/apps/statistics/Makefile index f7543025a..3ba260a2a 100644 --- a/apps/statistics/Makefile +++ b/apps/statistics/Makefile @@ -34,6 +34,7 @@ i18n_files += $(addprefix apps/statistics/,\ base.en.i18n\ base.es.i18n\ base.fr.i18n\ + base.it.i18n\ base.nl.i18n\ base.pt.i18n\ ) diff --git a/apps/statistics/base.it.i18n b/apps/statistics/base.it.i18n index f90b4d60b..941345722 100644 --- a/apps/statistics/base.it.i18n +++ b/apps/statistics/base.it.i18n @@ -1,25 +1,25 @@ -StatsApp = "Statistiques" -StatsAppCapital = "STATISTIQUES" -HistogramTab = "Histogramme" -BoxTab = "Boîte" -Values1 = "Valeurs V1" -Values2 = "Valeurs V2" -Values3 = "Valeurs V3" -Sizes1 = "Effectifs N1" -Sizes2 = "Effectifs N2" -Sizes3 = "Effectifs N3" -ImportList = "Importer une liste" -Interval = " Intervalle " -Size = " Effectif" -Frequency = "Fréquence" -HistogramSet = "Réglage de l'histogramme" -RectangleWidth = "Largeur des rectangles" -BarStart = "Début de la série" -FirstQuartile = "Premier quartile" -Median = "Médiane" -ThirdQuartile = "Troisième quartile" -TotalSize = "Effectif total" -Range = "Étendue" -StandardDeviationSigma = "Écart type" -SampleStandardDeviationS = "Écart type échantillon" -InterquartileRange = "Écart interquartile" +StatsApp = "Statistica" +StatsAppCapital = "STATISTICA" +HistogramTab = "Istogramma" +BoxTab = "Box Plot" +Values1 = "Valori V1" +Values2 = "Valori V2" +Values3 = "Valori V3" +Sizes1 = "Frequenze N1" +Sizes2 = "Frequenze N2" +Sizes3 = "Frequenze N3" +ImportList = "Importare una lista" +Interval = " Intervallo " +Size = " Frequenza" +Frequency = "Relativa" +HistogramSet = "Regolazione dell'istogramma" +RectangleWidth = "Larghezza dei rettangoli" +BarStart = "Inizio della serie" +FirstQuartile = "Primo quartile" +Median = "Mediana" +ThirdQuartile = "Terzo quartile" +TotalSize = "Dimensione totale" +Range = "Ampiezza" +StandardDeviationSigma = "Deviazione standard" +SampleStandardDeviationS = "Esempio deviazione stnrd" +InterquartileRange = "Scarto interquartile" diff --git a/apps/toolbox.it.i18n b/apps/toolbox.it.i18n index 0a67a6b24..14c8b7ddc 100644 --- a/apps/toolbox.it.i18n +++ b/apps/toolbox.it.i18n @@ -1,61 +1,61 @@ -Unit = "Unités" -UnitTimeMenu = "Temps" -UnitTimeSecondMenu = "Seconde" -UnitTimeSecond = "Seconde" -UnitTimeSecondMilli = "Milliseconde" -UnitTimeSecondMicro = "Microseconde" -UnitTimeSecondNano = "Nanoseconde" -UnitTimeMinute = "Minute" -UnitTimeHour = "Heure" -UnitTimeDay = "Jour" -UnitTimeWeek = "Semaine" -UnitTimeMonth = "Mois" -UnitTimeYear = "Année" -UnitDistanceMenu = "Distance" -UnitDistanceMeterMenu = "Mètre" -UnitDistanceMeterKilo = "Kilomètre" -UnitDistanceMeter = "Mètre" -UnitDistanceMeterMilli = "Millimètre" -UnitDistanceMeterMicro = "Micromètre" -UnitDistanceMeterNano = "Nanomètre" -UnitDistanceMeterPico = "Picomètre" -UnitDistanceAstronomicalUnit = "Unité astronomique" -UnitDistanceLightYear = "Année lumière" +Unit = "Unità" +UnitTimeMenu = "Tempo" +UnitTimeSecondMenu = "Secondo" +UnitTimeSecond = "Secondo" +UnitTimeSecondMilli = "Millisecondo" +UnitTimeSecondMicro = "Microsecondo" +UnitTimeSecondNano = "Nanosecondo" +UnitTimeMinute = "Minuto" +UnitTimeHour = "Ora" +UnitTimeDay = "Giorno" +UnitTimeWeek = "Settimana" +UnitTimeMonth = "Mese" +UnitTimeYear = "Anno" +UnitDistanceMenu = "Distanza" +UnitDistanceMeterMenu = "Metro" +UnitDistanceMeterKilo = "Chilometro" +UnitDistanceMeter = "Metro" +UnitDistanceMeterMilli = "Millimetro" +UnitDistanceMeterMicro = "Micrometro" +UnitDistanceMeterNano = "Nanometro" +UnitDistanceMeterPico = "Picometro" +UnitDistanceAstronomicalUnit = "Unità astronomica" +UnitDistanceLightYear = "Anno luce" UnitDistanceParsec = "Parsec" -UnitMassMenu = "Masse" -UnitMassGramKilo = "Kilogramme" -UnitMassGram = "Gramme" -UnitMassGramMilli = "Milligramme" -UnitMassGramMicro = "Microgramme" -UnitMassGramNano = "Nanogramme" -UnitMassTonne = "Tonne" -UnitCurrentMenu = "Intensité du courant électrique" -UnitCurrentAmpere = "Ampère" -UnitCurrentAmpereMilli = "Milliampère" -UnitCurrentAmpereMicro = "Microampère" -UnitTemperatureMenu = "Température" +UnitMassMenu = "Massa" +UnitMassGramKilo = "Kilogrammo" +UnitMassGram = "Grammo" +UnitMassGramMilli = "Milligrammo" +UnitMassGramMicro = "Microgrammo" +UnitMassGramNano = "Nanogrammo" +UnitMassTonne = "Tonnellata" +UnitCurrentMenu = "Intensità di corrente elettrica" +UnitCurrentAmpere = "Ampere" +UnitCurrentAmpereMilli = "Milliampere" +UnitCurrentAmpereMicro = "Microampere" +UnitTemperatureMenu = "Temperatura" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "Quantité de matière" +UnitAmountMenu = "Quantità de materia" UnitAmountMole = "Mole" UnitAmountMoleMilli = "Millimole" UnitAmountMoleMicro = "Micromole" -UnitLuminousIntensityMenu = "Intensité lumineuse" +UnitLuminousIntensityMenu = "Intensità luminosa" UnitLuminousIntensityCandela = "Candela" -UnitFrequencyMenu = "Fréquence" +UnitFrequencyMenu = "Frequenza" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" UnitFrequencyHertz = "Hertz" -UnitForceMenu = "Force" +UnitForceMenu = "Forza" UnitForceNewtonKilo = "Kilonewton" UnitForceNewton = "Newton" UnitForceNewtonMilli = "Millinewton" -UnitPressureMenu = "Pression" +UnitPressureMenu = "Pressione" UnitPressurePascal = "Pascal" UnitPressurePascalHecto = "Hectopascal" UnitPressureBar = "Bar" -UnitPressureAtm = "Atmosphère" -UnitEnergyMenu = "Énergie" +UnitPressureAtm = "Atmosfera" +UnitEnergyMenu = "Energia" UnitEnergyJouleMenu = "Joule" UnitEnergyJouleKilo = "Kilojoule" UnitEnergyJoule = "Joule" @@ -65,103 +65,103 @@ UnitEnergyElectronVoltMega = "Megaelectronvolt" UnitEnergyElectronVoltKilo = "Kiloelectronvolt" UnitEnergyElectronVolt = "Electronvolt" UnitEnergyElectronVoltMilli = "Millielectronvolt" -UnitPowerMenu = "Puissance" +UnitPowerMenu = "Potenza" UnitPowerWattGiga = "Gigawatt" UnitPowerWattMega = "Megawatt" UnitPowerWattKilo = "Kilowatt" UnitPowerWatt = "Watt" UnitPowerWattMilli = "Milliwatt" UnitPowerWattMicro = "Microwatt" -UnitElectricChargeMenu = "Charge électrique" +UnitElectricChargeMenu = "Carica elettrica" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "Tension électrique" +UnitPotentialMenu = "Tensione elettrica" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" UnitPotentialVoltMilli = "Millivolt" UnitPotentialVoltMicro = "Microvolt" -UnitCapacitanceMenu = "Capacité électrique" +UnitCapacitanceMenu = "Capacità elettrica" UnitCapacitanceFarad = "Farad" UnitCapacitanceFaradMilli = "Millifarad" UnitCapacitanceFaradMicro = "Microfarad" -UnitResistanceMenu = "Résistance électrique" +UnitResistanceMenu = "Resistenza elettrica" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "Conductance électrique" +UnitConductanceMenu = "Conduttanza elettrica" UnitConductanceSiemens = "Siemens" UnitConductanceSiemensMilli = "Millisiemens" -UnitMagneticFieldMenu = "Induction électromagnétique" +UnitMagneticFieldMenu = "Induzione elettromagnetica" UnitMagneticFieldTesla = "Tesla" -InductanceMenu = "Inductance" +InductanceMenu = "Induttanza" UnitInductanceHenry = "Henry" UnitSurfaceMenu = "Superficie" -UnitSurfaceHectar = "Hectare" +UnitSurfaceHectar = "Ettaro" UnitVolumeMenu = "Volume" -UnitVolumeLiter = "Litre" -UnitVolumeLiterDeci = "Decilitre" -UnitVolumeLiterCenti = "Centilitre" -UnitVolumeLiterMilli = "Millilitre" -Toolbox = "Boîte à outils" -AbsoluteValue = "Valeur absolue" -NthRoot = "Racine n-ième" -BasedLogarithm = "Logarithme base a" -Calculation = "Calcul" -ComplexNumber = "Nombres complexes" -Combinatorics = "Dénombrement" -Arithmetic = "Arithmétique" -Matrices = "Matrices" -NewMatrix = "Nouvelle matrice" -Identity = "Matrice identité de taille n" -Lists = "Listes" -HyperbolicTrigonometry = "Trigonométrie hyperbolique" -Fluctuation = "Intervalle de fluctuation" -DerivateNumber = "Nombre derivé" -Integral = "Intégrale" -Sum = "Somme" -Product = "Produit" -ComplexAbsoluteValue = "Module" -Agument = "Argument" -RealPart = "Partie réelle" -ImaginaryPart = "Partie imaginaire" -Conjugate = "Conjugué" -Combination = "k parmi n" -Permutation = "Arrangement" -GreatCommonDivisor = "PGCD" -LeastCommonMultiple = "PPCM" -Remainder = "Reste de la division de p par q" -Quotient = "Quotient de la division de p par q" -Inverse = "Inverse" -Determinant = "Déterminant" -Transpose = "Transposée" -Trace = "Trace" -Dimension = "Taille" -Sort = "Tri croissant" -InvSort = "Tri décroissant" -Maximum = "Maximum" -Minimum = "Minimum" -Floor = "Partie entière" -FracPart = "Partie fractionnaire" -Ceiling = "Plafond" -Rounding = "Arrondi à n décimales" -HyperbolicCosine = "Cosinus hyperbolique" -HyperbolicSine = "Sinus hyperbolique" -HyperbolicTangent = "Tangente hyperbolique" -InverseHyperbolicCosine = "Argument cosinus hyperbolique" -InverseHyperbolicSine = "Argument sinus hyperbolique" -InverseHyperbolicTangent = "Argument tangente hyperbolique" -Prediction95 = "Intervalle fluctuation 95% (Term)" -Prediction = "Intervalle fluctuation simple (2de)" -Confidence = "Intervalle de confiance" -RandomAndApproximation = "Aléatoire et approximation" -RandomFloat = "Nombre décimal dans [0,1[" -RandomInteger = "Entier aléatoire dans [a,b]" -PrimeFactorDecomposition = "Décomposition en facteurs premiers" -NormCDF = "P(X Date: Fri, 13 Mar 2020 10:24:57 +0100 Subject: [PATCH 099/453] [it]changes --- apps/shared.it.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n index adde7f9d8..4ae77bdb6 100644 --- a/apps/shared.it.i18n +++ b/apps/shared.it.i18n @@ -61,7 +61,7 @@ Sci = "sci" SquareSum = "Somma dei quadrati" StandardDeviation = "Deviazione standard" StatTab = "Stats" -Step = "Pas" +Step = "Passo" StorageMemoryFull1 = "La memoria è piena." StorageMemoryFull2 = "Cancellate i dati e riprovate." StoreExpressionNotAllowed = "'store' non è consentito" From 51d20a61640483b3c84cbcd844b461bc53344b9a Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Fri, 13 Mar 2020 11:04:01 +0100 Subject: [PATCH 100/453] [it]changes --- apps/code/catalog.it.i18n | 2 +- apps/toolbox.it.i18n | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 5628eff94..21accb3c5 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -5,7 +5,7 @@ PythonLF = "Nuova riga" PythonTab = "Tabulazione" PythonAmpersand = "Congiunzione" PythonSymbolExp = "Disgiunzione esclusiva" -PythonVerticalBar = "Disgiunzione" +PythonVerticalBar = "Disgiunzione" PythonImag = "Parte immaginaria di z" PythonReal = "Parte reale di z" PythonSingleQuote = "Apostrofo" diff --git a/apps/toolbox.it.i18n b/apps/toolbox.it.i18n index 14c8b7ddc..179be7b55 100644 --- a/apps/toolbox.it.i18n +++ b/apps/toolbox.it.i18n @@ -123,12 +123,12 @@ Agument = "Argomento" RealPart = "Parte reale" ImaginaryPart = "Parte immaginaria" Conjugate = "Coniugato" -Combination = "k tra n" -Permutation = "Disposizione" +Combination = "Combinazione" +Permutation = "Permutazione" GreatCommonDivisor = "MCD" LeastCommonMultiple = "mcm" -Remainder = "Resto divisione di p per q" -Quotient = "Quoziente divisione di p per q" +Remainder = "Resto divisione p/q" +Quotient = "Quoziente divisione p/q" Inverse = "Inversa" Determinant = "Determinante" Transpose = "Trasposta" @@ -138,20 +138,20 @@ Sort = "Ordine crescente" InvSort = "Ordine decrescente" Maximum = "Massimo" Minimum = "Minimo" -Floor = "Parte intera" +Floor = "Parte intera inferiore" FracPart = "Parte frazionaria" Ceiling = "Parte intera superiore" -Rounding = "Arrotondato a n decimali" +Rounding = "Arrotonda a n decimali" HyperbolicCosine = "Coseno iperbolico" HyperbolicSine = "Seno iperbolico" HyperbolicTangent = "Tangente iperbolica" -InverseHyperbolicCosine = "Argomento coseno iperbolico" -InverseHyperbolicSine = "Argomento seno iperbolico" -InverseHyperbolicTangent = "Argomento tangente iperbolico" +InverseHyperbolicCosine = "Coseno iperbolico inverso" +InverseHyperbolicSine = "Seno iperbolico inverso" +InverseHyperbolicTangent = "Tangente iperbolica inversa" Prediction95 = "Intervallo di previsione al 95%" Prediction = "Intervallo di previsione semplice" Confidence = "Intervallo di confidenza" -RandomAndApproximation = "Aleatorio e approssimazione" +RandomAndApproximation = "Aleatorietà e approssimazione" RandomFloat = "Numero decimale in [0,1[" RandomInteger = "Intero aleatorio tra [a,b]" PrimeFactorDecomposition = "Scomposizione in fattori primi" From 40a1f1a10c1d51564c351c8f8ffa575361ef86ec Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Fri, 13 Mar 2020 11:29:32 +0100 Subject: [PATCH 101/453] [it]changes --- apps/settings/base.it.i18n | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n index bf81e9990..84333c2a0 100644 --- a/apps/settings/base.it.i18n +++ b/apps/settings/base.it.i18n @@ -3,7 +3,7 @@ SettingsAppCapital = "IMPOSTAZIONI" AngleUnit = "Misura angolo" DisplayMode = "Formato risultato" EditionMode = "Formato scrittura" -EditionLinear = "Lineare " +EditionLinear = "In linea " Edition2D = "Naturale " ComplexFormat = "Formato complesso" ExamMode = "Modalità Esame" @@ -26,7 +26,7 @@ Gradians = "Gradienti " Radian = "Radianti " Decimal = "Decimale " Scientific = "Scientifico " -Engineering = "Engineering " +Engineering = "Ingegneristico " SignificantFigures = "Cifre significative " Real = "Reale " Cartesian = "Algebrico " From 883455c9580d9f08fba98ad9fe6895f8fc21b043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 11:51:28 +0200 Subject: [PATCH 102/453] [apps] IT and NL iso6391 definitions --- apps/language_it_iso6391.universal.i18n | 1 + apps/language_nl_iso6391.universal.i18n | 1 + 2 files changed, 2 insertions(+) create mode 100644 apps/language_it_iso6391.universal.i18n create mode 100644 apps/language_nl_iso6391.universal.i18n diff --git a/apps/language_it_iso6391.universal.i18n b/apps/language_it_iso6391.universal.i18n new file mode 100644 index 000000000..6a72c7216 --- /dev/null +++ b/apps/language_it_iso6391.universal.i18n @@ -0,0 +1 @@ +LanguageISO6391IT = "it" diff --git a/apps/language_nl_iso6391.universal.i18n b/apps/language_nl_iso6391.universal.i18n new file mode 100644 index 000000000..0fef88fd0 --- /dev/null +++ b/apps/language_nl_iso6391.universal.i18n @@ -0,0 +1 @@ +LanguageISO6391NL = "nl" From c9d72295669f8ead242fe9197c254f3be9538635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 11:53:13 +0200 Subject: [PATCH 103/453] [apps/code] Fix ' characters --- apps/code/catalog.it.i18n | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 21accb3c5..6153d4db8 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -10,7 +10,7 @@ PythonImag = "Parte immaginaria di z" PythonReal = "Parte reale di z" PythonSingleQuote = "Apostrofo" PythonAbs = "Valore assoluto/Modulo" -PythonAcos = "Coseno d’arco" +PythonAcos = "Coseno d'arco" PythonAcosh = "Coseno iperbolico inverso" PythonAppend = "Inserisce x alla fine della lista" PythonAsin = "Arco sinusoidale" @@ -162,7 +162,7 @@ PythonTurtleFunction = "Prefisso di funzione del modello turtle" PythonTurtleGoto = "Spostati alle coordinate (x,y)" PythonTurtleGreen = "Colore verde" PythonTurtleGrey = "Colore grigio" -PythonTurtleHeading = "Restituisce l’orientamento attuale" +PythonTurtleHeading = "Restituisce l'orientamento attuale" PythonTurtleHideturtle = "Nascondi la tartaruga" PythonTurtleIsdown = "True se la penna è abbassata" PythonTurtleLeft = "Ruota di a gradi a sinistra" @@ -176,7 +176,7 @@ PythonTurtlePurple = "Colore viola" PythonTurtleRed = "Colore rosso" PythonTurtleReset = "Azzera il disegno" PythonTurtleRight = "Ruota di a gradi a destra" -PythonTurtleSetheading = "Imposta l’orientamento per a gradi" +PythonTurtleSetheading = "Imposta l'orientamento per a gradi" PythonTurtleSetposition = "Posiziona la tartaruga" PythonTurtleShowturtle = "Mostra la tartaruga" PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)" From 64a221a72c130233d6943a4e07d027113e4d3f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 12:15:09 +0200 Subject: [PATCH 104/453] [apps/code] Add missing i18n (not translated yet) --- apps/code/catalog.it.i18n | 11 +++++++++++ apps/code/catalog.nl.i18n | 13 ++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 6153d4db8..8bcaf8b20 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -13,11 +13,14 @@ PythonAbs = "Valore assoluto/Modulo" PythonAcos = "Coseno d'arco" PythonAcosh = "Coseno iperbolico inverso" PythonAppend = "Inserisce x alla fine della lista" +PythonArrow = "Draw an arrow from (x,y) to (x+dx,y+dy)" PythonAsin = "Arco sinusoidale" PythonAsinh = "Arco sinusoidale iperbolico" PythonAtan = "Arco tangente" PythonAtan2 = "Calcolo di atan(y/x)" PythonAtanh = "Arco tangente iperbolico" +PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Draw a bar plot with x values" PythonBin = "Converte un intero in binario" PythonCeil = "Parte intera superiore" PythonChoice = "Numero aleatorio nella lista" @@ -46,12 +49,15 @@ PythonFrExp = "Mantissa ed esponente di x : (m,e)" PythonGamma = "Funzione gamma" PythonGetPixel = "Restituisce il colore del pixel(x,y)" PythonGetrandbits = "Numero aleatorio con k bit" +PythonGrid = "Toggle the visibility of the grid" PythonHex = "Conversione intero in esadecimale" +PythonHist = "Draw the histogram of x" PythonImportCmath = "Importazione del modulo cmath" PythonImportIon = "Importazione del modulo ion" PythonImportKandinsky = "Importazione del modulo kandinsky" PythonImportRandom = "Importazione del modulo random" PythonImportMath = "Importazione del modulo math" +PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" PythonImportTurtle = "Importazione del modulo turtle" PythonImportTime = "Importazione del modulo time" PythonIndex = "Indice prima occorrenza di x" @@ -117,12 +123,14 @@ PythonLog = "Logaritmo di base a" PythonLog10 = "Logaritmo decimale" PythonLog2 = "Logaritmo di base 2" PythonMathFunction = "Prefisso funzione del modulo math" +PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" PythonMax = "Massimo" PythonMin = "Minimo" PythonModf = "Parti frazionarie e intere" PythonMonotonic = "Restituisce il valore dell'orologio" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" +PythonPlot = "Plot y versus x as lines" PythonPolar = "Conversione in polare" PythonPop = "Cancella l'ultimo elemento" PythonPower = "x alla potenza y" @@ -138,8 +146,10 @@ PythonRect = "Conversione in coordinate algebriche" PythonRemove = "Cancella la prima x dalla liste" PythonReverse = "Inverte gli elementi della lista" PythonRound = "Arrotondato a n cifre decimali" +PythonScatter = "Draw a scatter plot of y versus x" PythonSeed = "Inizializza il generatore random" PythonSetPixel = "Colora il pixel (x,y)" +PythonShow = "Display the figure" PythonSin = "Seno" PythonSinh = "Seno iperbolico" PythonSleep = "Sospende l'esecuzione t secondi" @@ -148,6 +158,7 @@ PythonSqrt = "Radice quadrata" PythonSum = "Somma degli elementi della lista" PythonTan = "Tangente" PythonTanh = "Tangente iperbolica" +PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "Prefisso funzione modulo time" PythonTrunc = "Troncamento intero" PythonTurtleBackward = "Indietreggia di x pixels" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index 739442d0c..571e701f5 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -13,11 +13,14 @@ PythonAbs = "Absolute waarde" PythonAcos = "Arccosinus" PythonAcosh = "Arccosinus hyperbolicus" PythonAppend = "Voeg x toe aan het eind van je lijst" +PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)" PythonAsin = "Arcsinus" PythonAsinh = "Arcsinus hyperbolicus" PythonAtan = "Arctangens" PythonAtan2 = "Geeft atan(y/x)" PythonAtanh = "Arctangens hyperbolicus" +PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Draw a bar plot with x values" PythonBin = "Zet integer om in een binair getal" PythonCeil = "Plafond" PythonChoice = "Geeft willek. getal van de lijst" @@ -46,12 +49,15 @@ PythonFrExp = "Mantisse en exponent van x: (m,e)" PythonGamma = "Gammafunctie" PythonGetPixel = "Geef pixel (x,y) kleur (rgb)" PythonGetrandbits = "Integer met k willekeurige bits" +PythonGrid = "Toggle the visibility of the grid" PythonHex = "Zet integer om in hexadecimaal" +PythonHist = "Draw the histogram of x" PythonImportCmath = "Importeer cmath module" PythonImportIon = "Importeer ion module" PythonImportKandinsky = "Importeer kandinsky module" PythonImportRandom = "Importeer random module" PythonImportMath = "Importeer math module" +PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" PythonImportTime = "Importeer time module" PythonImportTurtle = "Importeer turtle module" PythonIndex = "Index van de eerste x aanwezigheden" @@ -117,12 +123,14 @@ PythonLog = "Logaritme met grondgetal a" PythonLog10 = "Logaritme met grondgetal 10" PythonLog2 = "Logaritme met grondgetal 2" PythonMathFunction = "math module voorvoegsel" +PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Fractionele en gehele delen van x" PythonMonotonic = "Waarde van een monotone klok" PythonOct = "Integer omzetten naar octaal" PythonPhase = "Fase van z in radialen" +PythonPlot = "Plot y versus x as lines" PythonPolar = "z in poolcoördinaten" PythonPop = "Verwijder en breng het laatste item terug" PythonPower = "x tot de macht y" @@ -138,9 +146,11 @@ PythonRect = "z in cartesiaanse coördinaten" PythonRemove = "Verwijder het eerste voorkomen van x" PythonReverse = "Keer de elementen van de lijst om" PythonRound = "Rond af op n cijfers" +PythonScatter = "Draw a scatter plot of y versus x" PythonSeed = "Start willek. getallengenerator" PythonSetPixel = "Kleur pixel (x,y)" -PythonSin = "Sinus" +PythonShow = "Display the figure" +PythonSin= "Sinus" PythonSinh = "Sinus hyperbolicus" PythonSleep = "Stel executie voor t seconden uit" PythonSort = "Sorteer de lijst" @@ -148,6 +158,7 @@ PythonSqrt = "Vierkantswortel" PythonSum = "Sommeer de items van een lijst" PythonTan = "Tangens" PythonTanh = "Tangens hyperbolicus" +PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "time module voorvoegsel" PythonTrunc = "x afgeknot tot een integer" PythonTurtleBackward = "Ga achterwaarts met x pixels" From c7c47acc1b74d4da6a23a38fd5e58435a2110418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 12:21:28 +0200 Subject: [PATCH 105/453] [build/config] Change the languages order --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index a81423662..a879199da 100644 --- a/build/config.mak +++ b/build/config.mak @@ -5,7 +5,7 @@ DEBUG ?= 0 EPSILON_VERSION ?= 13.0.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings -EPSILON_I18N ?= en fr es de pt nl it +EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0 EPSILON_TELEMETRY ?= 0 ESCHER_LOG_EVENTS_BINARY ?= 0 From 8aa323b04312a7d3f6f4904f5d0045d817a5661e Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 21 Apr 2020 14:40:20 +0200 Subject: [PATCH 106/453] [it]python --- apps/code/catalog.it.i18n | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 8bcaf8b20..084d3f60b 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -13,14 +13,14 @@ PythonAbs = "Valore assoluto/Modulo" PythonAcos = "Coseno d'arco" PythonAcosh = "Coseno iperbolico inverso" PythonAppend = "Inserisce x alla fine della lista" -PythonArrow = "Draw an arrow from (x,y) to (x+dx,y+dy)" +PythonArrow = "Disegna una freccia da (x,y) a (x+dx,y+dy)" PythonAsin = "Arco sinusoidale" PythonAsinh = "Arco sinusoidale iperbolico" PythonAtan = "Arco tangente" PythonAtan2 = "Calcolo di atan(y/x)" PythonAtanh = "Arco tangente iperbolico" -PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Draw a bar plot with x values" +PythonAxis = "Impostare gli assi su (xmin,xmax,ymin,ymax)" +PythonBar = "Disegna un grafico a barre con x valori" PythonBin = "Converte un intero in binario" PythonCeil = "Parte intera superiore" PythonChoice = "Numero aleatorio nella lista" @@ -42,22 +42,22 @@ PythonExp = "Funzione esponenziale" PythonExpm1 = "Calcola exp(x)-1" PythonFabs = "Valore assoluto" PythonFillRect = "Riempie un rettangolo" -PythonFloat = "Conversion en flottant" +PythonFloat = "Conversione in flottanti" PythonFloor = "Parte intera" PythonFmod = "a modulo b" PythonFrExp = "Mantissa ed esponente di x : (m,e)" PythonGamma = "Funzione gamma" PythonGetPixel = "Restituisce il colore del pixel(x,y)" PythonGetrandbits = "Numero aleatorio con k bit" -PythonGrid = "Toggle the visibility of the grid" +PythonGrid = "Attivare la visibilità della griglia" PythonHex = "Conversione intero in esadecimale" -PythonHist = "Draw the histogram of x" +PythonHist = "Disegna l'istogramma di x" PythonImportCmath = "Importazione del modulo cmath" PythonImportIon = "Importazione del modulo ion" PythonImportKandinsky = "Importazione del modulo kandinsky" PythonImportRandom = "Importazione del modulo random" PythonImportMath = "Importazione del modulo math" -PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" +PythonImportMatplotlibPyplot = "Importazione del modulo matplotlib.pyplot" PythonImportTurtle = "Importazione del modulo turtle" PythonImportTime = "Importazione del modulo time" PythonIndex = "Indice prima occorrenza di x" @@ -123,14 +123,14 @@ PythonLog = "Logaritmo di base a" PythonLog10 = "Logaritmo decimale" PythonLog2 = "Logaritmo di base 2" PythonMathFunction = "Prefisso funzione del modulo math" -PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" +PythonMatplotlibPyplotFunction = "prefisso del modulo matplotlib.pyplot" PythonMax = "Massimo" PythonMin = "Minimo" PythonModf = "Parti frazionarie e intere" PythonMonotonic = "Restituisce il valore dell'orologio" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" -PythonPlot = "Plot y versus x as lines" +PythonPlot = "Disegna y in funzione di x come linee" PythonPolar = "Conversione in polare" PythonPop = "Cancella l'ultimo elemento" PythonPower = "x alla potenza y" @@ -146,10 +146,10 @@ PythonRect = "Conversione in coordinate algebriche" PythonRemove = "Cancella la prima x dalla liste" PythonReverse = "Inverte gli elementi della lista" PythonRound = "Arrotondato a n cifre decimali" -PythonScatter = "Draw a scatter plot of y versus x" +PythonScatter = "Disegna un diagramma di dispersione di y in funzione di x" PythonSeed = "Inizializza il generatore random" PythonSetPixel = "Colora il pixel (x,y)" -PythonShow = "Display the figure" +PythonShow = "Mostra la figura" PythonSin = "Seno" PythonSinh = "Seno iperbolico" PythonSleep = "Sospende l'esecuzione t secondi" @@ -158,7 +158,7 @@ PythonSqrt = "Radice quadrata" PythonSum = "Somma degli elementi della lista" PythonTan = "Tangente" PythonTanh = "Tangente iperbolica" -PythonText = "Display a text at (x,y) coordinates" +PythonText = "Mostra un testo in (x,y)" PythonTimeFunction = "Prefisso funzione modulo time" PythonTrunc = "Troncamento intero" PythonTurtleBackward = "Indietreggia di x pixels" From e803ada15f98f7178776c725c0b34abffb12c426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 16:22:49 +0200 Subject: [PATCH 107/453] [apps/Makefiles] Automatize i18n adding for different locales --- apps/Makefile | 29 +++++------------------------ apps/calculation/Makefile | 10 +--------- apps/code/Makefile | 29 +++-------------------------- apps/graph/Makefile | 10 +--------- apps/helpers.mk | 19 +++++++++++++++++++ apps/home/Makefile | 10 +--------- apps/on_boarding/Makefile | 10 +--------- apps/probability/Makefile | 11 +---------- apps/regression/Makefile | 11 +---------- apps/sequence/Makefile | 10 +--------- apps/settings/Makefile | 10 +--------- apps/solver/Makefile | 10 +--------- apps/statistics/Makefile | 10 +--------- apps/usb/Makefile | 11 +---------- 14 files changed, 38 insertions(+), 152 deletions(-) create mode 100644 apps/helpers.mk diff --git a/apps/Makefile b/apps/Makefile index 9fc12513d..f7392f395 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,3 +1,4 @@ +include apps/helpers.mk include apps/shared/Makefile include apps/home/Makefile include apps/on_boarding/Makefile @@ -60,30 +61,10 @@ i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_ ifeq ($(EPSILON_GETOPT),1) i18n_files += $(addprefix apps/language_,$(addsuffix _iso6391.universal.i18n, $(EPSILON_I18N))) endif -i18n_files += $(addprefix apps/,\ - shared.de.i18n\ - shared.en.i18n\ - shared.es.i18n\ - shared.fr.i18n\ - shared.it.i18n\ - shared.nl.i18n\ - shared.pt.i18n\ - shared.universal.i18n\ - toolbox.de.i18n\ - toolbox.en.i18n\ - toolbox.es.i18n\ - toolbox.fr.i18n\ - toolbox.it.i18n\ - toolbox.nl.i18n\ - toolbox.pt.i18n\ - variables.de.i18n\ - variables.en.i18n\ - variables.es.i18n\ - variables.fr.i18n\ - variables.it.i18n\ - variables.nl.i18n\ - variables.pt.i18n\ -) + +i18n_files += $(call i18n_with_universal_for,shared) +i18n_files += $(call i18n_without_universal_for,toolbox) +i18n_files += $(call i18n_without_universal_for,variables) $(eval $(call rule_for, \ I18N, \ diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index 9ae808006..453e46cf0 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -33,15 +33,7 @@ app_calculation_src = $(addprefix apps/calculation/,\ app_calculation_src += $(app_calculation_test_src) apps_src += $(app_calculation_src) -i18n_files += $(addprefix apps/calculation/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,calculation/base) tests_src += $(addprefix apps/calculation/test/,\ calculation_store.cpp\ diff --git a/apps/code/Makefile b/apps/code/Makefile index edbb6a3bf..d91713eed 100644 --- a/apps/code/Makefile +++ b/apps/code/Makefile @@ -29,31 +29,8 @@ app_code_src = $(addprefix apps/code/,\ app_code_src += $(app_code_test_src) apps_src += $(app_code_src) -i18n_files += $(addprefix apps/code/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ - base.universal.i18n\ - catalog.de.i18n\ - catalog.en.i18n\ - catalog.es.i18n\ - catalog.fr.i18n\ - catalog.it.i18n\ - catalog.nl.i18n\ - catalog.pt.i18n\ - catalog.universal.i18n\ - toolbox.de.i18n\ - toolbox.en.i18n\ - toolbox.es.i18n\ - toolbox.fr.i18n\ - toolbox.it.i18n\ - toolbox.nl.i18n\ - toolbox.pt.i18n\ - toolbox.universal.i18n\ -) +i18n_files += $(call i18n_with_universal_for,code/base) +i18n_files += $(call i18n_with_universal_for,code/catalog) +i18n_files += $(call i18n_with_universal_for,code/toolbox) $(eval $(call depends_on_image,apps/code/app.cpp,apps/code/code_icon.png)) diff --git a/apps/graph/Makefile b/apps/graph/Makefile index 580cabcfc..4f440fea8 100644 --- a/apps/graph/Makefile +++ b/apps/graph/Makefile @@ -33,14 +33,6 @@ app_graph_src = $(addprefix apps/graph/,\ apps_src += $(app_graph_src) -i18n_files += $(addprefix apps/graph/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,graph/base) $(eval $(call depends_on_image,apps/graph/app.cpp,apps/graph/graph_icon.png)) diff --git a/apps/helpers.mk b/apps/helpers.mk new file mode 100644 index 000000000..1d86bb88c --- /dev/null +++ b/apps/helpers.mk @@ -0,0 +1,19 @@ +# i18n helpers + +# Should be called as: i18n_for_locale basename locale +define i18n_for_locale +$(addprefix apps/, $(addprefix $(1), $(addprefix ., $(addsuffix .i18n,$(2))))) +endef + +# Should be called as: i18n_without_universal_for basename +# Adds the basename.**.i18n for all locales in EPSILON_I18N +define i18n_without_universal_for +$(foreach LOCALE,$(EPSILON_I18N),$(call i18n_for_locale, $(1), $(LOCALE))) +endef + +# Should be called as: i18n_with_universal_for basename +# Adds basename.**.i18n for all EPSILON_I18N locales + basename.universal.i18n +define i18n_with_universal_for +$(call i18n_without_universal_for,$(1)) +$(call i18n_for_locale,$(1),universal) +endef diff --git a/apps/home/Makefile b/apps/home/Makefile index 7a2004e2a..fc45cb479 100644 --- a/apps/home/Makefile +++ b/apps/home/Makefile @@ -6,12 +6,4 @@ app_home_src = $(addprefix apps/home/,\ apps_src += $(app_home_src) -i18n_files += $(addprefix apps/home/,\ - base.de.i18n \ - base.en.i18n \ - base.es.i18n \ - base.fr.i18n \ - base.it.i18n\ - base.nl.i18n \ - base.pt.i18n \ -) +i18n_files += $(call i18n_without_universal_for,home/base) diff --git a/apps/on_boarding/Makefile b/apps/on_boarding/Makefile index 9941b02d7..42d22f508 100644 --- a/apps/on_boarding/Makefile +++ b/apps/on_boarding/Makefile @@ -9,14 +9,6 @@ app_on_boarding_src = $(addprefix apps/on_boarding/,\ apps_src += $(app_on_boarding_src) -i18n_files += $(addprefix apps/on_boarding/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,on_boarding/base) $(eval $(call depends_on_image,apps/on_boarding/logo_view.cpp,apps/on_boarding/logo_icon.png)) diff --git a/apps/probability/Makefile b/apps/probability/Makefile index 72f2ee19d..d22f88d48 100644 --- a/apps/probability/Makefile +++ b/apps/probability/Makefile @@ -40,16 +40,7 @@ app_probability_src = $(addprefix apps/probability/,\ app_probability_src += $(app_probability_test_src) apps_src += $(app_probability_src) -i18n_files += $(addprefix apps/probability/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ - base.universal.i18n\ -) +i18n_files += $(call i18n_with_universal_for,probability/base) tests_src += $(addprefix apps/probability/test/,\ hypergeometric_function.cpp\ diff --git a/apps/regression/Makefile b/apps/regression/Makefile index 117279718..2211e3192 100644 --- a/apps/regression/Makefile +++ b/apps/regression/Makefile @@ -40,16 +40,7 @@ app_regression_src = $(addprefix apps/regression/,\ app_regression_src += $(app_regression_test_src) apps_src += $(app_regression_src) -i18n_files += $(addprefix apps/regression/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ - base.universal.i18n\ -) +i18n_files += $(call i18n_with_universal_for,regression/base) tests_src += $(addprefix apps/regression/test/,\ model.cpp\ diff --git a/apps/sequence/Makefile b/apps/sequence/Makefile index 818166e6f..f36277bca 100644 --- a/apps/sequence/Makefile +++ b/apps/sequence/Makefile @@ -28,15 +28,7 @@ app_sequence_src = $(addprefix apps/sequence/,\ app_sequence_src += $(app_sequence_test_src) apps_src += $(app_sequence_src) -i18n_files += $(addprefix apps/sequence/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,sequence/base) tests_src += $(addprefix apps/sequence/test/,\ sequence.cpp\ diff --git a/apps/settings/Makefile b/apps/settings/Makefile index e05c24692..8f954d668 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -25,14 +25,6 @@ app_settings_src = $(addprefix apps/settings/,\ app_settings_src += $(app_settings_test_src) apps_src += $(app_settings_src) -i18n_files += $(addprefix apps/settings/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,settings/base) $(eval $(call depends_on_image,apps/settings/app.cpp,apps/settings/settings_icon.png)) diff --git a/apps/solver/Makefile b/apps/solver/Makefile index ef9ca6700..63b222173 100644 --- a/apps/solver/Makefile +++ b/apps/solver/Makefile @@ -18,15 +18,7 @@ app_solver_src = $(addprefix apps/solver/,\ app_solver_src += $(app_solver_test_src) apps_src += $(app_solver_src) -i18n_files += $(addprefix apps/solver/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,solver/base) tests_src += $(addprefix apps/solver/test/,\ equation_store.cpp \ diff --git a/apps/statistics/Makefile b/apps/statistics/Makefile index 3ba260a2a..d29964dfe 100644 --- a/apps/statistics/Makefile +++ b/apps/statistics/Makefile @@ -29,15 +29,7 @@ app_statistics_src = $(addprefix apps/statistics/,\ app_statistics_src += $(app_statistics_test_src) apps_src += $(app_statistics_src) -i18n_files += $(addprefix apps/statistics/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ -) +i18n_files += $(call i18n_without_universal_for,statistics/base) tests_src += $(addprefix apps/statistics/test/,\ store.cpp\ diff --git a/apps/usb/Makefile b/apps/usb/Makefile index 0ccf53019..79692e351 100644 --- a/apps/usb/Makefile +++ b/apps/usb/Makefile @@ -5,13 +5,4 @@ app_usb_src = $(addprefix apps/usb/,\ apps_src += $(app_usb_src) -i18n_files += $(addprefix apps/usb/,\ - base.de.i18n\ - base.en.i18n\ - base.es.i18n\ - base.fr.i18n\ - base.it.i18n\ - base.nl.i18n\ - base.pt.i18n\ - base.universal.i18n\ -) +i18n_files += $(call i18n_with_universal_for,usb/base) From 21e4af967a76e36a3cab0cc26812a5746c391c63 Mon Sep 17 00:00:00 2001 From: Serenela Moreira Date: Tue, 21 Apr 2020 15:31:06 +0100 Subject: [PATCH 108/453] [pt] base and catalog translations new translations that were missing after version 13 --- apps/calculation/base.pt.i18n | 14 +++++++------- apps/code/catalog.pt.i18n | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/calculation/base.pt.i18n b/apps/calculation/base.pt.i18n index 36d7a8bdb..0d9210d09 100644 --- a/apps/calculation/base.pt.i18n +++ b/apps/calculation/base.pt.i18n @@ -1,9 +1,9 @@ CalculApp = "Cálculo" CalculAppCapital = "CÁLCULO" -AdditionalResults = "????" -DecimalBase = "????" -HexadecimalBase = "????" -BinaryBase = "????" -PrimeFactors = "????" -MixedFraction = "????" -EuclideanDivision = "????" +AdditionalResults = "Resultados Adicionais" +DecimalBase = "Decimal" +HexadecimalBase = "Hexadecimal" +BinaryBase = "Binário" +PrimeFactors = "Fatores primos" +MixedFraction = "Fração mista" +EuclideanDivision = "Divisão euclidiana" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index d991fb104..5d3b58e78 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -13,14 +13,14 @@ PythonAbs = "Valor absoluto/módulo" PythonAcos = "Arco cosseno" PythonAcosh = "Arco cosseno hiperbólico" PythonAppend = "Adicionar x no fim da lista" -PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)" +PythonArrow = "Seta de (x,y) para (x+dx,y+dy)" PythonAsin = "Arco seno" PythonAsinh = "Arco seno hiperbólico" PythonAtan = "Arco tangente" PythonAtan2 = "Cálculo de atan(y/x)" PythonAtanh = "Arco tangente hiperbólica" -PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Draw a bar plot with x values" +PythonAxis = "Definir eixos (xmin,xmax,ymin,ymax)" +PythonBar = "Gráfico de barras com valores de x" PythonBin = "Converter número inteiro em binário" PythonCeil = "Teto" PythonChoice = "Número aleatório na lista" @@ -49,15 +49,15 @@ PythonFrExp = "Coeficiente e expoente de x: (m, e)" PythonGamma = "Função gama" PythonGetPixel = "Devolve a cor do pixel (x,y)" PythonGetrandbits = "Número inteiro aleatório com k bits" -PythonGrid = "Toggle the visibility of the grid" +PythonGrid = "Alterar visibilidade da grelha" PythonHex = "Converter inteiro em hexadecimal" -PythonHist = "Draw the histogram of x" +PythonHist = "Desenhar o histograma de x" PythonImportCmath = "Importar módulo cmath" PythonImportIon = "Importar módulo ion" PythonImportKandinsky = "Importar módulo kandinsky" PythonImportRandom = "Importar módulo random" PythonImportMath = "Importar módulo math" -PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" +PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot" PythonImportTime = "Importar módulo time" PythonImportTurtle = "Importar módulo turtle" PythonIndex = "Índice da primeira ocorrência de x" @@ -123,14 +123,14 @@ PythonLog = "Logaritmo de base a" PythonLog10 = "Logaritmo de base 10" PythonLog2 = "Logaritmo de base 2" PythonMathFunction = "Prefixo da função do módulo math" -PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" +PythonMatplotlibPyplotFunction = "Prefixo do módulo matplotlib.pyplot" PythonMax = "Máximo" PythonMin = "Mínimo" PythonModf = "Partes inteira e frácionária de x" PythonMonotonic = "Devolve o valor do relógio" PythonOct = "Converter número inteiro em octal" PythonPhase = "Argumento de z" -PythonPlot = "Plot y versus x as lines" +PythonPlot = "Desenhar y em função de x" PythonPolar = "z em coordenadas polares" PythonPop = "Remover o último item" PythonPower = "x levantado a y" @@ -142,14 +142,14 @@ PythonRandomFunction = "Prefixo da função do módulo random" PythonRandrange = "Número aleatório em [start,stop-1]" PythonRangeStartStop = "Lista de start a stop-1" PythonRangeStop = "Lista de 0 a stop-1" -PythonRect = "z em coordenadas cartesianas" +PythonRect = "Converter para coordenadas cartesianas" PythonRemove = "Remover a primeira ocorrência de x" PythonReverse = "Inverter os elementos da lista" PythonRound = "Arredondar para n dígitos" -PythonScatter = "Draw a scatter plot of y versus x" +PythonScatter = "Gráfico de dispersão (x,y)" PythonSeed = "Iniciar gerador aleatório" PythonSetPixel = "Cor do pixel (x,y)" -PythonShow = "Display the figure" +PythonShow = "Mostrar a figura" PythonSin = "Seno" PythonSinh = "Seno hiperbólico" PythonSleep = "Suspender a execução por t segundos" @@ -158,7 +158,7 @@ PythonSqrt = "Raiz quadrada" PythonSum = "Soma dos itens da lista" PythonTan = "Tangente" PythonTanh = "Tangente hiperbólica" -PythonText = "Display a text at (x,y) coordinates" +PythonText = "Mostrar um texto em (x,y)" PythonTimeFunction = "Prefixo da função do módulo time" PythonTrunc = "x truncado a um número inteiro" PythonTurtleBackward = "Recuar x pixels" From 33ebd3d1aaf4240663a50c4caccc3dd7644084da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 16:45:35 +0200 Subject: [PATCH 109/453] [apps/pt] Remove superfluous upper case --- apps/calculation/base.pt.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/base.pt.i18n b/apps/calculation/base.pt.i18n index 0d9210d09..b8e8717aa 100644 --- a/apps/calculation/base.pt.i18n +++ b/apps/calculation/base.pt.i18n @@ -1,6 +1,6 @@ CalculApp = "Cálculo" CalculAppCapital = "CÁLCULO" -AdditionalResults = "Resultados Adicionais" +AdditionalResults = "Resultados adicionais" DecimalBase = "Decimal" HexadecimalBase = "Hexadecimal" BinaryBase = "Binário" From 6cd9b744e153c4e478fceb70c61423868d214b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 17:34:30 +0200 Subject: [PATCH 110/453] [apps/code] Fix some toolbox descriptions --- apps/code/catalog.de.i18n | 2 +- apps/code/catalog.en.i18n | 2 +- apps/code/catalog.es.i18n | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 0a9e9c71d..f29a4e305 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -45,7 +45,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)" PythonFloat = "Convert x to a float" PythonFloor = "Floor" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" +PythonFrExp = "Mantissa and exponent of x: (m,e)" PythonGamma = "Gamma function" PythonGetPixel = "Return pixel (x,y) color" PythonGetrandbits = "Integer with k random bits" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 90c1903f9..fd514a811 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -45,7 +45,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)" PythonFloat = "Convert x to a float" PythonFloor = "Floor" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" +PythonFrExp = "Mantissa and exponent of x: (m,e)" PythonGamma = "Gamma function" PythonGetPixel = "Return pixel (x,y) color" PythonGetrandbits = "Integer with k random bits" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index a480d11b1..d98508b1c 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -45,7 +45,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)" PythonFloat = "Convert x to a float" PythonFloor = "Floor" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" +PythonFrExp = "Mantissa and exponent of x: (m,e)" PythonGamma = "Gamma function" PythonGetPixel = "Return pixel (x,y) color" PythonGetrandbits = "Integer with k random bits" From e542296b81099f9c406eb97d9e00ebcbb811203b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 21 Apr 2020 18:00:15 +0200 Subject: [PATCH 111/453] [apps/shared.i18n] Remove unused value --- apps/shared.de.i18n | 1 - apps/shared.en.i18n | 1 - apps/shared.es.i18n | 1 - apps/shared.fr.i18n | 1 - apps/shared.it.i18n | 1 - apps/shared.nl.i18n | 1 - apps/shared.pt.i18n | 1 - 7 files changed, 7 deletions(-) diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index c470e3775..5ed8c2101 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -73,7 +73,6 @@ TStart = "T Startwert" ToZoom = "Zoom: " Trigonometric = "Trigonometrisch" UndefinedValue = "Nicht definierter Wert" -ValueNotReachedByFunction = "Der Wert wird von der Funktion nicht erreicht" ValuesTab = "Tabelle" Warning = "Achtung" XEnd = "X Endwert" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 761eabbb9..4adfebb8d 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -73,7 +73,6 @@ TStart = "T start" ToZoom = "Zoom: " Trigonometric = "Trigonometrical" UndefinedValue = "Undefined value" -ValueNotReachedByFunction = "Value not reached by function" ValuesTab = "Table" Warning = "Warning" XEnd = "X end" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index fa05139c1..e0a1ab4de 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -73,7 +73,6 @@ TStart = "T inicio" ToZoom = "Zoom : " Trigonometric = "Trigonométrico" UndefinedValue = "Valor indefinido" -ValueNotReachedByFunction = "No se alcanza este valor" ValuesTab = "Tabla" Warning = "Cuidado" XEnd = "X fin" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 22842405f..67729237d 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -73,7 +73,6 @@ TStart = "T début" ToZoom = "Zoomer : " Trigonometric = "Trigonométrique" UndefinedValue = "Valeur non définie" -ValueNotReachedByFunction = "Valeur non atteinte par la fonction" ValuesTab = "Tableau" Warning = "Attention" XEnd = "X fin" diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n index 4ae77bdb6..cd058299b 100644 --- a/apps/shared.it.i18n +++ b/apps/shared.it.i18n @@ -73,7 +73,6 @@ TStart = "T iniziale" ToZoom = "Ingrandire : " Trigonometric = "Trigonometrica" UndefinedValue = "Valore non definito" -ValueNotReachedByFunction = "Valore non raggiunto dalla funzione" ValuesTab = "Tabella" Warning = "Attenzione" XEnd = "X finale" diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index 87cf82d2e..00a69365f 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -73,7 +73,6 @@ TStart = "T begin" ToZoom = "Zoom: " Trigonometric = "Goniometrisch" UndefinedValue = "Ongedefinieerde waarde" -ValueNotReachedByFunction = "Waarde niet bereikt door functie" ValuesTab = "Tabel" Warning = "Waarschuwing" XEnd = "X einde" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 7dced5099..0fc30061e 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -73,7 +73,6 @@ TStart = "T início" ToZoom = "Zoom : " Trigonometric = "Trigonométrico" UndefinedValue = "Valor indefinido" -ValueNotReachedByFunction = "O valor não é alcançado pela função" ValuesTab = "Tabela" Warning = "Atenção" XEnd = "X fim" From e203f7ae086149a539fd2dced633e1e30fc4171a Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 21 Apr 2020 16:55:48 +0200 Subject: [PATCH 112/453] [it]Forma --- apps/settings/base.it.i18n | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n index 84333c2a0..8ce5e37f3 100644 --- a/apps/settings/base.it.i18n +++ b/apps/settings/base.it.i18n @@ -1,11 +1,11 @@ SettingsApp = "Impostazioni" SettingsAppCapital = "IMPOSTAZIONI" AngleUnit = "Misura angolo" -DisplayMode = "Formato risultato" -EditionMode = "Formato scrittura" +DisplayMode = "Forma risultato" +EditionMode = "Forma scrittura" EditionLinear = "In linea " Edition2D = "Naturale " -ComplexFormat = "Formato complesso" +ComplexFormat = "Forma complessa" ExamMode = "Modalità Esame" ExamModeActive = "Riattivare modalità Esame" ToDeactivateExamMode1 = "Per disattivare la modalità esame," From 98da319a2bc202c2bdd5e571b22d2f0f4d456f26 Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 21 Apr 2020 18:30:53 +0200 Subject: [PATCH 113/453] [it]python --- apps/code/catalog.it.i18n | 54 +++++++++++++++++++------------------- apps/settings/base.it.i18n | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 084d3f60b..4e10351f5 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -19,22 +19,22 @@ PythonAsinh = "Arco sinusoidale iperbolico" PythonAtan = "Arco tangente" PythonAtan2 = "Calcolo di atan(y/x)" PythonAtanh = "Arco tangente iperbolico" -PythonAxis = "Impostare gli assi su (xmin,xmax,ymin,ymax)" -PythonBar = "Disegna un grafico a barre con x valori" +PythonAxis = "Imposta assi su (xmin,xmax,ymin,ymax)" +PythonBar = "Disegna grafico a barre con x valori" PythonBin = "Converte un intero in binario" PythonCeil = "Parte intera superiore" PythonChoice = "Numero aleatorio nella lista" PythonClear = "Svuota la lista" -PythonCmathFunction = "Funzione prefissata del modulo cmath" +PythonCmathFunction = "Funzione prefissata modulo cmath" PythonColor = "Definisci un colore rvb" PythonComplex = "Restituisce a+ib" -PythonCopySign = "Restituisce x avec le signe de y" +PythonCopySign = "Restituisce x con segno di y" PythonCos = "Coseno" PythonCosh = "Coseno iperbolico" -PythonCount = "Compte les occurrences de x" +PythonCount = "Conta le ricorrenze di x" PythonDegrees = "Conversione di radianti in gradi" PythonDivMod = "Quoziente e resto" -PythonDrawString = "Visualizza il text dal pixel x,y" +PythonDrawString = "Visualizza il testo dal pixel x,y" PythonErf = "Funzione d'errore" PythonErfc = "Funzione d'errore complementare" PythonEval = "Valuta l'espressione nell'argomento " @@ -47,19 +47,19 @@ PythonFloor = "Parte intera" PythonFmod = "a modulo b" PythonFrExp = "Mantissa ed esponente di x : (m,e)" PythonGamma = "Funzione gamma" -PythonGetPixel = "Restituisce il colore del pixel(x,y)" +PythonGetPixel = "Restituisce colore del pixel(x,y)" PythonGetrandbits = "Numero aleatorio con k bit" -PythonGrid = "Attivare la visibilità della griglia" +PythonGrid = "Attiva la visibilità della griglia" PythonHex = "Conversione intero in esadecimale" PythonHist = "Disegna l'istogramma di x" -PythonImportCmath = "Importazione del modulo cmath" -PythonImportIon = "Importazione del modulo ion" -PythonImportKandinsky = "Importazione del modulo kandinsky" -PythonImportRandom = "Importazione del modulo random" -PythonImportMath = "Importazione del modulo math" -PythonImportMatplotlibPyplot = "Importazione del modulo matplotlib.pyplot" -PythonImportTurtle = "Importazione del modulo turtle" -PythonImportTime = "Importazione del modulo time" +PythonImportCmath = "Importa modulo cmath" +PythonImportIon = "Importa modulo ion" +PythonImportKandinsky = "Importa modulo kandinsky" +PythonImportRandom = "Importa modulo random" +PythonImportMath = "Importa modulo math" +PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot" +PythonImportTurtle = "Importa del modulo turtle" +PythonImportTime = "Importa del modulo time" PythonIndex = "Indice prima occorrenza di x" PythonInput = "Inserire un valore" PythonInsert = "Inserire x in posizione i-esima" @@ -67,9 +67,9 @@ PythonInt = "Conversione in intero" PythonIonFunction = "Prefisso di funzione modulo ion" PythonIsFinite = "Testa se x è finito" PythonIsInfinite = "Testa se x est infinito" -PythonIsKeyDown = "Restituisce True se viene premuto il tasto k" +PythonIsKeyDown = "Restituisce True premendo tasto k" PythonIsNaN = "Testa se x è NaN" -PythonKandinskyFunction = "Prefisso di funzione modulo kandinsky" +PythonKandinskyFunction = "Prefisso funzione modulo kandinsky" PythonKeyLeft = "Tasto FRECCIA SINISTRA" PythonKeyUp = "Tasto FRECCIA ALTO" PythonKeyDown = "Tasto FRECCIA BASSO" @@ -123,14 +123,14 @@ PythonLog = "Logaritmo di base a" PythonLog10 = "Logaritmo decimale" PythonLog2 = "Logaritmo di base 2" PythonMathFunction = "Prefisso funzione del modulo math" -PythonMatplotlibPyplotFunction = "prefisso del modulo matplotlib.pyplot" +PythonMatplotlibPyplotFunction = "Prefisso modulo matplotlib.pyplot" PythonMax = "Massimo" PythonMin = "Minimo" PythonModf = "Parti frazionarie e intere" PythonMonotonic = "Restituisce il valore dell'orologio" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" -PythonPlot = "Disegna y in funzione di x come linee" +PythonPlot = "Disegna y in f. di x come linee" PythonPolar = "Conversione in polare" PythonPop = "Cancella l'ultimo elemento" PythonPower = "x alla potenza y" @@ -138,15 +138,15 @@ PythonPrint = "Visualizza l'oggetto" PythonRadians = "Conversione da gradi a radianti" PythonRandint = "Intero aleatorio in [a,b]" PythonRandom = "Numero aleatorio in [0,1[" -PythonRandomFunction = "Prefisso di funzione del modulo casuale" +PythonRandomFunction = "Prefisso funzione modulo casuale" PythonRandrange = "Numero dentro il range(start, stop)" PythonRangeStartStop = "Lista da start a stop-1" PythonRangeStop = "Lista da 0 a stop-1" -PythonRect = "Conversione in coordinate algebriche" -PythonRemove = "Cancella la prima x dalla liste" +PythonRect = "Converte in coordinate algebriche" +PythonRemove = "Cancella la prima x dalla lista" PythonReverse = "Inverte gli elementi della lista" PythonRound = "Arrotondato a n cifre decimali" -PythonScatter = "Disegna un diagramma di dispersione di y in funzione di x" +PythonScatter = "Disegna diagramma di dispersione di y in f. di x" PythonSeed = "Inizializza il generatore random" PythonSetPixel = "Colora il pixel (x,y)" PythonShow = "Mostra la figura" @@ -168,8 +168,8 @@ PythonTurtleBrown = "Colore marrone" PythonTurtleCircle = "Cerchio di raggio r pixel" PythonTurtleColor = "Modifica il colore del tratto" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" -PythonTurtleForward = "Avancza di x pixel" -PythonTurtleFunction = "Prefisso di funzione del modello turtle" +PythonTurtleForward = "Avanza di x pixel" +PythonTurtleFunction = "Prefisso funzione modello turtle" PythonTurtleGoto = "Spostati alle coordinate (x,y)" PythonTurtleGreen = "Colore verde" PythonTurtleGrey = "Colore grigio" @@ -182,7 +182,7 @@ PythonTurtlePendown = "Abbassa la penna" PythonTurtlePensize = "Dimensione del tratto in pixel" PythonTurtlePenup = "Solleva la penna" PythonTurtlePink = "Colore rosa" -PythonTurtlePosition = "Restituisce la posizione corrente (x,y)" +PythonTurtlePosition = "Fornisce posizione corrente (x,y)" PythonTurtlePurple = "Colore viola" PythonTurtleRed = "Colore rosso" PythonTurtleReset = "Azzera il disegno" diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n index 8ce5e37f3..e21e01eca 100644 --- a/apps/settings/base.it.i18n +++ b/apps/settings/base.it.i18n @@ -26,7 +26,7 @@ Gradians = "Gradienti " Radian = "Radianti " Decimal = "Decimale " Scientific = "Scientifico " -Engineering = "Ingegneristico " +Engineering = "Ingegneria " SignificantFigures = "Cifre significative " Real = "Reale " Cartesian = "Algebrico " From 71ab038e9733dfcf7186c682107bf79a46397948 Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 21 Apr 2020 18:48:25 +0200 Subject: [PATCH 114/453] [it]python --- apps/code/catalog.it.i18n | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 4e10351f5..3bb659f96 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -13,19 +13,19 @@ PythonAbs = "Valore assoluto/Modulo" PythonAcos = "Coseno d'arco" PythonAcosh = "Coseno iperbolico inverso" PythonAppend = "Inserisce x alla fine della lista" -PythonArrow = "Disegna una freccia da (x,y) a (x+dx,y+dy)" +PythonArrow = "Freccia da (x,y) a (x+dx,y+dy)" PythonAsin = "Arco sinusoidale" PythonAsinh = "Arco sinusoidale iperbolico" PythonAtan = "Arco tangente" PythonAtan2 = "Calcolo di atan(y/x)" PythonAtanh = "Arco tangente iperbolico" -PythonAxis = "Imposta assi su (xmin,xmax,ymin,ymax)" -PythonBar = "Disegna grafico a barre con x valori" +PythonAxis = "Imposta assi (xmin,xmax,ymin,ymax)" +PythonBar = "Grafico a barre con x valori" PythonBin = "Converte un intero in binario" PythonCeil = "Parte intera superiore" PythonChoice = "Numero aleatorio nella lista" PythonClear = "Svuota la lista" -PythonCmathFunction = "Funzione prefissata modulo cmath" +PythonCmathFunction = "Funz. prefissata modulo cmath" PythonColor = "Definisci un colore rvb" PythonComplex = "Restituisce a+ib" PythonCopySign = "Restituisce x con segno di y" @@ -146,7 +146,7 @@ PythonRect = "Converte in coordinate algebriche" PythonRemove = "Cancella la prima x dalla lista" PythonReverse = "Inverte gli elementi della lista" PythonRound = "Arrotondato a n cifre decimali" -PythonScatter = "Disegna diagramma di dispersione di y in f. di x" +PythonScatter = "Diagramma dispersione di y in f. di x" PythonSeed = "Inizializza il generatore random" PythonSetPixel = "Colora il pixel (x,y)" PythonShow = "Mostra la figura" From 33b2633729f6bf9075dbd0851e1af12548b49e44 Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Tue, 21 Apr 2020 18:50:47 +0200 Subject: [PATCH 115/453] [it]python --- apps/code/catalog.it.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 3bb659f96..0ca9d0f86 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -146,7 +146,7 @@ PythonRect = "Converte in coordinate algebriche" PythonRemove = "Cancella la prima x dalla lista" PythonReverse = "Inverte gli elementi della lista" PythonRound = "Arrotondato a n cifre decimali" -PythonScatter = "Diagramma dispersione di y in f. di x" +PythonScatter = "Diagramma dispersione y in f. di x" PythonSeed = "Inizializza il generatore random" PythonSetPixel = "Colora il pixel (x,y)" PythonShow = "Mostra la figura" From ddd3904ea990b3c11151f8e77cc12f9432a7269c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 10:25:48 +0200 Subject: [PATCH 116/453] [apps/calculation] Translate ES toolbox --- apps/calculation/base.es.i18n | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/calculation/base.es.i18n b/apps/calculation/base.es.i18n index 36d7a8bdb..25c3c5035 100644 --- a/apps/calculation/base.es.i18n +++ b/apps/calculation/base.es.i18n @@ -1,9 +1,9 @@ CalculApp = "Cálculo" CalculAppCapital = "CÁLCULO" -AdditionalResults = "????" -DecimalBase = "????" -HexadecimalBase = "????" -BinaryBase = "????" -PrimeFactors = "????" -MixedFraction = "????" -EuclideanDivision = "????" +AdditionalResults = "Resultados adicionales" +DecimalBase = "Decimal" +HexadecimalBase = "Hexadecimal" +BinaryBase = "Binario" +PrimeFactors = "Factores primos" +MixedFraction = "Fracción mixta" +EuclideanDivision = "División euclidiana" From e2dc79c2d51fd9ec510ce2e1a4a512aceb10cbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 21 Apr 2020 17:59:21 +0200 Subject: [PATCH 117/453] [poincare] Partially implement simplification for UnitConversion::Classic --- poincare/include/poincare/unit.h | 13 ++++++ poincare/src/multiplication.cpp | 75 ++++++++++++++++++-------------- poincare/src/unit.cpp | 22 ++++++++++ poincare/test/simplification.cpp | 2 +- 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 2d05ad88a..252de05d9 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -414,6 +414,9 @@ public: Representative::Prefixable::Yes, NegativePrefixes), }; + static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; + static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; + static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; static constexpr const Dimension DimensionTable[] = { /* The current table is sorted from most to least simple units. * The order determines the behavior of simplification. @@ -718,6 +721,9 @@ public: &EmptyPrefix ), }; + static const Dimension constexpr * TimeDimension = &DimensionTable[0] ; + static const Dimension constexpr * DistanceDimension = &DimensionTable[1]; + static constexpr const Unit::Dimension * DimensionTableUpperBound = DimensionTable + sizeof(DimensionTable)/sizeof(Dimension); static bool CanParse(const char * symbol, size_t length, @@ -725,11 +731,18 @@ public: Unit(const UnitNode * node) : Expression(node) {} static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); + static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } + static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } + + static bool IsISSpeed(Expression & e); + bool isMeter() const; + bool isSecond() const; // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); + static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; private: UnitNode * node() const { return static_cast(Expression::node()); } Expression removeUnit(Expression * unit); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 11cdca1af..8741c1e00 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -355,12 +355,13 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu return std::move(o); } + Expression result; + // Step 2: Handle the units Expression self = *this; Expression units; self = removeUnit(&units); - Expression result; if (!units.isUninitialized()) { ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion(); if (unitConversionMode == ExpressionNode::UnitConversion::Default || unitConversionMode == ExpressionNode::UnitConversion::Classic) { @@ -438,48 +439,56 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu // If the value is undefined, return "undef" without any unit result = Undefined::Builder(); } else { - if (unitConversionMode == ExpressionNode::UnitConversion::Classic) { - // TODO create new result 1h 23min 24secondes ? - // Utiliser store ? - } else { + // Find the right unit prefix when the value ≠ 0 + if (unitConversionMode == ExpressionNode::UnitConversion::Default && value != 0.0 && value != 1.0 && !std::isinf(value)) { + // Identify the first Unit factor and its exponent + Expression firstFactor = units; + int exponent = 1; + if (firstFactor.type() == ExpressionNode::Type::Multiplication) { + firstFactor = firstFactor.childAtIndex(0); + } + if (firstFactor.type() == ExpressionNode::Type::Power) { + Expression exp = firstFactor.childAtIndex(1); + firstFactor = firstFactor.childAtIndex(0); + assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); + Integer expInt = static_cast(exp).signedIntegerNumerator(); + if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { + exponent = expInt.extractedInt(); + } else { + // The exponent is too large to be extracted, so do not try to use it. + exponent = 0; + } + } + assert(firstFactor.type() == ExpressionNode::Type::Unit); + // Choose its multiple and update value accordingly + if (exponent != 0) { + static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); + } + } else if (unitConversionMode == ExpressionNode::UnitConversion::Classic) { + if (Unit::IsISSpeed(units)) { + value *= Unit::MeterPerSecondToKilometerPerHourFactor; + units = Multiplication::Builder( + Unit::Kilometer(), + Power::Builder( + Unit::Hour(), + Rational::Builder(-1) + ) + ); + } + // TODO: what to do if no classic conversion? + } + if (result.isUninitialized()) { + // Build final Expression Expression resultWithoutUnit; if (std::isinf(value)) { resultWithoutUnit = Infinity::Builder(value < 0.0); } else { - // Find the right unit prefix when the value ≠ 0 - if (unitConversionMode == ExpressionNode::UnitConversion::Default && value != 0.0 && value != 1.0) { - // Identify the first Unit factor and its exponent - Expression firstFactor = units; - int exponent = 1; - if (firstFactor.type() == ExpressionNode::Type::Multiplication) { - firstFactor = firstFactor.childAtIndex(0); - } - if (firstFactor.type() == ExpressionNode::Type::Power) { - Expression exp = firstFactor.childAtIndex(1); - firstFactor = firstFactor.childAtIndex(0); - assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); - Integer expInt = static_cast(exp).signedIntegerNumerator(); - if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { - exponent = expInt.extractedInt(); - } else { - // The exponent is too large to be extracted, so do not try to use it. - exponent = 0; - } - } - assert(firstFactor.type() == ExpressionNode::Type::Unit); - // Choose its multiple and update value accordingly - if (exponent != 0) { - static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); - } - } resultWithoutUnit = Float::Builder(value); } - // Build final Expression result = Multiplication::Builder(resultWithoutUnit, units); static_cast(result).mergeSameTypeChildrenInPlace(); } } - } else { // Step 3: Create a Division if relevant Expression numer, denom; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 91a4b3ef2..da08ba2c7 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -259,7 +259,12 @@ constexpr const Unit::Representative Unit::CatalyticActivityRepresentatives[], Unit::SurfaceRepresentatives[], Unit::VolumeRepresentatives[]; +const Unit::Representative constexpr * Unit::SecondRepresentative; +const Unit::Representative constexpr * Unit::HourRepresentative; +const Unit::Representative constexpr * Unit::MeterRepresentative; constexpr const Unit::Dimension Unit::DimensionTable[]; +const Unit::Dimension constexpr * Unit::TimeDimension; +const Unit::Dimension constexpr * Unit::DistanceDimension; constexpr const Unit::Dimension * Unit::DimensionTableUpperBound; bool Unit::CanParse(const char * symbol, size_t length, @@ -348,6 +353,23 @@ Expression Unit::removeUnit(Expression * unit) { return one; } +bool Unit::isSecond() const { + return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && node()->prefix() == &EmptyPrefix; +} + +bool Unit::isMeter() const { + return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; +} + +bool Unit::IsISSpeed(Expression & e) { + // Form m*s^-1 + return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 2 && + e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert().isMeter() && + e.childAtIndex(1).type() == ExpressionNode::Type::Power && + e.childAtIndex(1).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusOne() && + e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isSecond(); +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 40971b7a6..3c3554e8c 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1284,7 +1284,7 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { assert_parsed_expression_simplify_to("1000000_cm", "10×_km", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, DefaultUnitConversion); assert_parsed_expression_simplify_to("1000000_cm", "1000000×_cm", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, NoUnitConversion); assert_parsed_expression_simplify_to("1000000_cm", "10000×_m", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, InternationalSystemUnitConversion); - //assert_parsed_expression_simplify_to("10_m/h", "0.01km/h", SystemForApproximation, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); + assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); } QUIZ_CASE(poincare_simplification_user_function) { From cc114900fa210a39b530f48478955723ef10e239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 22 Apr 2020 09:54:04 +0200 Subject: [PATCH 118/453] [poincare] Add Liter representation to classic unit conversion --- poincare/include/poincare/integer.h | 1 + poincare/include/poincare/rational.h | 2 ++ poincare/include/poincare/unit.h | 7 +++++++ poincare/src/multiplication.cpp | 5 +++++ poincare/src/unit.cpp | 7 +++++++ poincare/test/simplification.cpp | 2 ++ 6 files changed, 24 insertions(+) diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 181193a75..66e948bf5 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -118,6 +118,7 @@ public: static int NumberOfBase10DigitsWithoutSign(const Integer & i); bool isOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && !m_negative); }; bool isTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && !m_negative); }; + bool isThree() const { return (numberOfDigits() == 1 && digit(0) == 3 && !m_negative); }; bool isTen() const { return (numberOfDigits() == 1 && digit(0) == 10 && !m_negative); }; bool isMinusOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && m_negative); }; bool isZero() const { return (numberOfDigits() == 0); }; diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 4e16c5cf0..091e6fbc9 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -45,6 +45,7 @@ public: // Basic test bool isZero() const { return unsignedNumerator().isZero(); } bool isOne() const { return signedNumerator().isOne() && isInteger(); } + bool isThree() const { return signedNumerator().isThree() && isInteger(); } bool isMinusOne() const { return signedNumerator().isMinusOne() && isInteger(); } bool isHalf() const { return signedNumerator().isOne() && denominator().isTwo(); } bool isMinusHalf() const { return signedNumerator().isMinusOne() && denominator().isTwo(); } @@ -89,6 +90,7 @@ public: bool isNegative() const { return node()->isNegative(); } bool isZero() const { return node()->isZero(); } bool isOne() const { return node()->isOne(); } + bool isThree() const { return node()->isThree(); } bool isMinusOne() const { return node()->isMinusOne(); } bool isHalf() const { return node()->isHalf(); } bool isMinusHalf() const { return node()->isMinusHalf(); } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 252de05d9..0be5807e8 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -414,9 +414,11 @@ public: Representative::Prefixable::Yes, NegativePrefixes), }; + // TODO: find a better way to find defines these pointers static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; + static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; static constexpr const Dimension DimensionTable[] = { /* The current table is sorted from most to least simple units. * The order determines the behavior of simplification. @@ -721,8 +723,10 @@ public: &EmptyPrefix ), }; + // TODO: find a better way to find defines these pointers static const Dimension constexpr * TimeDimension = &DimensionTable[0] ; static const Dimension constexpr * DistanceDimension = &DimensionTable[1]; + static const Dimension constexpr * VolumeDimension = &DimensionTable[sizeof(DimensionTable)/sizeof(Dimension)-1]; static constexpr const Unit::Dimension * DimensionTableUpperBound = DimensionTable + sizeof(DimensionTable)/sizeof(Dimension); @@ -733,8 +737,10 @@ public: static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } + static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } static bool IsISSpeed(Expression & e); + static bool IsISVolume(Expression & e); bool isMeter() const; bool isSecond() const; @@ -743,6 +749,7 @@ public: void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; + static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; private: UnitNode * node() const { return static_cast(Expression::node()); } Expression removeUnit(Expression * unit); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 8741c1e00..6eb3af9c1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -475,6 +475,11 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu ) ); } + if (Unit::IsISVolume(units)) { + value *= Unit::CubicMeterToLiterFactor; + units = Unit::Liter(); + static_cast(units).chooseBestMultipleForValue(value, 1, reductionContext); + } // TODO: what to do if no classic conversion? } if (result.isUninitialized()) { diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index da08ba2c7..89e1734fd 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -370,6 +370,13 @@ bool Unit::IsISSpeed(Expression & e) { e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isSecond(); } +bool Unit::IsISVolume(Expression & e) { + // Form m^3 + return e.type() == ExpressionNode::Type::Power && + e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert().isMeter() && + e.childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).convert().isThree(); +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 3c3554e8c..b636e13b8 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1285,6 +1285,8 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { assert_parsed_expression_simplify_to("1000000_cm", "1000000×_cm", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, NoUnitConversion); assert_parsed_expression_simplify_to("1000000_cm", "10000×_m", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, InternationalSystemUnitConversion); assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); + assert_parsed_expression_simplify_to("0.2_m^3", "200×_L", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); + assert_parsed_expression_simplify_to("0.000012_m^3", "1.2×_cL", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); } QUIZ_CASE(poincare_simplification_user_function) { From 4d7b9aa2a9ab3727f4af5bd5ec841ba7a507dafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Apr 2020 09:59:27 +0200 Subject: [PATCH 119/453] [poincare] Add watthour representation to classic unit conversion --- poincare/include/poincare/integer.h | 1 + poincare/include/poincare/rational.h | 4 ++++ poincare/include/poincare/unit.h | 10 ++++++++++ poincare/src/multiplication.cpp | 9 +++++++++ poincare/src/unit.cpp | 17 +++++++++++++++++ poincare/test/simplification.cpp | 1 + 6 files changed, 42 insertions(+) diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 66e948bf5..7140ccd80 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -121,6 +121,7 @@ public: bool isThree() const { return (numberOfDigits() == 1 && digit(0) == 3 && !m_negative); }; bool isTen() const { return (numberOfDigits() == 1 && digit(0) == 10 && !m_negative); }; bool isMinusOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && m_negative); }; + bool isMinusTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && m_negative); }; bool isZero() const { return (numberOfDigits() == 0); }; bool isEven() const { return ((digit(0) & 1) == 0); } diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 091e6fbc9..c1af28415 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -45,8 +45,10 @@ public: // Basic test bool isZero() const { return unsignedNumerator().isZero(); } bool isOne() const { return signedNumerator().isOne() && isInteger(); } + bool isTwo() const { return signedNumerator().isTwo() && isInteger(); } bool isThree() const { return signedNumerator().isThree() && isInteger(); } bool isMinusOne() const { return signedNumerator().isMinusOne() && isInteger(); } + bool isMinusTwo() const { return signedNumerator().isMinusTwo() && isInteger(); } bool isHalf() const { return signedNumerator().isOne() && denominator().isTwo(); } bool isMinusHalf() const { return signedNumerator().isMinusOne() && denominator().isTwo(); } bool isTen() const { return signedNumerator().isTen() && isInteger(); } @@ -90,8 +92,10 @@ public: bool isNegative() const { return node()->isNegative(); } bool isZero() const { return node()->isZero(); } bool isOne() const { return node()->isOne(); } + bool isTwo() const { return node()->isTwo(); } bool isThree() const { return node()->isThree(); } bool isMinusOne() const { return node()->isMinusOne(); } + bool isMinusTwo() const { return node()->isMinusTwo(); } bool isHalf() const { return node()->isHalf(); } bool isMinusHalf() const { return node()->isMinusHalf(); } bool isTen() const { return node()->isTen(); } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 0be5807e8..40421e479 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -415,10 +415,13 @@ public: NegativePrefixes), }; // TODO: find a better way to find defines these pointers + static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative might require to be fixed if the TimeRepresentatives table was changed."); static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; + static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0]; static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; + static const Representative constexpr * WattRepresentative = &PowerRepresentatives[0]; static constexpr const Dimension DimensionTable[] = { /* The current table is sorted from most to least simple units. * The order determines the behavior of simplification. @@ -724,8 +727,11 @@ public: ), }; // TODO: find a better way to find defines these pointers + static_assert(sizeof(DimensionTable)/sizeof(Dimension) == 23, "The Unit::TimeDimension, Unit::DistanceDimension and so on might require to be fixed if the Dimension table was changed."); static const Dimension constexpr * TimeDimension = &DimensionTable[0] ; static const Dimension constexpr * DistanceDimension = &DimensionTable[1]; + static const Dimension constexpr * MassDimension = &DimensionTable[2]; + static const Dimension constexpr * PowerDimension = &DimensionTable[11]; static const Dimension constexpr * VolumeDimension = &DimensionTable[sizeof(DimensionTable)/sizeof(Dimension)-1]; static constexpr const Unit::Dimension * DimensionTableUpperBound = @@ -738,11 +744,14 @@ public: static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } + static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); + static bool IsISEnergy(Expression & e); bool isMeter() const; bool isSecond() const; + bool isKilogram() const; // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); @@ -750,6 +759,7 @@ public: static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; + static constexpr double JouleToWatthourFactor = 1.0/3600.0; private: UnitNode * node() const { return static_cast(Expression::node()); } Expression removeUnit(Expression * unit); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 6eb3af9c1..59c40e618 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -480,6 +480,15 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu units = Unit::Liter(); static_cast(units).chooseBestMultipleForValue(value, 1, reductionContext); } + if (Unit::IsISEnergy(units)) { + value *= Unit::JouleToWatthourFactor; + Unit w = Unit::Watt(); + units = Multiplication::Builder( + w, + Unit::Hour() + ); + w.chooseBestMultipleForValue(value, 1, reductionContext); + } // TODO: what to do if no classic conversion? } if (result.isUninitialized()) { diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 89e1734fd..f19004a1a 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -361,6 +361,11 @@ bool Unit::isMeter() const { return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; } + +bool Unit::isKilogram() const { + return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; +} + bool Unit::IsISSpeed(Expression & e) { // Form m*s^-1 return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 2 && @@ -377,6 +382,18 @@ bool Unit::IsISVolume(Expression & e) { e.childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).convert().isThree(); } +bool Unit::IsISEnergy(Expression & e) { + // Form _kg*_m^2*_s^-2 + return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 3 && + e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert().isKilogram() && + e.childAtIndex(1).type() == ExpressionNode::Type::Power && + e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isMeter(); + e.childAtIndex(1).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isTwo() && + e.childAtIndex(2).type() == ExpressionNode::Type::Power && + e.childAtIndex(2).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isSecond(); + e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusTwo(); +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index b636e13b8..0badb52f2 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1287,6 +1287,7 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); assert_parsed_expression_simplify_to("0.2_m^3", "200×_L", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); assert_parsed_expression_simplify_to("0.000012_m^3", "1.2×_cL", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); + assert_parsed_expression_simplify_to("3600_J", "1×_W×_h", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); } QUIZ_CASE(poincare_simplification_user_function) { From 687766567daf63ea2c19ab5c5afbc328368cbb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 10:55:43 +0200 Subject: [PATCH 120/453] [poincare] Multiplication::shallowBeautify: don't bother to choose best unit for UnitConversion::Classic --- poincare/src/multiplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 59c40e618..c61ac9ae1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -364,7 +364,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu if (!units.isUninitialized()) { ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion(); - if (unitConversionMode == ExpressionNode::UnitConversion::Default || unitConversionMode == ExpressionNode::UnitConversion::Classic) { + if (unitConversionMode == ExpressionNode::UnitConversion::Default) { /* Step 2a: Recognize derived units * - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most. * - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'. From ec7382c75e04d75298cdb069ee2ef699ae42537e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 10:56:27 +0200 Subject: [PATCH 121/453] [poincare] Unit::chooseBestMultipleForValue handles edge cases (inf, 1, 0) cases itself --- poincare/src/multiplication.cpp | 2 +- poincare/src/unit.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index c61ac9ae1..aa831a2d2 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -440,7 +440,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu result = Undefined::Builder(); } else { // Find the right unit prefix when the value ≠ 0 - if (unitConversionMode == ExpressionNode::UnitConversion::Default && value != 0.0 && value != 1.0 && !std::isinf(value)) { + if (unitConversionMode == ExpressionNode::UnitConversion::Default) { // Identify the first Unit factor and its exponent Expression firstFactor = units; int exponent = 1; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index f19004a1a..4d1daadf1 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -319,7 +319,10 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext } void Unit::chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext) { - assert(value != 0 && !std::isnan(value) && !std::isinf(value) && exponent != 0); + assert(!std::isnan(value) && exponent != 0); + if (value == 0 || value == 1.0 || std::isinf(value)) { + return; + } UnitNode * unitNode = node(); const Dimension * dim = unitNode->dimension(); /* Find in the Dimension 'dim' which unit (Representative and Prefix) make From 8d12cf1e8b2935fccdded0ddba0ed82e57022371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 10:57:08 +0200 Subject: [PATCH 122/453] [poincare] Multiplication: clean code --- poincare/src/multiplication.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index aa831a2d2..f35bdd64d 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -493,13 +493,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } if (result.isUninitialized()) { // Build final Expression - Expression resultWithoutUnit; - if (std::isinf(value)) { - resultWithoutUnit = Infinity::Builder(value < 0.0); - } else { - resultWithoutUnit = Float::Builder(value); - } - result = Multiplication::Builder(resultWithoutUnit, units); + result = Multiplication::Builder(Number::FloatNumber(value), units); static_cast(result).mergeSameTypeChildrenInPlace(); } } From 94c5941fb50a2cd79ec91102d6b4f14967be0904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 14:35:34 +0200 Subject: [PATCH 123/453] [poincare] Unit: improve ChooseBestMultipleForValue --- poincare/include/poincare/unit.h | 3 ++- poincare/src/multiplication.cpp | 26 ++------------------ poincare/src/unit.cpp | 41 +++++++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 40421e479..389946adb 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -755,13 +755,14 @@ public: // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - void chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext); + static void ChooseBestMultipleForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext); static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; static constexpr double JouleToWatthourFactor = 1.0/3600.0; private: UnitNode * node() const { return static_cast(Expression::node()); } + void chooseBestMultipleForValue(double * value, const int exponent, ExpressionNode::ReductionContext reductionContext); Expression removeUnit(Expression * unit); }; diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index f35bdd64d..bcab43e26 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -439,31 +439,9 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu // If the value is undefined, return "undef" without any unit result = Undefined::Builder(); } else { - // Find the right unit prefix when the value ≠ 0 if (unitConversionMode == ExpressionNode::UnitConversion::Default) { - // Identify the first Unit factor and its exponent - Expression firstFactor = units; - int exponent = 1; - if (firstFactor.type() == ExpressionNode::Type::Multiplication) { - firstFactor = firstFactor.childAtIndex(0); - } - if (firstFactor.type() == ExpressionNode::Type::Power) { - Expression exp = firstFactor.childAtIndex(1); - firstFactor = firstFactor.childAtIndex(0); - assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); - Integer expInt = static_cast(exp).signedIntegerNumerator(); - if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { - exponent = expInt.extractedInt(); - } else { - // The exponent is too large to be extracted, so do not try to use it. - exponent = 0; - } - } - assert(firstFactor.type() == ExpressionNode::Type::Unit); - // Choose its multiple and update value accordingly - if (exponent != 0) { - static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); - } + // Find the right unit prefix + Unit::ChooseBestMultipleForValue(&units, &value, reductionContext); } else if (unitConversionMode == ExpressionNode::UnitConversion::Classic) { if (Unit::IsISSpeed(units)) { value *= Unit::MeterPerSecondToKilometerPerHourFactor; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 4d1daadf1..f3b8aa28e 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -1,6 +1,9 @@ #include +#include #include +#include #include +#include #include #include #include @@ -318,9 +321,35 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext return result; } -void Unit::chooseBestMultipleForValue(double & value, const int exponent, ExpressionNode::ReductionContext reductionContext) { - assert(!std::isnan(value) && exponent != 0); - if (value == 0 || value == 1.0 || std::isinf(value)) { +void Unit::ChooseBestMultipleForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { + // Identify the first Unit factor and its exponent + Expression firstFactor = *units; + int exponent = 1; + if (firstFactor.type() == ExpressionNode::Type::Multiplication) { + firstFactor = firstFactor.childAtIndex(0); + } + if (firstFactor.type() == ExpressionNode::Type::Power) { + Expression exp = firstFactor.childAtIndex(1); + firstFactor = firstFactor.childAtIndex(0); + assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); + Integer expInt = static_cast(exp).signedIntegerNumerator(); + if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { + exponent = expInt.extractedInt(); + } else { + // The exponent is too large to be extracted, so do not try to use it. + exponent = 0; + } + } + assert(firstFactor.type() == ExpressionNode::Type::Unit); + // Choose its multiple and update value accordingly + if (exponent != 0) { + static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); + } +} + +void Unit::chooseBestMultipleForValue(double * value, const int exponent, ExpressionNode::ReductionContext reductionContext) { + assert(!std::isnan(*value) && exponent != 0); + if (*value == 0 || *value == 1.0 || std::isinf(*value)) { return; } UnitNode * unitNode = node(); @@ -330,11 +359,11 @@ void Unit::chooseBestMultipleForValue(double & value, const int exponent, Expres */ const Representative * bestRep = unitNode->representative(); const Prefix * bestPre = unitNode->prefix(); - double bestVal = value; + double bestVal = *value; for (const Representative * rep = dim->stdRepresentative(); rep < dim->representativesUpperBound(); rep++) { // evaluate quotient - double val = value * std::pow(Division::Builder(clone(), Unit::Builder(dim, rep, &EmptyPrefix)).deepReduce(reductionContext).approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()), exponent); + double val = *value * std::pow(Division::Builder(clone(), Unit::Builder(dim, rep, &EmptyPrefix)).deepReduce(reductionContext).approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()), exponent); // Get the best prefix and update val accordingly const Prefix * pre = rep->bestPrefixForValue(val, exponent); if (std::fabs(std::log10(std::fabs(bestVal))) - std::fabs(std::log10(std::fabs(val))) > Epsilon()) { @@ -346,7 +375,7 @@ void Unit::chooseBestMultipleForValue(double & value, const int exponent, Expres } unitNode->setRepresentative(bestRep); unitNode->setPrefix(bestPre); - value = bestVal; + *value = bestVal; } Expression Unit::removeUnit(Expression * unit) { From 845a1180730d4e3c0f65b225b828ac6b2e03e7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 14:36:10 +0200 Subject: [PATCH 124/453] [poincare] Add Unit::BuildTimeSplit and helpers for time units --- poincare/include/poincare/unit.h | 11 +++++++++++ poincare/src/unit.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 389946adb..34fad77da 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -417,7 +417,11 @@ public: // TODO: find a better way to find defines these pointers static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative might require to be fixed if the TimeRepresentatives table was changed."); static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; + static const Representative constexpr * MinuteRepresentative = &TimeRepresentatives[1]; static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; + static const Representative constexpr * DayRepresentative = &TimeRepresentatives[3]; + static const Representative constexpr * MonthRepresentative = &TimeRepresentatives[5]; + static const Representative constexpr * YearRepresentative = &TimeRepresentatives[6]; static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0]; static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; @@ -742,13 +746,20 @@ public: Unit(const UnitNode * node) : Expression(node) {} static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } + static Unit Second() { return Builder(TimeDimension, SecondRepresentative, &EmptyPrefix); } + static Unit Minute() { return Builder(TimeDimension, MinuteRepresentative, &EmptyPrefix); } static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } + static Unit Day() { return Builder(TimeDimension, DayRepresentative, &EmptyPrefix); } + static Unit Month() { return Builder(TimeDimension, MonthRepresentative, &EmptyPrefix); } + static Unit Year() { return Builder(TimeDimension, YearRepresentative, &EmptyPrefix); } static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } + static Expression BuildTimeSplit(double seconds); static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); static bool IsISEnergy(Expression & e); + static bool IsISTime(Expression & e); bool isMeter() const; bool isSecond() const; bool isKilogram() const; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index f3b8aa28e..3bd6d524c 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -426,6 +426,34 @@ bool Unit::IsISEnergy(Expression & e) { e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusTwo(); } +bool Unit::IsISTime(Expression & e) { + return e.type() == ExpressionNode::Type::Unit && static_cast(e).isSecond(); +} + +Expression Unit::BuildTimeSplit(double seconds) { + assert(!std::isnan(seconds)); + if (std::isinf(seconds)) { + return Multiplication::Builder(Infinity::Builder(seconds < 0.0), Unit::Second()); + } + double remain = seconds; + constexpr static int numberOfTimeUnits = 6; + // This could be computed from the time representatives but we same time by using constexpr double + constexpr static double timeFactors[numberOfTimeUnits] = {365.25*24.0*60.0*60.0, 365.25/12.0*24.0*60.0*60.0, 24.0*60.0*60.0, 60.0*60.0, 60.0, 1.0 }; + Unit units[numberOfTimeUnits] = {Unit::Year(), Unit::Month(), Unit::Day(), Unit::Hour(), Unit::Minute(), Unit::Second() }; + double valuesPerUnit[numberOfTimeUnits]; + Addition a = Addition::Builder(); + for (size_t i = 0; i < numberOfTimeUnits; i++) { + valuesPerUnit[i] = std::floor(remain/timeFactors[i]); + remain -= valuesPerUnit[i]*timeFactors[i]; + if (std::fabs(remain) < Expression::Epsilon()) { + break; + } + Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); + a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); + } + return a.squashUnaryHierarchyInPlace(); +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; From 71b13bb84f4a0d09907ebe4d9f0eb7af7226e965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:35:47 +0200 Subject: [PATCH 125/453] [poincare] Fix Unit::BuildTimeSplit --- poincare/src/unit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 3bd6d524c..68b7b555c 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -445,11 +445,11 @@ Expression Unit::BuildTimeSplit(double seconds) { for (size_t i = 0; i < numberOfTimeUnits; i++) { valuesPerUnit[i] = std::floor(remain/timeFactors[i]); remain -= valuesPerUnit[i]*timeFactors[i]; + Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); + a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); if (std::fabs(remain) < Expression::Epsilon()) { break; } - Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); - a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); } return a.squashUnaryHierarchyInPlace(); } From 397aac27c53ef89601a20dd7a001321c84c46593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:38:29 +0200 Subject: [PATCH 126/453] [poincare] Add test on Unit helpers --- poincare/test/expression.cpp | 75 ++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/poincare/test/expression.cpp b/poincare/test/expression.cpp index a18c0bf5a..fa3efbafe 100644 --- a/poincare/test/expression.cpp +++ b/poincare/test/expression.cpp @@ -3,7 +3,10 @@ #include #include #include +#include +#include #include "tree/helpers.h" +#include "helper.h" using namespace Poincare; @@ -70,3 +73,75 @@ QUIZ_CASE(poincare_expression_rational_constructor) { Rational f = Rational::Builder(overflow, overflow); assert_pool_size(initialPoolSize+6); } + +QUIZ_CASE(poincare_expression_unit_constructor) { + Shared::GlobalContext globalContext; + ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); + // Time + Unit s = Unit::Second(); + quiz_assert(s.isSecond()); + quiz_assert(!s.isMeter()); + Expression time = Unit::BuildTimeSplit(1234567890); + Addition a = Addition::Builder(); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(39.0), + Unit::Year() + ), + 0, 0); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(1.0), + Unit::Month() + ), + 1, 1); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(13.0), + Unit::Day() + ), + 2, 2); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(19.0), + Unit::Hour() + ), + 3, 3); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(1.0), + Unit::Minute() + ), + 4, 4); + a.addChildAtIndexInPlace(Multiplication::Builder( + Float::Builder(30.0), + Unit::Second() + ), + 5, 5); + quiz_assert(a.isIdenticalTo(time)); + + // Speed + Expression kilometerPerHour = Multiplication::Builder( + Unit::Kilometer(), + Power::Builder( + Unit::Hour(), + Rational::Builder(-1) + ) + ); + kilometerPerHour = kilometerPerHour.reduce(reductionContext); + Expression meterPerSecond; + kilometerPerHour = kilometerPerHour.removeUnit(&meterPerSecond); + quiz_assert(Unit::IsISSpeed(meterPerSecond)); + + // Volume + Expression liter = Unit::Liter(); + liter = liter.reduce(reductionContext); + Expression meter3; + liter = liter.removeUnit(&meter3); + quiz_assert(Unit::IsISVolume(meter3)); + + // Energy + Expression wattHour = Multiplication::Builder( + Unit::Watt(), + Unit::Hour() + ); + wattHour = wattHour.reduce(reductionContext); + Expression kilogramMeter2PerSecond2; + wattHour = wattHour.removeUnit(&kilogramMeter2PerSecond2); + quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); +} From 83a63155b10ec02bb1bde9b9a8eecdd39c41c75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:38:51 +0200 Subject: [PATCH 127/453] [apps] PoincareHelpers: enable to specify the UnitConversion mode in Simplify --- apps/shared/poincare_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shared/poincare_helpers.h b/apps/shared/poincare_helpers.h index 31010f61f..d2124de32 100644 --- a/apps/shared/poincare_helpers.h +++ b/apps/shared/poincare_helpers.h @@ -62,11 +62,11 @@ inline Poincare::Expression ParseAndSimplify(const char * text, Poincare::Contex return Poincare::Expression::ParseAndSimplify(text, context, complexFormat, preferences->angleUnit(), symbolicComputation); } -inline void Simplify(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { +inline void Simplify(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = Poincare::ExpressionNode::UnitConversion::Default) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), *e, context); - *e = e->simplify(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), target, symbolicComputation)); + *e = e->simplify(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), target, symbolicComputation, unitConversion)); } inline void ParseAndSimplifyAndApproximate(const char * text, Poincare::Expression * simplifiedExpression, Poincare::Expression * approximateExpression, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { From 7b28f760b7ba4ad49a6845ec6a160a3708dc4de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:39:24 +0200 Subject: [PATCH 128/453] [poincare] Float: float can be layouted --- poincare/include/poincare/float.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/float.h b/poincare/include/poincare/float.h index 2a1b032bb..40f73ffed 100644 --- a/poincare/include/poincare/float.h +++ b/poincare/include/poincare/float.h @@ -50,7 +50,7 @@ public: Evaluation approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } private: // Simplification - LayoutShape leftLayoutShape() const override { assert(false); return LayoutShape::Decimal; } + LayoutShape leftLayoutShape() const override { return LayoutShape::Decimal; } template Evaluation templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { return Complex::Builder((U)m_value); From 53db27ffeba7bc03708c5cd0c1282fd02694aa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:43:30 +0200 Subject: [PATCH 129/453] [poincare] Discard UnitConversion::Classic mode. This will be done in Calculation app --- poincare/include/poincare/expression_node.h | 3 +- poincare/src/multiplication.cpp | 34 ++------------------- poincare/test/helper.h | 1 - poincare/test/simplification.cpp | 4 --- 4 files changed, 4 insertions(+), 38 deletions(-) diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 6a5f576b3..ef9f6a81a 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -133,8 +133,7 @@ public: enum class UnitConversion { None = 0, Default, - InternationalSystem, - Classic // km/h, days + hours + minute + InternationalSystem }; enum class Sign { Negative = -1, diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index bcab43e26..2e2fc2bc1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -442,38 +442,10 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu if (unitConversionMode == ExpressionNode::UnitConversion::Default) { // Find the right unit prefix Unit::ChooseBestMultipleForValue(&units, &value, reductionContext); - } else if (unitConversionMode == ExpressionNode::UnitConversion::Classic) { - if (Unit::IsISSpeed(units)) { - value *= Unit::MeterPerSecondToKilometerPerHourFactor; - units = Multiplication::Builder( - Unit::Kilometer(), - Power::Builder( - Unit::Hour(), - Rational::Builder(-1) - ) - ); - } - if (Unit::IsISVolume(units)) { - value *= Unit::CubicMeterToLiterFactor; - units = Unit::Liter(); - static_cast(units).chooseBestMultipleForValue(value, 1, reductionContext); - } - if (Unit::IsISEnergy(units)) { - value *= Unit::JouleToWatthourFactor; - Unit w = Unit::Watt(); - units = Multiplication::Builder( - w, - Unit::Hour() - ); - w.chooseBestMultipleForValue(value, 1, reductionContext); - } - // TODO: what to do if no classic conversion? - } - if (result.isUninitialized()) { - // Build final Expression - result = Multiplication::Builder(Number::FloatNumber(value), units); - static_cast(result).mergeSameTypeChildrenInPlace(); } + // Build final Expression + result = Multiplication::Builder(Number::FloatNumber(value), units); + static_cast(result).mergeSameTypeChildrenInPlace(); } } else { // Step 3: Create a Division if relevant diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 18b81b31f..a6e069828 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -14,7 +14,6 @@ constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceDefinedFunctionsW constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined; constexpr Poincare::ExpressionNode::UnitConversion NoUnitConversion = Poincare::ExpressionNode::UnitConversion::None; constexpr Poincare::ExpressionNode::UnitConversion DefaultUnitConversion = Poincare::ExpressionNode::UnitConversion::Default; -constexpr Poincare::ExpressionNode::UnitConversion ClassicUnitConversion = Poincare::ExpressionNode::UnitConversion::Classic; constexpr Poincare::ExpressionNode::UnitConversion InternationalSystemUnitConversion = Poincare::ExpressionNode::UnitConversion::InternationalSystem; constexpr Poincare::Preferences::AngleUnit Degree = Poincare::Preferences::AngleUnit::Degree; constexpr Poincare::Preferences::AngleUnit Radian = Poincare::Preferences::AngleUnit::Radian; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 0badb52f2..a6f1069fb 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1284,10 +1284,6 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { assert_parsed_expression_simplify_to("1000000_cm", "10×_km", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, DefaultUnitConversion); assert_parsed_expression_simplify_to("1000000_cm", "1000000×_cm", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, NoUnitConversion); assert_parsed_expression_simplify_to("1000000_cm", "10000×_m", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, InternationalSystemUnitConversion); - assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); - assert_parsed_expression_simplify_to("0.2_m^3", "200×_L", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); - assert_parsed_expression_simplify_to("0.000012_m^3", "1.2×_cL", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); - assert_parsed_expression_simplify_to("3600_J", "1×_W×_h", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); } QUIZ_CASE(poincare_simplification_user_function) { From 1a9014645cacbc4314ee7f0b2655470a2b2ccb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:44:05 +0200 Subject: [PATCH 130/453] [apps] additional_outputs: fill unit additional results --- .../unit_list_controller.cpp | 77 ++++++++++++++++--- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index fe4e61d84..a288bdca8 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -1,6 +1,13 @@ #include "unit_list_controller.h" #include "../app.h" #include "../../shared/poincare_helpers.h" +#include +#include +#include +#include +#include + +using namespace Poincare; namespace Calculation { @@ -9,18 +16,68 @@ int UnitListController::numberOfRows() const { //FIXME } void UnitListController::computeLayoutAtIndex(int index) { //FIXME - Poincare::Expression expressionAtIndex; + Expression expressionAtIndex = m_expression.clone(); if (index == 0) { - expressionAtIndex = m_expression; - } else { - assert(index == 1); - Poincare::ExpressionNode::ReductionContext reductionContext( + // SI units only + Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); + } else if (index == 1) { + ExpressionNode::ReductionContext reductionContext( App::app()->localContext(), - Poincare::Preferences::sharedPreferences()->complexFormat(), - Poincare::Preferences::sharedPreferences()->angleUnit(), - Poincare::ExpressionNode::ReductionTarget::SystemForApproximation, - Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); - expressionAtIndex = m_expression.reduce(reductionContext); + Preferences::sharedPreferences()->complexFormat(), + Preferences::sharedPreferences()->angleUnit(), + ExpressionNode::ReductionTarget::User, + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + Expression units; + // Reduce to be able to recognize units + expressionAtIndex = expressionAtIndex.reduce(reductionContext); + expressionAtIndex = expressionAtIndex.removeUnit(&units); + bool requireSimplification = true; + bool canChangeUnitPrefix = true; + if (Unit::IsISSpeed(units)) { + expressionAtIndex = UnitConvert::Builder( + m_expression.clone(), + Multiplication::Builder( + Unit::Kilometer(), + Power::Builder( + Unit::Hour(), + Rational::Builder(-1) + ) + ) + ); + canChangeUnitPrefix = false; // We force km/h + } else if (Unit::IsISVolume(units)) { + expressionAtIndex = UnitConvert::Builder( + m_expression.clone(), + Unit::Liter() + ); + } else if (Unit::IsISEnergy(units)) { + expressionAtIndex = UnitConvert::Builder( + m_expression.clone(), + Multiplication::Builder( + Unit::Watt(), + Unit::Hour() + ) + ); + } else if (Unit::IsISTime(units)) { + double value = Shared::PoincareHelpers::ApproximateToScalar(expressionAtIndex, App::app()->localContext()); + expressionAtIndex = Unit::BuildTimeSplit(value); + requireSimplification = false; + canChangeUnitPrefix = false; + } else { + requireSimplification = false; + canChangeUnitPrefix = false; + } + + if (requireSimplification) { + Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User); + } + if (canChangeUnitPrefix) { + Expression newUnits; + expressionAtIndex = expressionAtIndex.removeUnit(&newUnits); + double value = Shared::PoincareHelpers::ApproximateToScalar(expressionAtIndex, App::app()->localContext()); + Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); + expressionAtIndex = Multiplication::Builder(Number::FloatNumber(value), newUnits); + } } m_layouts[index] = Shared::PoincareHelpers::CreateLayout(expressionAtIndex); } From 785d7a0a62d56bb2a6fbf6428d0d55b14b884a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 17:49:57 +0200 Subject: [PATCH 131/453] [apps] additional_outputs: misc. clean-up on unit additional results --- .../unit_list_controller.cpp | 21 +++++++++++-------- apps/calculation/calculation.cpp | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index a288bdca8..d43ece851 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -21,6 +21,7 @@ void UnitListController::computeLayoutAtIndex(int index) { //FIXME // SI units only Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); } else if (index == 1) { + // Miscellaneous classic units for some dimensions ExpressionNode::ReductionContext reductionContext( App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), @@ -31,9 +32,10 @@ void UnitListController::computeLayoutAtIndex(int index) { //FIXME // Reduce to be able to recognize units expressionAtIndex = expressionAtIndex.reduce(reductionContext); expressionAtIndex = expressionAtIndex.removeUnit(&units); - bool requireSimplification = true; - bool canChangeUnitPrefix = true; + bool requireSimplification = false; + bool canChangeUnitPrefix = false; if (Unit::IsISSpeed(units)) { + // Turn into km/h expressionAtIndex = UnitConvert::Builder( m_expression.clone(), Multiplication::Builder( @@ -44,13 +46,17 @@ void UnitListController::computeLayoutAtIndex(int index) { //FIXME ) ) ); - canChangeUnitPrefix = false; // We force km/h + requireSimplification = true; // Reduce the conversion } else if (Unit::IsISVolume(units)) { + // Turn into L expressionAtIndex = UnitConvert::Builder( m_expression.clone(), Unit::Liter() ); + requireSimplification = true; // reduce the conversion + canChangeUnitPrefix = true; // Pick best prefix (mL) } else if (Unit::IsISEnergy(units)) { + // Turn into W expressionAtIndex = UnitConvert::Builder( m_expression.clone(), Multiplication::Builder( @@ -58,16 +64,13 @@ void UnitListController::computeLayoutAtIndex(int index) { //FIXME Unit::Hour() ) ); + requireSimplification = true; // reduce the conversion + canChangeUnitPrefix = true; // Pick best prefix (kWh) } else if (Unit::IsISTime(units)) { + // Turn into ? year + ? month + ? day + ? h + ? min + ? s double value = Shared::PoincareHelpers::ApproximateToScalar(expressionAtIndex, App::app()->localContext()); expressionAtIndex = Unit::BuildTimeSplit(value); - requireSimplification = false; - canChangeUnitPrefix = false; - } else { - requireSimplification = false; - canChangeUnitPrefix = false; } - if (requireSimplification) { Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User); } diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 3393e9f2e..abcafd696 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -250,7 +250,7 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) { return AdditionalInformationType::Trigonometry; } - if (o.hasUnit()) { + if (o.hasUnit()) { // TODO: find a way to check that it'll do have additional results return AdditionalInformationType::Unit; } if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { From 0d0a37c02a95deb51698f1bc4f1a37c6cafd2dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 27 Apr 2020 09:58:46 +0200 Subject: [PATCH 132/453] [apps/calculation] additional_outputs: improve unit_list_controller to compute all expressions before being displayed --- .../unit_list_controller.cpp | 159 ++++++++++-------- .../additional_outputs/unit_list_controller.h | 4 + 2 files changed, 95 insertions(+), 68 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index d43ece851..1f4cfe766 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -11,78 +11,101 @@ using namespace Poincare; namespace Calculation { -int UnitListController::numberOfRows() const { //FIXME - return 2; +void UnitListController::setExpression(Poincare::Expression e) { + // TODO: order of call issue!!! + ExpressionsListController::setExpression(e); + assert(!m_expression.isUninitialized()); + // Reinitizlize m_memoizedExpressions + for (size_t i = 0; i < k_maxNumberOfCells; i++) { + m_memoizedExpressions[i] = Expression(); + } + + // 1. First result: SI units only + m_memoizedExpressions[0] = m_expression.clone(); + Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[0], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); + + // 2. Second result: miscellaneous classic units for some dimensions + ExpressionNode::ReductionContext reductionContext( + App::app()->localContext(), + Preferences::sharedPreferences()->complexFormat(), + Preferences::sharedPreferences()->angleUnit(), + ExpressionNode::ReductionTarget::User, + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + Expression copy = m_expression.clone(); + Expression units; + // Reduce to be able to recognize units + copy = copy.reduce(reductionContext); + copy = copy.removeUnit(&units); + bool requireSimplification = false; + bool canChangeUnitPrefix = false; + if (Unit::IsISSpeed(units)) { + // 2.a. Turn speed into km/h + m_memoizedExpressions[1] = UnitConvert::Builder( + m_expression.clone(), + Multiplication::Builder( + Unit::Kilometer(), + Power::Builder( + Unit::Hour(), + Rational::Builder(-1) + ) + ) + ); + requireSimplification = true; // Reduce the conversion + } else if (Unit::IsISVolume(units)) { + // 2.b. Turn volume into L + m_memoizedExpressions[1] = UnitConvert::Builder( + m_expression.clone(), + Unit::Liter() + ); + requireSimplification = true; // reduce the conversion + canChangeUnitPrefix = true; // Pick best prefix (mL) + } else if (Unit::IsISEnergy(units)) { + // 2.c. Turn energy into Wh + m_memoizedExpressions[1] = UnitConvert::Builder( + m_expression.clone(), + Multiplication::Builder( + Unit::Watt(), + Unit::Hour() + ) + ); + requireSimplification = true; // reduce the conversion + canChangeUnitPrefix = true; // Pick best prefix (kWh) + } else if (Unit::IsISTime(units)) { + // Turni time into ? year + ? month + ? day + ? h + ? min + ? s + double value = Shared::PoincareHelpers::ApproximateToScalar(copy, App::app()->localContext()); + m_memoizedExpressions[1] = Unit::BuildTimeSplit(value); + } + if (requireSimplification) { + Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[1], App::app()->localContext(), ExpressionNode::ReductionTarget::User); + } + if (canChangeUnitPrefix) { + Expression newUnits; + m_memoizedExpressions[1] = m_memoizedExpressions[1].removeUnit(&newUnits); + double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[1], App::app()->localContext()); + Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); + m_memoizedExpressions[1] = Multiplication::Builder(Number::FloatNumber(value), newUnits); + } + + if (!m_memoizedExpressions[1].isUninitialized() && m_memoizedExpressions[0].isIdenticalTo(m_memoizedExpressions[1])) { + // Avoid displaying duplicate + m_memoizedExpressions[1] = Expression(); + } + // TODO m_memoizedExpressions[2]? } -void UnitListController::computeLayoutAtIndex(int index) { //FIXME - Expression expressionAtIndex = m_expression.clone(); - if (index == 0) { - // SI units only - Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); - } else if (index == 1) { - // Miscellaneous classic units for some dimensions - ExpressionNode::ReductionContext reductionContext( - App::app()->localContext(), - Preferences::sharedPreferences()->complexFormat(), - Preferences::sharedPreferences()->angleUnit(), - ExpressionNode::ReductionTarget::User, - ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); - Expression units; - // Reduce to be able to recognize units - expressionAtIndex = expressionAtIndex.reduce(reductionContext); - expressionAtIndex = expressionAtIndex.removeUnit(&units); - bool requireSimplification = false; - bool canChangeUnitPrefix = false; - if (Unit::IsISSpeed(units)) { - // Turn into km/h - expressionAtIndex = UnitConvert::Builder( - m_expression.clone(), - Multiplication::Builder( - Unit::Kilometer(), - Power::Builder( - Unit::Hour(), - Rational::Builder(-1) - ) - ) - ); - requireSimplification = true; // Reduce the conversion - } else if (Unit::IsISVolume(units)) { - // Turn into L - expressionAtIndex = UnitConvert::Builder( - m_expression.clone(), - Unit::Liter() - ); - requireSimplification = true; // reduce the conversion - canChangeUnitPrefix = true; // Pick best prefix (mL) - } else if (Unit::IsISEnergy(units)) { - // Turn into W - expressionAtIndex = UnitConvert::Builder( - m_expression.clone(), - Multiplication::Builder( - Unit::Watt(), - Unit::Hour() - ) - ); - requireSimplification = true; // reduce the conversion - canChangeUnitPrefix = true; // Pick best prefix (kWh) - } else if (Unit::IsISTime(units)) { - // Turn into ? year + ? month + ? day + ? h + ? min + ? s - double value = Shared::PoincareHelpers::ApproximateToScalar(expressionAtIndex, App::app()->localContext()); - expressionAtIndex = Unit::BuildTimeSplit(value); - } - if (requireSimplification) { - Shared::PoincareHelpers::Simplify(&expressionAtIndex, App::app()->localContext(), ExpressionNode::ReductionTarget::User); - } - if (canChangeUnitPrefix) { - Expression newUnits; - expressionAtIndex = expressionAtIndex.removeUnit(&newUnits); - double value = Shared::PoincareHelpers::ApproximateToScalar(expressionAtIndex, App::app()->localContext()); - Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); - expressionAtIndex = Multiplication::Builder(Number::FloatNumber(value), newUnits); +int UnitListController::numberOfRows() const { + int nbOfRows = 0; + for (size_t i = 0; i < k_maxNumberOfCells; i++) { + if (!m_memoizedExpressions[i].isUninitialized()) { + nbOfRows++; } } - m_layouts[index] = Shared::PoincareHelpers::CreateLayout(expressionAtIndex); + return nbOfRows; +} + +void UnitListController::computeLayoutAtIndex(int index) { + assert(!m_memoizedExpressions[index].isUninitialized()); + m_layouts[index] = Shared::PoincareHelpers::CreateLayout(m_memoizedExpressions[index]); } I18n::Message UnitListController::messageAtIndex(int index) { diff --git a/apps/calculation/additional_outputs/unit_list_controller.h b/apps/calculation/additional_outputs/unit_list_controller.h index 1e9d168bd..e3fdee036 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.h +++ b/apps/calculation/additional_outputs/unit_list_controller.h @@ -10,11 +10,15 @@ public: UnitListController(EditExpressionController * editExpressionController) : ExpressionsListController(editExpressionController) {} + void setExpression(Poincare::Expression e) override; + //ListViewDataSource int numberOfRows() const override; private: void computeLayoutAtIndex(int index) override; I18n::Message messageAtIndex(int index) override; + // Memoization of expressions + mutable Poincare::Expression m_memoizedExpressions[k_maxNumberOfCells]; }; } From ec95ed0789989efed838c21a877cc3b022ca15e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 27 Apr 2020 14:25:42 +0200 Subject: [PATCH 133/453] [poincare] Add Unit::ElectronVolt builder --- poincare/include/poincare/unit.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 34fad77da..518879ad1 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -415,7 +415,7 @@ public: NegativePrefixes), }; // TODO: find a better way to find defines these pointers - static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative might require to be fixed if the TimeRepresentatives table was changed."); + static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative and so on might require to be fixed if the TimeRepresentatives table was changed."); static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; static const Representative constexpr * MinuteRepresentative = &TimeRepresentatives[1]; static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; @@ -426,6 +426,8 @@ public: static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0]; static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; static const Representative constexpr * WattRepresentative = &PowerRepresentatives[0]; + static_assert(sizeof(EnergyRepresentatives)/sizeof(Representative) == 2, "The Unit::ElectronVoltRepresentative might require to be fixed if the EnergyRepresentatives table was changed."); + static const Representative constexpr * ElectronVoltRepresentative = &EnergyRepresentatives[1]; static constexpr const Dimension DimensionTable[] = { /* The current table is sorted from most to least simple units. * The order determines the behavior of simplification. @@ -735,6 +737,7 @@ public: static const Dimension constexpr * TimeDimension = &DimensionTable[0] ; static const Dimension constexpr * DistanceDimension = &DimensionTable[1]; static const Dimension constexpr * MassDimension = &DimensionTable[2]; + static const Dimension constexpr * EnergyDimension = &DimensionTable[10]; static const Dimension constexpr * PowerDimension = &DimensionTable[11]; static const Dimension constexpr * VolumeDimension = &DimensionTable[sizeof(DimensionTable)/sizeof(Dimension)-1]; @@ -753,6 +756,7 @@ public: static Unit Month() { return Builder(TimeDimension, MonthRepresentative, &EmptyPrefix); } static Unit Year() { return Builder(TimeDimension, YearRepresentative, &EmptyPrefix); } static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } + static Unit ElectronVolt() { return Builder(EnergyDimension, ElectronVoltRepresentative, &EmptyPrefix); } static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } static Expression BuildTimeSplit(double seconds); From e063c0a9133018f9a96711693597b143323bd4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 27 Apr 2020 14:26:01 +0200 Subject: [PATCH 134/453] [apps/calculation] additional_outputs: add electronVolt row to additional results on energy units --- .../unit_list_controller.cpp | 55 +++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index 1f4cfe766..121498c8e 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -20,11 +20,13 @@ void UnitListController::setExpression(Poincare::Expression e) { m_memoizedExpressions[i] = Expression(); } + size_t numberOfMemoizedExpressions = 0; // 1. First result: SI units only m_memoizedExpressions[0] = m_expression.clone(); Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[0], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); + numberOfMemoizedExpressions++; - // 2. Second result: miscellaneous classic units for some dimensions + // 2. Next results: miscellaneous classic units for some dimensions ExpressionNode::ReductionContext reductionContext( App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), @@ -38,6 +40,7 @@ void UnitListController::setExpression(Poincare::Expression e) { copy = copy.removeUnit(&units); bool requireSimplification = false; bool canChangeUnitPrefix = false; + if (Unit::IsISSpeed(units)) { // 2.a. Turn speed into km/h m_memoizedExpressions[1] = UnitConvert::Builder( @@ -51,6 +54,7 @@ void UnitListController::setExpression(Poincare::Expression e) { ) ); requireSimplification = true; // Reduce the conversion + numberOfMemoizedExpressions++; } else if (Unit::IsISVolume(units)) { // 2.b. Turn volume into L m_memoizedExpressions[1] = UnitConvert::Builder( @@ -59,6 +63,7 @@ void UnitListController::setExpression(Poincare::Expression e) { ); requireSimplification = true; // reduce the conversion canChangeUnitPrefix = true; // Pick best prefix (mL) + numberOfMemoizedExpressions++; } else if (Unit::IsISEnergy(units)) { // 2.c. Turn energy into Wh m_memoizedExpressions[1] = UnitConvert::Builder( @@ -68,29 +73,47 @@ void UnitListController::setExpression(Poincare::Expression e) { Unit::Hour() ) ); + m_memoizedExpressions[2] = UnitConvert::Builder( + m_expression.clone(), + Unit::ElectronVolt() + ); requireSimplification = true; // reduce the conversion canChangeUnitPrefix = true; // Pick best prefix (kWh) + numberOfMemoizedExpressions += 2; } else if (Unit::IsISTime(units)) { // Turni time into ? year + ? month + ? day + ? h + ? min + ? s double value = Shared::PoincareHelpers::ApproximateToScalar(copy, App::app()->localContext()); m_memoizedExpressions[1] = Unit::BuildTimeSplit(value); + numberOfMemoizedExpressions++; } - if (requireSimplification) { - Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[1], App::app()->localContext(), ExpressionNode::ReductionTarget::User); + size_t currentExpressionIndex = 1; + while (currentExpressionIndex < numberOfMemoizedExpressions) { + assert(!m_memoizedExpressions[currentExpressionIndex].isUninitialized()); + if (requireSimplification) { + Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User); + } + if (canChangeUnitPrefix) { + Expression newUnits; + m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits); + double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext()); + Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); + m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits); + } + // Scan previous expressions to avoid duplicates + for (size_t i = 0; i < currentExpressionIndex; i++) { + assert(!m_memoizedExpressions[i].isUninitialized()); + if (m_memoizedExpressions[i].isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) { + // Shift next expressions + for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions-1; j++) { + m_memoizedExpressions[j] = m_memoizedExpressions[j+1]; + } + // Remove last expression + m_memoizedExpressions[numberOfMemoizedExpressions - 1] = Expression(); + break; + } + } + currentExpressionIndex++; } - if (canChangeUnitPrefix) { - Expression newUnits; - m_memoizedExpressions[1] = m_memoizedExpressions[1].removeUnit(&newUnits); - double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[1], App::app()->localContext()); - Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); - m_memoizedExpressions[1] = Multiplication::Builder(Number::FloatNumber(value), newUnits); - } - - if (!m_memoizedExpressions[1].isUninitialized() && m_memoizedExpressions[0].isIdenticalTo(m_memoizedExpressions[1])) { - // Avoid displaying duplicate - m_memoizedExpressions[1] = Expression(); - } - // TODO m_memoizedExpressions[2]? } int UnitListController::numberOfRows() const { From 73a598e02353db4febb955f0280decaa733d7495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 11:41:03 +0200 Subject: [PATCH 135/453] [poincare] Unit: enable to tune both the prefix and the Representant or just the prefix on a given Unit --- .../additional_outputs/unit_list_controller.cpp | 2 +- poincare/include/poincare/unit.h | 6 ++++-- poincare/src/multiplication.cpp | 2 +- poincare/src/unit.cpp | 15 +++++++++------ 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index 121498c8e..e36f9e9bf 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -96,7 +96,7 @@ void UnitListController::setExpression(Poincare::Expression e) { Expression newUnits; m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits); double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext()); - Unit::ChooseBestMultipleForValue(&newUnits, &value, reductionContext); + Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext); m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits); } // Scan previous expressions to avoid duplicates diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 518879ad1..e9bb2f2f6 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -770,14 +770,16 @@ public: // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); - static void ChooseBestMultipleForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext); + static void ChooseBestRepresentativeAndPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, true, reductionContext); } + static void ChooseBestPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, false, reductionContext); } static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; static constexpr double JouleToWatthourFactor = 1.0/3600.0; private: UnitNode * node() const { return static_cast(Expression::node()); } - void chooseBestMultipleForValue(double * value, const int exponent, ExpressionNode::ReductionContext reductionContext); + static void ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); + void chooseBestMultipleForValue(double * value, const int exponent, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); Expression removeUnit(Expression * unit); }; diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 2e2fc2bc1..519d8c520 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -441,7 +441,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } else { if (unitConversionMode == ExpressionNode::UnitConversion::Default) { // Find the right unit prefix - Unit::ChooseBestMultipleForValue(&units, &value, reductionContext); + Unit::ChooseBestRepresentativeAndPrefixForValue(&units, &value, reductionContext); } // Build final Expression result = Multiplication::Builder(Number::FloatNumber(value), units); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 68b7b555c..93ca0252e 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -321,7 +321,7 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext return result; } -void Unit::ChooseBestMultipleForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { +void Unit::ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext) { // Identify the first Unit factor and its exponent Expression firstFactor = *units; int exponent = 1; @@ -343,25 +343,28 @@ void Unit::ChooseBestMultipleForValue(Expression * units, double * value, Expres assert(firstFactor.type() == ExpressionNode::Type::Unit); // Choose its multiple and update value accordingly if (exponent != 0) { - static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext); + static_cast(firstFactor).chooseBestMultipleForValue(value, exponent, tuneRepresentative, reductionContext); } } -void Unit::chooseBestMultipleForValue(double * value, const int exponent, ExpressionNode::ReductionContext reductionContext) { +void Unit::chooseBestMultipleForValue(double * value, const int exponent, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext) { assert(!std::isnan(*value) && exponent != 0); if (*value == 0 || *value == 1.0 || std::isinf(*value)) { return; } UnitNode * unitNode = node(); const Dimension * dim = unitNode->dimension(); - /* Find in the Dimension 'dim' which unit (Representative and Prefix) make - * the value closer to 1. + /* Find in the Dimension 'dim' which unit (Prefix and optionally + * Representative) make the value closer to 1. */ const Representative * bestRep = unitNode->representative(); const Prefix * bestPre = unitNode->prefix(); double bestVal = *value; - for (const Representative * rep = dim->stdRepresentative(); rep < dim->representativesUpperBound(); rep++) { + // Test all representatives if tuneRepresentative is on. Otherwise, force current representative + const Representative * startRep = tuneRepresentative ? dim->stdRepresentative() : bestRep; + const Representative * endRep = tuneRepresentative ? dim->representativesUpperBound() : bestRep + 1; + for (const Representative * rep = startRep; rep < endRep; rep++) { // evaluate quotient double val = *value * std::pow(Division::Builder(clone(), Unit::Builder(dim, rep, &EmptyPrefix)).deepReduce(reductionContext).approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()), exponent); // Get the best prefix and update val accordingly From 115ae59b5a1b5c51d4a437e74b5c3530d4e3f550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 12:20:14 +0200 Subject: [PATCH 136/453] [apps/calculation] additional_outputs: reorder unit addition outputs --- .../unit_list_controller.cpp | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index e36f9e9bf..184ab5f06 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -21,12 +21,7 @@ void UnitListController::setExpression(Poincare::Expression e) { } size_t numberOfMemoizedExpressions = 0; - // 1. First result: SI units only - m_memoizedExpressions[0] = m_expression.clone(); - Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[0], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); - numberOfMemoizedExpressions++; - - // 2. Next results: miscellaneous classic units for some dimensions + // 1. First rows: miscellaneous classic units for some dimensions ExpressionNode::ReductionContext reductionContext( App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), @@ -42,8 +37,8 @@ void UnitListController::setExpression(Poincare::Expression e) { bool canChangeUnitPrefix = false; if (Unit::IsISSpeed(units)) { - // 2.a. Turn speed into km/h - m_memoizedExpressions[1] = UnitConvert::Builder( + // 1.a. Turn speed into km/h + m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder( m_expression.clone(), Multiplication::Builder( Unit::Kilometer(), @@ -54,39 +49,36 @@ void UnitListController::setExpression(Poincare::Expression e) { ) ); requireSimplification = true; // Reduce the conversion - numberOfMemoizedExpressions++; } else if (Unit::IsISVolume(units)) { - // 2.b. Turn volume into L - m_memoizedExpressions[1] = UnitConvert::Builder( + // 1.b. Turn volume into L + m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder( m_expression.clone(), Unit::Liter() ); requireSimplification = true; // reduce the conversion canChangeUnitPrefix = true; // Pick best prefix (mL) - numberOfMemoizedExpressions++; } else if (Unit::IsISEnergy(units)) { - // 2.c. Turn energy into Wh - m_memoizedExpressions[1] = UnitConvert::Builder( + // 1.c. Turn energy into Wh + m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder( m_expression.clone(), Multiplication::Builder( Unit::Watt(), Unit::Hour() ) ); - m_memoizedExpressions[2] = UnitConvert::Builder( + m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder( m_expression.clone(), Unit::ElectronVolt() ); requireSimplification = true; // reduce the conversion canChangeUnitPrefix = true; // Pick best prefix (kWh) - numberOfMemoizedExpressions += 2; } else if (Unit::IsISTime(units)) { - // Turni time into ? year + ? month + ? day + ? h + ? min + ? s + // Turn time into ? year + ? month + ? day + ? h + ? min + ? s double value = Shared::PoincareHelpers::ApproximateToScalar(copy, App::app()->localContext()); - m_memoizedExpressions[1] = Unit::BuildTimeSplit(value); - numberOfMemoizedExpressions++; + m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value); } - size_t currentExpressionIndex = 1; + // 1.d. Simplify and tune prefix of all computed expressions + size_t currentExpressionIndex = 0; while (currentExpressionIndex < numberOfMemoizedExpressions) { assert(!m_memoizedExpressions[currentExpressionIndex].isUninitialized()); if (requireSimplification) { @@ -99,19 +91,33 @@ void UnitListController::setExpression(Poincare::Expression e) { Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext); m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits); } - // Scan previous expressions to avoid duplicates + currentExpressionIndex++; + } + + // 2. IS units only + assert(numberOfMemoizedExpressions < k_maxNumberOfCells - 1); + m_memoizedExpressions[numberOfMemoizedExpressions] = m_expression.clone(); + Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[numberOfMemoizedExpressions], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem); + numberOfMemoizedExpressions++; + + // 3. Get rid of duplicates + currentExpressionIndex = 1; + while (currentExpressionIndex < numberOfMemoizedExpressions) { for (size_t i = 0; i < currentExpressionIndex; i++) { assert(!m_memoizedExpressions[i].isUninitialized()); if (m_memoizedExpressions[i].isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) { + numberOfMemoizedExpressions--; // Shift next expressions - for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions-1; j++) { + for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions; j++) { m_memoizedExpressions[j] = m_memoizedExpressions[j+1]; } // Remove last expression - m_memoizedExpressions[numberOfMemoizedExpressions - 1] = Expression(); - break; + m_memoizedExpressions[numberOfMemoizedExpressions] = Expression(); + // The current expression has been discarded, no need to increment thre current index + continue; } } + // The current expression is not a duplicate, check next expression currentExpressionIndex++; } } From fe0a858352a422b7cde759105d48a28fcd5090e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 12:20:32 +0200 Subject: [PATCH 137/453] [poincare] Unit: improve BuildTimeSplit to avoid displaing null sub unit in the final addition and to keep the fractional part of the seconds --- poincare/src/unit.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 93ca0252e..71164e7a9 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -435,8 +435,8 @@ bool Unit::IsISTime(Expression & e) { Expression Unit::BuildTimeSplit(double seconds) { assert(!std::isnan(seconds)); - if (std::isinf(seconds)) { - return Multiplication::Builder(Infinity::Builder(seconds < 0.0), Unit::Second()); + if (std::isinf(seconds) || std::fabs(seconds) < Expression::Epsilon()) { + return Multiplication::Builder(Number::FloatNumber(seconds), Unit::Second()); } double remain = seconds; constexpr static int numberOfTimeUnits = 6; @@ -446,10 +446,16 @@ Expression Unit::BuildTimeSplit(double seconds) { double valuesPerUnit[numberOfTimeUnits]; Addition a = Addition::Builder(); for (size_t i = 0; i < numberOfTimeUnits; i++) { - valuesPerUnit[i] = std::floor(remain/timeFactors[i]); + valuesPerUnit[i] = remain/timeFactors[i]; + // Keep only the floor of the values except for the last unit (seconds) + if (i < numberOfTimeUnits - 1) { + valuesPerUnit[i] = std::floor(valuesPerUnit[i]); + } remain -= valuesPerUnit[i]*timeFactors[i]; - Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); - a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); + if (std::fabs(valuesPerUnit[i]) > Expression::Epsilon()) { + Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); + a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); + } if (std::fabs(remain) < Expression::Epsilon()) { break; } From 23540e93ce944769aca336f3d11c29ca89f9b19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 14:58:33 +0200 Subject: [PATCH 138/453] [poincare] Unit::BuildTimeSplit rounds its argument to avoid displaying very small seconds due to approximations This fixes: Input "310_min", in additional results, you get "5_h+10_min+0.000000???_s" --- poincare/src/unit.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 71164e7a9..32a2da66e 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -438,7 +438,16 @@ Expression Unit::BuildTimeSplit(double seconds) { if (std::isinf(seconds) || std::fabs(seconds) < Expression::Epsilon()) { return Multiplication::Builder(Number::FloatNumber(seconds), Unit::Second()); } - double remain = seconds; + /* Round the number of seconds to 13 significant digits + * (= k_numberOfStoredSignificantDigits - 1). + * Indeed, the user input has been converted to the most adequate unit + * which might have led to approximating the value to 14 significants + * digits. The number of seconds was then computed from this approximation. + * We thus round it to avoid displaying small numbers of seconds that are + * artifacts of the previous approximations. */ + double err = std::pow(10.0, Poincare::PrintFloat::k_numberOfStoredSignificantDigits - 1 - std::ceil(log10(std::fabs(seconds)))); + double remain = std::round(seconds*err)/err; + constexpr static int numberOfTimeUnits = 6; // This could be computed from the time representatives but we same time by using constexpr double constexpr static double timeFactors[numberOfTimeUnits] = {365.25*24.0*60.0*60.0, 365.25/12.0*24.0*60.0*60.0, 24.0*60.0*60.0, 60.0*60.0, 60.0, 1.0 }; @@ -456,9 +465,6 @@ Expression Unit::BuildTimeSplit(double seconds) { Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); } - if (std::fabs(remain) < Expression::Epsilon()) { - break; - } } return a.squashUnaryHierarchyInPlace(); } From 5fa50ec79d55f770bc5edf9929721099dd31f5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 18:11:09 +0200 Subject: [PATCH 139/453] [poincare] Unit::BuildTimeSplit can split negative time --- .../additional_outputs/unit_list_controller.cpp | 2 +- poincare/include/poincare/unit.h | 2 +- poincare/src/unit.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index 184ab5f06..c8f654e10 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -75,7 +75,7 @@ void UnitListController::setExpression(Poincare::Expression e) { } else if (Unit::IsISTime(units)) { // Turn time into ? year + ? month + ? day + ? h + ? min + ? s double value = Shared::PoincareHelpers::ApproximateToScalar(copy, App::app()->localContext()); - m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value); + m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value, App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), Preferences::sharedPreferences()->angleUnit()); } // 1.d. Simplify and tune prefix of all computed expressions size_t currentExpressionIndex = 0; diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index e9bb2f2f6..be7c14910 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -758,7 +758,7 @@ public: static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } static Unit ElectronVolt() { return Builder(EnergyDimension, ElectronVoltRepresentative, &EmptyPrefix); } static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } - static Expression BuildTimeSplit(double seconds); + static Expression BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 32a2da66e..74642d7d4 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -433,7 +433,7 @@ bool Unit::IsISTime(Expression & e) { return e.type() == ExpressionNode::Type::Unit && static_cast(e).isSecond(); } -Expression Unit::BuildTimeSplit(double seconds) { +Expression Unit::BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { assert(!std::isnan(seconds)); if (std::isinf(seconds) || std::fabs(seconds) < Expression::Epsilon()) { return Multiplication::Builder(Number::FloatNumber(seconds), Unit::Second()); @@ -458,7 +458,7 @@ Expression Unit::BuildTimeSplit(double seconds) { valuesPerUnit[i] = remain/timeFactors[i]; // Keep only the floor of the values except for the last unit (seconds) if (i < numberOfTimeUnits - 1) { - valuesPerUnit[i] = std::floor(valuesPerUnit[i]); + valuesPerUnit[i] = valuesPerUnit[i] >= 0.0 ? std::floor(valuesPerUnit[i]) : std::ceil(valuesPerUnit[i]); } remain -= valuesPerUnit[i]*timeFactors[i]; if (std::fabs(valuesPerUnit[i]) > Expression::Epsilon()) { @@ -466,7 +466,9 @@ Expression Unit::BuildTimeSplit(double seconds) { a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); } } - return a.squashUnaryHierarchyInPlace(); + ExpressionNode::ReductionContext reductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion::None); + // Beautify the addition into an subtraction if necessary + return a.squashUnaryHierarchyInPlace().shallowBeautify(reductionContext); } template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; From a248302132999bc27fbeb0835a2aa1771f04096d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 18:12:33 +0200 Subject: [PATCH 140/453] [poincare] Unit: define order on representatives in a way that time addition are displayed: years + months + ... + seconds --- poincare/src/unit.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 74642d7d4..2aa75e81b 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -183,7 +183,10 @@ int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascendi } const ptrdiff_t repdiff = eNode->representative() - m_representative; if (repdiff != 0) { - return repdiff; + /* We order representatives in the reverse order as how they're stored in + * the representatives table. This enables to sort addition of time as: + * year + month + days + hours + minutes + seconds. */ + return -repdiff; } const ptrdiff_t prediff = eNode->prefix() - m_prefix; return prediff; From 22fd3388ed469bf518bccfdd94defda71e0c8780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 18:13:22 +0200 Subject: [PATCH 141/453] [poincare] Add tests on Unit::BuildTimeSplit --- poincare/test/expression.cpp | 44 +++++++++--------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/poincare/test/expression.cpp b/poincare/test/expression.cpp index fa3efbafe..057f08d12 100644 --- a/poincare/test/expression.cpp +++ b/poincare/test/expression.cpp @@ -74,6 +74,14 @@ QUIZ_CASE(poincare_expression_rational_constructor) { assert_pool_size(initialPoolSize+6); } +void assert_seconds_split_to(double totalSeconds, const char * splittedTime, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + Expression time = Unit::BuildTimeSplit(totalSeconds, context, complexFormat, angleUnit); + constexpr static int bufferSize = 100; + char buffer[bufferSize]; + time.serialize(buffer, bufferSize, DecimalMode); + quiz_assert_print_if_failure(strcmp(buffer, splittedTime) == 0, splittedTime); +} + QUIZ_CASE(poincare_expression_unit_constructor) { Shared::GlobalContext globalContext; ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); @@ -81,39 +89,9 @@ QUIZ_CASE(poincare_expression_unit_constructor) { Unit s = Unit::Second(); quiz_assert(s.isSecond()); quiz_assert(!s.isMeter()); - Expression time = Unit::BuildTimeSplit(1234567890); - Addition a = Addition::Builder(); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(39.0), - Unit::Year() - ), - 0, 0); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(1.0), - Unit::Month() - ), - 1, 1); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(13.0), - Unit::Day() - ), - 2, 2); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(19.0), - Unit::Hour() - ), - 3, 3); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(1.0), - Unit::Minute() - ), - 4, 4); - a.addChildAtIndexInPlace(Multiplication::Builder( - Float::Builder(30.0), - Unit::Second() - ), - 5, 5); - quiz_assert(a.isIdenticalTo(time)); + + assert_seconds_split_to(1234567890, "39×_year+1×_month+13×_day+19×_h+1×_min+30×_s", &globalContext, Cartesian, Degree); + assert_seconds_split_to(-122, "-2×_min-2×_s", &globalContext, Cartesian, Degree); // Speed Expression kilometerPerHour = Multiplication::Builder( From 62e2e733b2e3523da5aaf4a3fe24662c4b05aa1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 29 Apr 2020 18:16:41 +0200 Subject: [PATCH 142/453] [poincare] Add comment on unit tests --- poincare/test/expression.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/poincare/test/expression.cpp b/poincare/test/expression.cpp index 057f08d12..10f81b9d9 100644 --- a/poincare/test/expression.cpp +++ b/poincare/test/expression.cpp @@ -85,15 +85,18 @@ void assert_seconds_split_to(double totalSeconds, const char * splittedTime, Con QUIZ_CASE(poincare_expression_unit_constructor) { Shared::GlobalContext globalContext; ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); - // Time + // 1. Time + // 1.a. Test Unit::Second constructor Unit s = Unit::Second(); + // 1.b. Test Unit::isSecond helper quiz_assert(s.isSecond()); quiz_assert(!s.isMeter()); - + // 1.c. Test Unit::BuildTimeSplit constructor assert_seconds_split_to(1234567890, "39×_year+1×_month+13×_day+19×_h+1×_min+30×_s", &globalContext, Cartesian, Degree); assert_seconds_split_to(-122, "-2×_min-2×_s", &globalContext, Cartesian, Degree); - // Speed + // 2. Speed + // 2.a. test Unit::Kilometer and Unit::Hour constructors Expression kilometerPerHour = Multiplication::Builder( Unit::Kilometer(), Power::Builder( @@ -104,16 +107,20 @@ QUIZ_CASE(poincare_expression_unit_constructor) { kilometerPerHour = kilometerPerHour.reduce(reductionContext); Expression meterPerSecond; kilometerPerHour = kilometerPerHour.removeUnit(&meterPerSecond); + // 2.b. Test Unit::IsISSpeed helper quiz_assert(Unit::IsISSpeed(meterPerSecond)); - // Volume + // 3. Volume + // 3.a. test Unit::Liter constructor Expression liter = Unit::Liter(); liter = liter.reduce(reductionContext); Expression meter3; liter = liter.removeUnit(&meter3); + // 3.b. Test Unit::IsISVolume helper quiz_assert(Unit::IsISVolume(meter3)); - // Energy + // 4. Energy + // 4.a. test Unit::Watt and Unit::Hour constructors Expression wattHour = Multiplication::Builder( Unit::Watt(), Unit::Hour() @@ -121,5 +128,6 @@ QUIZ_CASE(poincare_expression_unit_constructor) { wattHour = wattHour.reduce(reductionContext); Expression kilogramMeter2PerSecond2; wattHour = wattHour.removeUnit(&kilogramMeter2PerSecond2); + // 4.b. Test Unit::IsISEnergy helper quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); } From 9b8b0bc98f6f1e80d6d63017a2e11b03cd1108bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Mar 2020 11:56:14 +0100 Subject: [PATCH 143/453] [apps/code] PythonTextArea should always be the PythonUser when coloring --- apps/code/python_text_area.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index b1a243af1..e924a03d2 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -75,23 +75,7 @@ void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const { LOG_DRAW("Drawing \"%.*s\"\n", byteLength, text); - if (!m_pythonDelegate->isPythonUser(this)) { - const char * lineStart = UTF8Helper::CodePointAtGlyphOffset(text, fromColumn); - const char * lineEnd = UTF8Helper::CodePointAtGlyphOffset(text, toColumn); - drawStringAt( - ctx, - line, - fromColumn, - lineStart, - std::min(text + byteLength, lineEnd) - lineStart, - StringColor, - BackgroundColor, - selectionStart, - selectionEnd, - HighlightColor - ); - return; - } + assert(m_pythonDelegate->isPythonUser(this)); /* We're using the MicroPython lexer to do syntax highlighting on a per-line * basis. This can work, however the MicroPython lexer won't accept a line From 32fbea9d06a540c8c9a1f0c7f73e09a080b86598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Mar 2020 18:58:39 +0100 Subject: [PATCH 144/453] [apps/code] Handle autocomplete coloring --- apps/code/python_text_area.cpp | 22 ++++++++++++++++++++++ apps/code/python_text_area.h | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index e924a03d2..d58adcdef 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -19,6 +19,7 @@ constexpr KDColor KeywordColor = KDColor::RGB24(0xFF000C); // constexpr KDColor BuiltinColor = KDColor::RGB24(0x0086B3); constexpr KDColor OperatorColor = KDColor::RGB24(0xd73a49); constexpr KDColor StringColor = KDColor::RGB24(0x032f62); +constexpr KDColor AutocompleteColor = KDColorRed; constexpr KDColor BackgroundColor = KDColorWhite; constexpr KDColor HighlightColor = Palette::Select; @@ -160,6 +161,27 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char mp_lexer_free(lex); nlr_pop(); } + + // Redraw the autocompleted word in the right color + const char * autocompleteStart = m_cursorLocation; + assert(autocompleteStart != text); + if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { + const char * autocompleteEnd = cursorLocation(); + while (*autocompleteEnd != ' ' && autocompleteEnd < text + byteLength) { + autocompleteEnd++; + } + drawStringAt( + ctx, + line, + UTF8Helper::GlyphOffsetAtCodePoint(text, autocompleteStart), + autocompleteStart, + minPointer(text + byteLength, autocompleteEnd) - autocompleteStart, + AutocompleteColor, + BackgroundColor, + nullptr, + nullptr, + HighlightColor); + } } KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, bool includeFollowingLines) const { diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 149d6bfd0..cfc6e23ef 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -21,7 +21,8 @@ protected: public: ContentView(App * pythonDelegate, const KDFont * font) : TextArea::ContentView(font), - m_pythonDelegate(pythonDelegate) + m_pythonDelegate(pythonDelegate), + m_autocomplete(false) { } void loadSyntaxHighlighter(); @@ -31,6 +32,7 @@ protected: KDRect dirtyRectFromPosition(const char * position, bool includeFollowingLines) const override; private: App * m_pythonDelegate; + bool m_autocomplete; }; private: const ContentView * nonEditableContentView() const override { return &m_contentView; } From 343d2328b8b10b5c101313f1788a82ed221a9add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 16:00:33 +0100 Subject: [PATCH 145/453] [ion/utf8_helper] EndOfWord helper --- apps/code/python_text_area.cpp | 5 +---- ion/include/ion/unicode/utf8_helper.h | 3 +++ ion/src/shared/unicode/utf8_helper.cpp | 10 ++++++++++ ion/test/utf8_helper.cpp | 13 +++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index d58adcdef..bcc839b28 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -166,10 +166,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char const char * autocompleteStart = m_cursorLocation; assert(autocompleteStart != text); if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { - const char * autocompleteEnd = cursorLocation(); - while (*autocompleteEnd != ' ' && autocompleteEnd < text + byteLength) { - autocompleteEnd++; - } + const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); drawStringAt( ctx, line, diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index 8f5e17c2d..fc906c03c 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -81,6 +81,9 @@ size_t GlyphOffsetAtCodePoint(const char * buffer, const char * position); * For instance, strlen("∑") = 3 but StringGlyphLength("∑") = 1 */ size_t StringGlyphLength(const char * s, int maxSize = -1); +// Returns the position of the first char between ' ', '\n' and 0. +const char * EndOfWord(const char * word); + }; #endif diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index 07c5c5838..f17841394 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -363,4 +363,14 @@ size_t StringGlyphLength(const char * s, int maxSize) { return glyphIndex; } +const char * EndOfWord(const char * word) { + assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1); + assert(UTF8Decoder::CharSizeOfCodePoint('\n') == 1); + const char * result = word; + while (*result != ' ' && *result != '\n' && *result != UCodePointNull) { + result++; + } + return result; +} + } diff --git a/ion/test/utf8_helper.cpp b/ion/test/utf8_helper.cpp index 39be3b366..2179f971f 100644 --- a/ion/test/utf8_helper.cpp +++ b/ion/test/utf8_helper.cpp @@ -273,3 +273,16 @@ QUIZ_CASE(ion_utf8_helper_string_glyph_length) { uint8_t testString[] = {'a', 'b', 'c', 0b11111111, 0b11111111, 0}; // Malformed utf-8 string assert_string_glyph_length_is((const char *)testString, 3, 3); } + + +void assert_end_of_word_is(const char * word, const char * endOfWord) { + quiz_assert(UTF8Helper::EndOfWord(word) == endOfWord); +} + +QUIZ_CASE(ion_utf8_helper_end_of_word) { + const char * test_sentence = "01 34+ 789"; + assert_end_of_word_is(test_sentence, test_sentence + 2); + assert_end_of_word_is(test_sentence + 2, test_sentence + 2); + assert_end_of_word_is(test_sentence + 3, test_sentence + 6); + assert_end_of_word_is(test_sentence + 8, test_sentence + 10); +} From 938e0dd84032c7f1d005f4b61923bc6a576c42e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 16:00:52 +0100 Subject: [PATCH 146/453] [apps/code] Autocompletion steps --- apps/code/python_text_area.cpp | 34 +++++++++++++++++++++++++++++++ apps/code/python_text_area.h | 5 +++++ escher/include/escher/text_area.h | 1 + escher/src/text_area.cpp | 6 +++++- 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index bcc839b28..08f751efd 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -196,4 +196,38 @@ KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, ); } +bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) { + if (*text == 0) { + return false; + } + if (m_contentView.isAutocompleting()) { + removeAutocompletion(); + } + bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText); + addAutocompletion(); + return result; +} + +void PythonTextArea::removeAutocompletion() { + assert(m_contentView.isAutocompleting()); + const char * autocompleteStart = m_contentView.cursorLocation(); + const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); + assert(autocompleteEnd > autocompleteStart); + m_contentView.removeText(autocompleteStart, autocompleteEnd); + m_contentView.setAutocompleting(false); +} + +void PythonTextArea::addAutocompletion() { + assert(!m_contentView.isAutocompleting()); + + // Compute the text to insert + // TODO LEA + const char * textToInsert = "test"; + + // Try to insert the text (this might fail if the buffer is full) + if (textToInsert && m_contentView.insertTextAtLocation(textToInsert, const_cast(cursorLocation()))) { + m_contentView.setAutocompleting(true); + } +} + } diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index cfc6e23ef..c05d24709 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -16,6 +16,7 @@ public: } void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); } void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } + bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; protected: class ContentView : public TextArea::ContentView { public: @@ -25,6 +26,8 @@ protected: m_autocomplete(false) { } + void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } + bool isAutocompleting() const { return m_autocomplete; } void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); void clearRect(KDContext * ctx, KDRect rect) const override; @@ -35,6 +38,8 @@ protected: bool m_autocomplete; }; private: + void removeAutocompletion(); + void addAutocompletion(); const ContentView * nonEditableContentView() const override { return &m_contentView; } ContentView m_contentView; }; diff --git a/escher/include/escher/text_area.h b/escher/include/escher/text_area.h index 640511dc1..7d7e58716 100644 --- a/escher/include/escher/text_area.h +++ b/escher/include/escher/text_area.h @@ -122,6 +122,7 @@ protected: bool removePreviousGlyph() override; bool removeEndOfLine() override; bool removeStartOfLine(); + size_t removeText(const char * start, const char * end); size_t deleteSelection() override; protected: KDRect glyphFrameAtPosition(const char * text, const char * position) const override; diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index 5a28a2a18..11dfc4045 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -521,9 +521,13 @@ bool TextArea::ContentView::removeStartOfLine() { return false; } +size_t TextArea::ContentView::removeText(const char * start, const char * end) { + return m_text.removeText(start, end); +} + size_t TextArea::ContentView::deleteSelection() { assert(!selectionIsEmpty()); - size_t removedLength = m_text.removeText(m_selectionStart, m_selectionEnd); + size_t removedLength = removeText(m_selectionStart, m_selectionEnd); /* We cannot call resetSelection() because m_selectionStart and m_selectionEnd * are invalid */ m_selectionStart = nullptr; From 5dd4f12ee33add493d42026e95e3f624515dd283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 16:41:26 +0100 Subject: [PATCH 147/453] [apps/code] Handle acception/dismissal of autocompletion --- apps/code/python_text_area.cpp | 31 +++++++++++++++++++++++++++++++ apps/code/python_text_area.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 08f751efd..d3ab068ef 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -196,6 +196,27 @@ KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, ); } +bool PythonTextArea::handleEvent(Ion::Events::Event event) { + if (m_contentView.isAutocompleting()) { + // Handle event with autocompletion + if (event == Ion::Events::Toolbox || event == Ion::Events::Var) { + } else if (event == Ion::Events::Right + || event == Ion::Events::ShiftRight + || event == Ion::Events::OK) + { + acceptAutocompletion(event != Ion::Events::ShiftRight); + if (event != Ion::Events::ShiftRight) { + // Do not process the event more + scrollToCursor(); + return true; + } + } else { + removeAutocompletion(); + } + } + return TextArea::handleEvent(event); +} + bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) { if (*text == 0) { return false; @@ -230,4 +251,14 @@ void PythonTextArea::addAutocompletion() { } } +void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) { + assert(m_contentView.isAutocompleting()); + m_contentView.setAutocompleting(false); + if (moveCursorToEndOfAutocompletion) { + const char * autocompleteEnd = UTF8Helper::EndOfWord(m_contentView.cursorLocation()); + setCursorLocation(autocompleteEnd); + addAutocompletion(); + } +} + } diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index c05d24709..85a6f5ab5 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -16,6 +16,7 @@ public: } void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); } void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } + bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; protected: class ContentView : public TextArea::ContentView { @@ -40,6 +41,7 @@ protected: private: void removeAutocompletion(); void addAutocompletion(); + void acceptAutocompletion(bool moveCursorToEndOfAutocompletion); const ContentView * nonEditableContentView() const override { return &m_contentView; } ContentView m_contentView; }; From a2cc923a026776dab0cf06b97ee60fb5249bfee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 16:45:57 +0100 Subject: [PATCH 148/453] [apps/code] Fix assertion --- apps/code/python_text_area.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index d3ab068ef..54e0fe390 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -164,8 +164,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char // Redraw the autocompleted word in the right color const char * autocompleteStart = m_cursorLocation; - assert(autocompleteStart != text); - if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { + assert(!m_autocomplete || autocompleteStart != text); + if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); drawStringAt( ctx, From f82079a40a3763e7396743546eecc7e206dc8508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 16:51:28 +0100 Subject: [PATCH 149/453] [apps/code] Autocomplete only if char before cursor is not ' ' or '\n' --- apps/code/python_text_area.cpp | 17 ++++++++++++----- ion/include/ion/unicode/utf8_helper.h | 2 ++ ion/src/shared/unicode/utf8_helper.cpp | 24 ++++++++++++++++++------ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 54e0fe390..ba7172ec3 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -165,7 +165,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char // Redraw the autocompleted word in the right color const char * autocompleteStart = m_cursorLocation; assert(!m_autocomplete || autocompleteStart != text); - if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { + if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); drawStringAt( ctx, @@ -241,12 +241,19 @@ void PythonTextArea::removeAutocompletion() { void PythonTextArea::addAutocompletion() { assert(!m_contentView.isAutocompleting()); - // Compute the text to insert - // TODO LEA - const char * textToInsert = "test"; + const char * autocompletionLocation = const_cast(cursorLocation()); + const char * textToInsert = nullptr; + CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), autocompletionLocation); + if (!UTF8Helper::CodePointIsEndOfWord(prevCodePoint)) { + /* The previous code point is neither the beginning of the text, nor a + * space, nor a \n. + * Compute the text to insert */ + // TODO LEA + textToInsert = "test"; + } // Try to insert the text (this might fail if the buffer is full) - if (textToInsert && m_contentView.insertTextAtLocation(textToInsert, const_cast(cursorLocation()))) { + if (textToInsert && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation))) { m_contentView.setAutocompleting(true); } } diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index fc906c03c..32ef6f042 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -66,8 +66,10 @@ const char * PerformAtCodePoints( const char * initialPosition = nullptr, const char * stoppingPosition = nullptr); +CodePoint PreviousCodePoint(const char * buffer, const char * location); // returns 0 if location == buffer bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c); bool CodePointIs(const char * location, CodePoint c); +bool CodePointIsEndOfWord(CodePoint c); // Shift the buffer and return the number of bytes removed. int RemovePreviousGlyph(const char * text, char * location, CodePoint * c = nullptr); diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index f17841394..3f0d44f36 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -257,13 +257,20 @@ const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction ac return codePointPointer; } +CodePoint PreviousCodePoint(const char * buffer, const char * location) { + if (location == buffer) { + return UCodePointNull; + } + UTF8Decoder decoder(buffer, location); + return decoder.previousCodePoint(); +} + bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c) { assert(location > buffer); if (UTF8Decoder::CharSizeOfCodePoint(c) == 1) { return *(location -1) == c; } - UTF8Decoder decoder(buffer, location); - return decoder.previousCodePoint() == c; + return PreviousCodePoint(buffer, location) == c; } bool CodePointIs(const char * location, CodePoint c) { @@ -274,6 +281,10 @@ bool CodePointIs(const char * location, CodePoint c) { return decoder.nextCodePoint() == c; } +bool CodePointIsEndOfWord(CodePoint c) { + return c == '\n' || c == ' ' || c == UCodePointNull; +} + int RemovePreviousGlyph(const char * text, char * location, CodePoint * c) { if (location <= text) { assert(location == text); @@ -364,11 +375,12 @@ size_t StringGlyphLength(const char * s, int maxSize) { } const char * EndOfWord(const char * word) { - assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1); - assert(UTF8Decoder::CharSizeOfCodePoint('\n') == 1); + UTF8Decoder decoder(word); + CodePoint codePoint = decoder.nextCodePoint(); const char * result = word; - while (*result != ' ' && *result != '\n' && *result != UCodePointNull) { - result++; + while (!CodePointIsEndOfWord(codePoint)) { + result = decoder.stringPosition(); + codePoint = decoder.nextCodePoint(); } return result; } From 77e34f04462087aa236d67392be9be0a0aeed6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 13 Mar 2020 19:59:54 +0100 Subject: [PATCH 150/453] [apps/code] Reload the view for autocompletion changes --- apps/code/python_text_area.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index ba7172ec3..bf5e8c28c 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -204,6 +204,7 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { || event == Ion::Events::ShiftRight || event == Ion::Events::OK) { + m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); acceptAutocompletion(event != Ion::Events::ShiftRight); if (event != Ion::Events::ShiftRight) { // Do not process the event more @@ -212,6 +213,7 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { } } else { removeAutocompletion(); + m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); } } return TextArea::handleEvent(event); From 1e2492c5f4e51f275df2d2720d89fa92aabd51f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 17 Mar 2020 16:02:48 +0100 Subject: [PATCH 151/453] [apps/code] Autocomplete only at the end of the word For instance, if the cursor is: "he|llo" and the user adds the letter 'i', there is no autocompletion provided as the cursor is still in the middle of a word. --- apps/code/python_text_area.cpp | 6 ++++-- ion/include/ion/unicode/utf8_helper.h | 1 + ion/src/shared/unicode/utf8_helper.cpp | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index bf5e8c28c..54b7eeaf3 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -246,9 +246,11 @@ void PythonTextArea::addAutocompletion() { const char * autocompletionLocation = const_cast(cursorLocation()); const char * textToInsert = nullptr; CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), autocompletionLocation); - if (!UTF8Helper::CodePointIsEndOfWord(prevCodePoint)) { + if (!UTF8Helper::CodePointIsEndOfWord(prevCodePoint) + && UTF8Helper::CodePointIsEndOfWord(UTF8Helper::CodePointAtLocation(autocompletionLocation))) + { /* The previous code point is neither the beginning of the text, nor a - * space, nor a \n. + * space, nor a \n, and the next code point is the end of the word. * Compute the text to insert */ // TODO LEA textToInsert = "test"; diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index 32ef6f042..8b20a926f 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -67,6 +67,7 @@ const char * PerformAtCodePoints( const char * stoppingPosition = nullptr); CodePoint PreviousCodePoint(const char * buffer, const char * location); // returns 0 if location == buffer +CodePoint CodePointAtLocation(const char * location); bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c); bool CodePointIs(const char * location, CodePoint c); bool CodePointIsEndOfWord(CodePoint c); diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index 3f0d44f36..7ddc93f7c 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -265,6 +265,11 @@ CodePoint PreviousCodePoint(const char * buffer, const char * location) { return decoder.previousCodePoint(); } +CodePoint CodePointAtLocation(const char * location) { + UTF8Decoder decoder(location); + return decoder.nextCodePoint(); +} + bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c) { assert(location > buffer); if (UTF8Decoder::CharSizeOfCodePoint(c) == 1) { @@ -277,8 +282,7 @@ bool CodePointIs(const char * location, CodePoint c) { if (UTF8Decoder::CharSizeOfCodePoint(c) == 1) { return *(location) == c; } - UTF8Decoder decoder(location); - return decoder.nextCodePoint() == c; + return CodePointAtLocation(location) == c; } bool CodePointIsEndOfWord(CodePoint c) { From 72aedaadd075b1d0cdd253d11d5194b72d7f1ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 18 Mar 2020 10:54:08 +0100 Subject: [PATCH 152/453] [apps/code] VarBox contains current/buitin/imported vars and functions --- apps/code/variable_box_controller.cpp | 178 ++++++++++++++++++++++---- apps/code/variable_box_controller.h | 20 ++- 2 files changed, 164 insertions(+), 34 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c937b4896..09e0d8889 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -13,8 +13,9 @@ namespace Code { VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : NestedMenuController(nullptr, I18n::Message::FunctionsAndVariables), - m_scriptNodesCount(0), - m_scriptStore(scriptStore) + m_scriptStore(scriptStore), + m_currentScriptNodesCount(0), + m_importedNodesCount(0) { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { m_leafCells[i].setScriptStore(scriptStore); @@ -48,28 +49,127 @@ static bool shouldAddObject(const char * name, int maxLength) { } int VariableBoxController::numberOfRows() const { - assert(m_scriptNodesCount <= k_maxScriptNodesCount); - return m_scriptNodesCount; -} - -int VariableBoxController::reusableCellCount(int type) { - assert(type == 0); - return k_maxNumberOfDisplayedRows; + assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_importedNodesCount <= k_maxScriptNodesCount); + return m_currentScriptNodesCount + k_builtinNodesCount + m_importedNodesCount; } void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { - assert(index < m_scriptNodesCount); - assert(m_scriptNodesCount <= k_maxScriptNodesCount); + assert(index >= 0 && index < numberOfRows()); ScriptNodeCell * myCell = static_cast(cell); - myCell->setScriptNode(&m_scriptNodes[index]); -} - -int VariableBoxController::typeAtLocation(int i, int j) { - return 0; + myCell->setScriptNode(scriptNodeAtIndex(index)); } void VariableBoxController::loadFunctionsAndVariables() { - m_scriptNodesCount = 0; + //TODO LEA Prune these + add modules + //TODO LEA load buitins only once + int index = 0; + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_abs), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_all), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_and), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_any), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_as), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ascii), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_assert), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bin), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bool), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_break), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_breakpoint), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytearray), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytes), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_callable), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_chr), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_class), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_classmethod), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_compile), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_complex), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_continue), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_def), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_del), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_delattr), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dict), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dir), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_divmod), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_elif), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_else), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_enumerate), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_eval), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_except), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_exec), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_False), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_filter), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_finally), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_float), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_for), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_format), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_from), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_frozenset), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_getattr), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_global), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_globals), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hasattr), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hash), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_help), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hex), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_id), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_if), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_import), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_in), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_input), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_int), 0); + // m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_is), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_isinstance), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_issubclass), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_iter), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_lambda), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_len), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_list), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_locals), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_map), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_max), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_memoryview), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_min), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_next), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_None), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_nonlocal), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_not), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_object), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_oct), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_open), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_or), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ord), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_pass), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_pow), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_print), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_property), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_raise), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_range), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_repr), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_return), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_reversed), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_round), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_set), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_setattr), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_slice), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sorted), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_staticmethod), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_str), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sum), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_super), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_True), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_try), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_tuple), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_type), 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_vars), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_while), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_with), 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_yield), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_zip), 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR___import__), 0); //TODO LEA alphabetical order? + assert(index == k_builtinNodesCount); + +#if 0 + m_scriptNodesCount = 1; m_scriptStore->scanScriptsForFunctionsAndVariables( this, [](void * context, const char * functionName, int scriptIndex) { @@ -84,6 +184,7 @@ void VariableBoxController::loadFunctionsAndVariables() { } VariableBoxController * cvc = static_cast(context); cvc->addVariableAtIndex(variableName, scriptIndex);}); +#endif } HighlightCell * VariableBoxController::leafCellAtIndex(int index) { @@ -92,12 +193,13 @@ HighlightCell * VariableBoxController::leafCellAtIndex(int index) { } bool VariableBoxController::selectLeaf(int rowIndex) { - assert(rowIndex >= 0 && rowIndex < m_scriptNodesCount); - assert(m_scriptNodesCount <= k_maxScriptNodesCount); + assert(rowIndex >= 0 && rowIndex < numberOfRows()); + assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_importedNodesCount <= k_maxScriptNodesCount); m_selectableTableView.deselectTable(); - ScriptNode selectedScriptNode = m_scriptNodes[rowIndex]; - insertTextInCaller(selectedScriptNode.name()); - if (selectedScriptNode.type() == ScriptNode::Type::Function) { + ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); + insertTextInCaller(selectedScriptNode->name()); + if (selectedScriptNode->type() == ScriptNode::Type::Function) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } Container::activeApp()->dismissModalViewController(); @@ -112,18 +214,38 @@ void VariableBoxController::insertTextInCaller(const char * text) { sender()->handleEventWithText(commandBuffer); } +// TODO LEA remane method (index) void VariableBoxController::addFunctionAtIndex(const char * functionName, int scriptIndex) { - if (m_scriptNodesCount < k_maxScriptNodesCount) { - m_scriptNodes[m_scriptNodesCount] = ScriptNode::FunctionNode(functionName, scriptIndex); - m_scriptNodesCount++; + // TODO LEA check if current script or imported + if (m_currentScriptNodesCount < k_maxScriptNodesCount) { + m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::FunctionNode(functionName, scriptIndex); + m_currentScriptNodesCount++; } } +// TODO LEA remane method (index) +// + factorize with addFunctionAtIndex? void VariableBoxController::addVariableAtIndex(const char * variableName, int scriptIndex) { - if (m_scriptNodesCount < k_maxScriptNodesCount) { - m_scriptNodes[m_scriptNodesCount] = ScriptNode::VariableNode(variableName, scriptIndex); - m_scriptNodesCount++; + // TODO LEA check if current script or imported + if (m_currentScriptNodesCount < k_maxScriptNodesCount) { + m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::VariableNode(variableName, scriptIndex); + m_currentScriptNodesCount++; } } +ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { + assert(index >= 0 && index < numberOfRows()); + assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_importedNodesCount <= k_maxScriptNodesCount); + ScriptNode * node = nullptr; + if (index < m_currentScriptNodesCount) { + node = m_currentScriptNodes + index; + } else if (index < m_currentScriptNodesCount + k_builtinNodesCount) { + node = m_builtinNodes + (index - m_currentScriptNodesCount); + } else { + node = m_importedNodes + (index - m_currentScriptNodesCount - k_builtinNodesCount); + } + return node; +} + } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 79d107f00..ee2cfd3ae 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -18,26 +18,34 @@ public: /* ListViewDataSource */ int numberOfRows() const override; - int reusableCellCount(int type) override; + int reusableCellCount(int type) override { + assert(type == 0); + return k_maxNumberOfDisplayedRows; + } void willDisplayCellForIndex(HighlightCell * cell, int index) override; - int typeAtLocation(int i, int j) override; + int typeAtLocation(int i, int j) override { return 0; } /* VariableBoxController */ void loadFunctionsAndVariables(); private: constexpr static int k_maxScriptObjectNameSize = 100; - constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40 + constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; + constexpr static int k_builtinNodesCount = 61; HighlightCell * leafCellAtIndex(int index) override; HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text); void addFunctionAtIndex(const char * functionName, int scriptIndex); void addVariableAtIndex(const char * variableName, int scriptIndex); - ScriptNode m_scriptNodes[k_maxScriptNodesCount]; - int m_scriptNodesCount; - ScriptStore * m_scriptStore; + ScriptNode * scriptNodeAtIndex(int index); + ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; + ScriptNode m_builtinNodes[k_builtinNodesCount]; + ScriptNode m_importedNodes[k_maxScriptNodesCount]; ScriptNodeCell m_leafCells[k_maxNumberOfDisplayedRows]; + ScriptStore * m_scriptStore; + int m_currentScriptNodesCount; + int m_importedNodesCount; }; } From f883516716c9d0385f305f8a85180a14a507e519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 18 Mar 2020 13:43:04 +0100 Subject: [PATCH 153/453] [apps/code] Editor asks VariableBox for autocompletion --- apps/code/python_text_area.cpp | 9 ++++++--- apps/code/python_text_area.h | 1 + apps/code/variable_box_controller.cpp | 4 ++++ apps/code/variable_box_controller.h | 1 + ion/include/ion/unicode/utf8_helper.h | 4 +++- ion/src/shared/unicode/utf8_helper.cpp | 17 +++++++++++++++++ ion/test/utf8_helper.cpp | 13 +++++++++++++ 7 files changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 54b7eeaf3..92163632d 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -251,9 +251,12 @@ void PythonTextArea::addAutocompletion() { { /* The previous code point is neither the beginning of the text, nor a * space, nor a \n, and the next code point is the end of the word. - * Compute the text to insert */ - // TODO LEA - textToInsert = "test"; + * Compute the text to insert: + * Look first in the current script variables and functions, then in the + * builtins, then in the imported modules/scripts. */ + VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); + const char * beginningOfWord = UTF8Helper::BeginningOfWord(m_contentView.editedText(), autocompletionLocation); + textToInsert = varBox->autocompletionForText(beginningOfWord); } // Try to insert the text (this might fail if the buffer is full) diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 85a6f5ab5..eb36fd99c 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -27,6 +27,7 @@ protected: m_autocomplete(false) { } + App * pythonDelegate() { return m_pythonDelegate; } void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } bool isAutocompleting() const { return m_autocomplete; } void loadSyntaxHighlighter(); diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 09e0d8889..b0649118c 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -187,6 +187,10 @@ void VariableBoxController::loadFunctionsAndVariables() { #endif } +const char * VariableBoxController::autocompletionForText(const char * text) const { + return nullptr; +} + HighlightCell * VariableBoxController::leafCellAtIndex(int index) { assert(index >= 0 && index < k_maxNumberOfDisplayedRows); return &m_leafCells[index]; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index ee2cfd3ae..2ab80b798 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -27,6 +27,7 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(); + const char * autocompletionForText(const char * text) const; private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index 8b20a926f..38878989c 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -84,7 +84,9 @@ size_t GlyphOffsetAtCodePoint(const char * buffer, const char * position); * For instance, strlen("∑") = 3 but StringGlyphLength("∑") = 1 */ size_t StringGlyphLength(const char * s, int maxSize = -1); -// Returns the position of the first char between ' ', '\n' and 0. +// Returns the position of the first previous char ' ', '\n' or text +const char * BeginningOfWord(const char * text, const char * word); +// Returns the position of the first following char ' ', '\n' or 0 const char * EndOfWord(const char * word); }; diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index 7ddc93f7c..6f2d3e41e 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -378,6 +378,23 @@ size_t StringGlyphLength(const char * s, int maxSize) { return glyphIndex; } +const char * BeginningOfWord(const char * text, const char * word) { + if (text == word) { + return text; + } + UTF8Decoder decoder(text, word); + const char * codePointPointer = decoder.stringPosition(); + CodePoint codePoint = decoder.previousCodePoint(); + while (!CodePointIsEndOfWord(codePoint)) { + codePointPointer = decoder.stringPosition(); + if (codePointPointer == text) { + break; + } + codePoint = decoder.previousCodePoint(); + } + return codePointPointer; +} + const char * EndOfWord(const char * word) { UTF8Decoder decoder(word); CodePoint codePoint = decoder.nextCodePoint(); diff --git a/ion/test/utf8_helper.cpp b/ion/test/utf8_helper.cpp index 2179f971f..b96f361d9 100644 --- a/ion/test/utf8_helper.cpp +++ b/ion/test/utf8_helper.cpp @@ -275,6 +275,19 @@ QUIZ_CASE(ion_utf8_helper_string_glyph_length) { } +void assert_beginning_of_word_is(const char * text, const char * word, const char * beginningOfWord) { + quiz_assert(UTF8Helper::BeginningOfWord(text, word) == beginningOfWord); +} + +QUIZ_CASE(ion_utf8_helper_beginning_of_word) { + const char * test_sentence = "01 34+ \n89"; + assert_beginning_of_word_is(test_sentence, test_sentence, test_sentence); + assert_beginning_of_word_is(test_sentence, test_sentence + 1, test_sentence); + assert_beginning_of_word_is(test_sentence, test_sentence + 2, test_sentence); + assert_beginning_of_word_is(test_sentence, test_sentence + 5, test_sentence + 3); + assert_beginning_of_word_is(test_sentence, test_sentence + 8, test_sentence + 8); +} + void assert_end_of_word_is(const char * word, const char * endOfWord) { quiz_assert(UTF8Helper::EndOfWord(word) == endOfWord); } From 321f87ea788409cec848de84555116cdb39feb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 19 Mar 2020 15:53:22 +0100 Subject: [PATCH 154/453] [apps/code] VariableBoxController::autocompletionForText --- apps/code/variable_box_controller.cpp | 14 +++++++++++++- apps/code/variable_box_controller.h | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index b0649118c..8e98ce155 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -187,7 +187,19 @@ void VariableBoxController::loadFunctionsAndVariables() { #endif } -const char * VariableBoxController::autocompletionForText(const char * text) const { +const char * VariableBoxController::autocompletionForText(const char * text) { + // TODO LEA Accelerate + loadFunctionsAndVariables(); + const char * endOfText = UTF8Helper::EndOfWord(text); + const int textLength = endOfText - text; + assert(textLength >= 1); + for (int i = 0; i < numberOfRows(); i++) { + const char * currentName = scriptNodeAtIndex(i)->name(); + if (strncmp(text, currentName, textLength) == 0 && *(currentName + textLength) + != 0) { + return currentName + textLength; + } + } return nullptr; } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 2ab80b798..a898db686 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -27,7 +27,7 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(); - const char * autocompletionForText(const char * text) const; + const char * autocompletionForText(const char * text); private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 From b9693f1f26562ade2ca768753f38e71f16c2f0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 19 Mar 2020 17:22:37 +0100 Subject: [PATCH 155/453] [apps/code] Load variable box with script index argument --- apps/code/app.h | 1 + apps/code/console_controller.cpp | 2 +- apps/code/editor_controller.cpp | 6 ++++-- apps/code/editor_controller.h | 4 +++- apps/code/editor_view.cpp | 4 ++++ apps/code/editor_view.h | 1 + apps/code/menu_controller.cpp | 2 +- apps/code/menu_controller.h | 1 + apps/code/python_text_area.cpp | 15 +++++++++++++-- apps/code/python_text_area.h | 2 ++ apps/code/variable_box_controller.cpp | 6 +++--- apps/code/variable_box_controller.h | 4 ++-- 12 files changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/code/app.h b/apps/code/app.h index 605beb8ea..57ee6181a 100644 --- a/apps/code/app.h +++ b/apps/code/app.h @@ -50,6 +50,7 @@ public: } StackViewController * stackViewController() { return &m_codeStackViewController; } ConsoleController * consoleController() { return &m_consoleController; } + MenuController * menuController() { return &m_menuController; } /* Responder */ bool handleEvent(Ion::Events::Event event) override; diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index cb0f06f23..6c66b51be 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -57,7 +57,7 @@ bool ConsoleController::loadPythonEnvironment() { /* We load functions and variables names in the variable box before running * any other python code to avoid failling to load functions and variables * due to memory exhaustion. */ - App::app()->variableBoxController()->loadFunctionsAndVariables(); + App::app()->variableBoxController()->loadFunctionsAndVariables(-1, nullptr); return true; } diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 863a29191..a03f29406 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -13,13 +13,15 @@ EditorController::EditorController(MenuController * menuController, App * python ViewController(nullptr), m_editorView(this, pythonDelegate), m_script(Ion::Storage::Record()), + m_scriptIndex(-1), m_menuController(menuController) { m_editorView.setTextAreaDelegates(this, this); } -void EditorController::setScript(Script script) { +void EditorController::setScript(Script script, int scriptIndex) { m_script = script; + m_scriptIndex = scriptIndex; /* We edit the script direclty in the storage buffer. We thus put all the * storage available space at the end of the current edited script and we set @@ -122,7 +124,7 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events: VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - varBox->loadFunctionsAndVariables(); + varBox->loadFunctionsAndVariables(m_scriptIndex, m_editorView.textToAutocomplete()); return varBox; } diff --git a/apps/code/editor_controller.h b/apps/code/editor_controller.h index 7fb5d9560..4cd32c1ed 100644 --- a/apps/code/editor_controller.h +++ b/apps/code/editor_controller.h @@ -16,7 +16,8 @@ class App; class EditorController : public ViewController, public TextAreaDelegate, public Shared::InputEventHandlerDelegate { public: EditorController(MenuController * menuController, App * pythonDelegate); - void setScript(Script script); + void setScript(Script script, int scriptIndex); + int scriptIndex() const { return m_scriptIndex; } void willExitApp(); /* ViewController */ @@ -39,6 +40,7 @@ private: StackViewController * stackController(); EditorView m_editorView; Script m_script; + int m_scriptIndex; MenuController * m_menuController; }; diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index cfcbe8113..455e5761e 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -16,6 +16,10 @@ EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) : m_textArea.setScrollViewDelegate(this); } +const char * EditorView::textToAutocomplete() const { + return m_textArea.textToAutocomplete(); +} + void EditorView::resetSelection() { m_textArea.resetSelection(); } diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index bbc608e88..58ec93eff 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -9,6 +9,7 @@ namespace Code { class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); + const char * textToAutocomplete() const; void resetSelection(); void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { m_textArea.setDelegates(inputEventHandlerDelegate, delegate); diff --git a/apps/code/menu_controller.cpp b/apps/code/menu_controller.cpp index e07632993..0857a0499 100644 --- a/apps/code/menu_controller.cpp +++ b/apps/code/menu_controller.cpp @@ -372,7 +372,7 @@ void MenuController::configureScript() { void MenuController::editScriptAtIndex(int scriptIndex) { assert(scriptIndex >=0 && scriptIndex < m_scriptStore->numberOfScripts()); Script script = m_scriptStore->scriptAtIndex(scriptIndex); - m_editorController.setScript(script); + m_editorController.setScript(script, scriptIndex); stackViewController()->push(&m_editorController); } diff --git a/apps/code/menu_controller.h b/apps/code/menu_controller.h index a5fc84638..6d87672ad 100644 --- a/apps/code/menu_controller.h +++ b/apps/code/menu_controller.h @@ -24,6 +24,7 @@ public: void openConsoleWithScript(Script script); void scriptContentEditionDidFinish(); void willExitApp(); + int editedScriptIndex() const { return m_editorController.scriptIndex(); } /* ViewController */ View * view() override { return &m_selectableTableView; } diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 92163632d..5d45bf203 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -53,6 +53,10 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { return lex->column - lex->tok_column; } +const char * PythonTextArea::ContentView::textToAutocomplete() const { + return UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); +} + void PythonTextArea::ContentView::loadSyntaxHighlighter() { m_pythonDelegate->initPythonWithUser(this); } @@ -231,6 +235,13 @@ bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bo return result; } +const char * PythonTextArea::textToAutocomplete() const { + if (!m_contentView.isAutocompleting()) { + return nullptr; + } + return m_contentView.textToAutocomplete(); +} + void PythonTextArea::removeAutocompletion() { assert(m_contentView.isAutocompleting()); const char * autocompleteStart = m_contentView.cursorLocation(); @@ -255,8 +266,8 @@ void PythonTextArea::addAutocompletion() { * Look first in the current script variables and functions, then in the * builtins, then in the imported modules/scripts. */ VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); - const char * beginningOfWord = UTF8Helper::BeginningOfWord(m_contentView.editedText(), autocompletionLocation); - textToInsert = varBox->autocompletionForText(beginningOfWord); + const char * beginningOfWord = m_contentView.textToAutocomplete(); + textToInsert = varBox->autocompletionForText(m_contentView.pythonDelegate()->menuController()->editedScriptIndex(), beginningOfWord); } // Try to insert the text (this might fail if the buffer is full) diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index eb36fd99c..7b0031b9d 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -18,6 +18,7 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; + const char * textToAutocomplete() const; protected: class ContentView : public TextArea::ContentView { public: @@ -30,6 +31,7 @@ protected: App * pythonDelegate() { return m_pythonDelegate; } void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } bool isAutocompleting() const { return m_autocomplete; } + const char * textToAutocomplete() const; void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); void clearRect(KDContext * ctx, KDRect rect) const override; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8e98ce155..4b21a418a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -60,7 +60,7 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in myCell->setScriptNode(scriptNodeAtIndex(index)); } -void VariableBoxController::loadFunctionsAndVariables() { +void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete) { //TODO LEA Prune these + add modules //TODO LEA load buitins only once int index = 0; @@ -187,9 +187,9 @@ void VariableBoxController::loadFunctionsAndVariables() { #endif } -const char * VariableBoxController::autocompletionForText(const char * text) { +const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text) { // TODO LEA Accelerate - loadFunctionsAndVariables(); + loadFunctionsAndVariables(scriptIndex, text); const char * endOfText = UTF8Helper::EndOfWord(text); const int textLength = endOfText - text; assert(textLength >= 1); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index a898db686..f0e69448c 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -26,8 +26,8 @@ public: int typeAtLocation(int i, int j) override { return 0; } /* VariableBoxController */ - void loadFunctionsAndVariables(); - const char * autocompletionForText(const char * text); + void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete); + const char * autocompletionForText(int scriptIndex, const char * text); private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 From 7f486d790fea3e46b5f7723734b5893998edc74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Mar 2020 14:45:29 +0100 Subject: [PATCH 156/453] [apps/code] Get current script variables and functions --- apps/code/script_node.h | 17 +- apps/code/script_node_cell.cpp | 6 +- apps/code/variable_box_controller.cpp | 371 ++++++++++++++++++-------- apps/code/variable_box_controller.h | 6 +- apps/math_toolbox.cpp | 2 +- apps/shared/toolbox_helpers.cpp | 7 +- apps/shared/toolbox_helpers.h | 2 +- kandinsky/include/kandinsky/font.h | 4 +- 8 files changed, 281 insertions(+), 134 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 1bac0f81d..36eaec7de 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -1,6 +1,7 @@ #ifndef CODE_SCRIPT_NODE_H #define CODE_SCRIPT_NODE_H +#include #include namespace Code { @@ -12,22 +13,24 @@ public: Variable = 1 }; ScriptNode() : - m_type(Type::Function), m_name(nullptr), m_scriptIndex(0) {} - static ScriptNode FunctionNode(const char * name, uint16_t scriptIndex) { - return ScriptNode(Type::Function, name, scriptIndex); + m_type(Type::Function), m_name(nullptr), m_scriptIndex(0), m_nameLength(0) {} + static ScriptNode FunctionNode(const char * name, int nameLength, uint16_t scriptIndex) { + return ScriptNode(Type::Function, name, scriptIndex, nameLength); } - static ScriptNode VariableNode(const char * name, uint16_t scriptIndex) { - return ScriptNode(Type::Variable, name, scriptIndex); + static ScriptNode VariableNode(const char * name, int nameLength, uint16_t scriptIndex) { + return ScriptNode(Type::Variable, name, scriptIndex, nameLength); } Type type() const { return m_type; } const char * name() const { return m_name; } + int nameLength() const { return m_nameLength; } uint16_t scriptIndex() const { return m_scriptIndex; } private: - ScriptNode(Type type, const char * name, uint16_t scriptIndex) : - m_type(type), m_name(name), m_scriptIndex(scriptIndex) {} + ScriptNode(Type type, const char * name, uint16_t scriptIndex, int nameLength) : + m_type(type), m_name(name), m_scriptIndex(scriptIndex), m_nameLength(nameLength) {} Type m_type; const char * m_name; uint16_t m_scriptIndex; + int m_nameLength; }; } diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index 3fda4c1eb..faeadc806 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -23,8 +23,8 @@ void ScriptNodeCell::ScriptNodeView::setScriptStore(ScriptStore * scriptStore) { } void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { - ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite); - KDSize nameSize = k_font->stringSize(m_scriptNode->name()); + ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite, m_scriptNode->nameLength()); + KDSize nameSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); if (m_scriptNode->type() == ScriptNode::Type::Function) { ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite); } @@ -35,7 +35,7 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { if (m_scriptNode->name() == nullptr) { return KDSizeZero; } - KDSize size1 = k_font->stringSize(m_scriptNode->name()); + KDSize size1 = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); KDSize size2 = k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName()); KDSize size3 = KDSizeZero; if (m_scriptNode->type() == ScriptNode::Type::Function) { diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 4b21a418a..660d7ea7a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -9,6 +9,12 @@ #include #include +extern "C" { +#include "py/lexer.h" +#include "py/nlr.h" +} + + namespace Code { VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : @@ -60,115 +66,251 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in myCell->setScriptNode(scriptNodeAtIndex(index)); } + +/*TODO LEA very dirty + * This is done to get the lexer position during lexing. As the _mp_reader_mem_t + * struct is private and declared in python/src/py/reader.c, we copy-paste it + * here to be able to use it. */ +typedef struct _mp_reader_mem_t { + size_t free_len; // if >0 mem is freed on close by: m_free(beg, free_len) + const byte *beg; + const byte *cur; + const byte *end; +} mp_reader_mem_t; +/* TODO end*/ + void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete) { //TODO LEA Prune these + add modules - //TODO LEA load buitins only once + //TODO LEA Load according to textToAutocomplete int index = 0; - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_abs), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_all), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_and), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_any), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_as), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ascii), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_assert), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bin), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bool), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_break), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_breakpoint), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytearray), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytes), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_callable), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_chr), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_class), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_classmethod), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_compile), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_complex), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_continue), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_def), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_del), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_delattr), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dict), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dir), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_divmod), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_elif), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_else), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_enumerate), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_eval), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_except), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_exec), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_False), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_filter), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_finally), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_float), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_for), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_format), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_from), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_frozenset), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_getattr), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_global), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_globals), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hasattr), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hash), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_help), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hex), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_id), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_if), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_import), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_in), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_input), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_int), 0); - // m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_is), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_isinstance), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_issubclass), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_iter), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_lambda), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_len), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_list), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_locals), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_map), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_max), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_memoryview), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_min), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_next), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_None), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_nonlocal), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_not), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_object), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_oct), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_open), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_or), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ord), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_pass), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_pow), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_print), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_property), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_raise), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_range), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_repr), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_return), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_reversed), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_round), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_set), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_setattr), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_slice), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sorted), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_staticmethod), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_str), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sum), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_super), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_True), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_try), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_tuple), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_type), 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_vars), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_while), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_with), 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_yield), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_zip), 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR___import__), 0); //TODO LEA alphabetical order? + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_abs), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_all), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_and), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_any), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_as), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ascii), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_assert), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bin), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bool), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_break), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_breakpoint), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytearray), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytes), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_callable), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_chr), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_class), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_classmethod), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_compile), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_complex), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_continue), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_def), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_del), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_delattr), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dict), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dir), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_divmod), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_elif), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_else), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_enumerate), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_eval), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_except), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_exec), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_False), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_filter), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_finally), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_float), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_for), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_format), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_from), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_frozenset), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_getattr), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_global), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_globals), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hasattr), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hash), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_help), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hex), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_id), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_if), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_import), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_in), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_input), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_int), -1, 0); + // m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_is), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_isinstance), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_issubclass), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_iter), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_lambda), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_len), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_list), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_locals), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_map), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_max), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_memoryview), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_min), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_next), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_None), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_nonlocal), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_not), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_object), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_oct), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_open), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_or), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ord), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_pass), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_pow), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_print), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_property), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_raise), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_range), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_repr), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_return), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_reversed), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_round), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_set), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_setattr), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_slice), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sorted), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_staticmethod), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_str), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sum), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_super), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_True), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_try), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_tuple), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_type), -1, 0); + //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_vars), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_while), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_with), -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_yield), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_zip), -1, 0); + m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR___import__), -1, 0); //TODO LEA alphabetical order? assert(index == k_builtinNodesCount); -#if 0 + + // Load the imported variables and functions + //TODO LEA + +#if 1 + if (scriptIndex < 0) { + //TODO LEA + return; + } + const char * script = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); + + /* To find variable and funtion names: + * 1) We lex the script + * 2) We detect patterns on a line per line basis, a line being ended by '\n' + * or by ';', but continued by '\'. */ + +#if 1 + m_currentScriptNodesCount = 0; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + + // 1) Lex the script + _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, script, strlen(script), false); + bool defToken = false; + + // This is a trick to get the token position in the text. + const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + + while (lex->tok_kind != MP_TOKEN_END) { + /* 2) Detect MP_TOKEN_NAME that are not in the builtins. Keep track of DEF + * tokens to differentiate between variables and functions. */ + if (lex->tok_kind == MP_TOKEN_NAME) { + const char * name = lex->vstr.buf; + int nameLength = lex->vstr.len; + // Check if this token is already int the var box + bool alreadyInVarBox = false; + + // TODO Look also in imported nodes + //TODO LEA speed this up with alphabetical search + for (int i = 0; i < k_builtinNodesCount; i++) { + const char * nodeName = m_builtinNodes[i].name(); + int nodeNameLength = m_builtinNodes[i].nameLength(); + if ((nodeNameLength < 0 || nodeNameLength == nameLength) && strncmp(nodeName, name, nameLength) == 0) { + alreadyInVarBox = true; + break; + } + } + + if (!alreadyInVarBox) { + tokenInText -= 2; + if (defToken) { + addFunctionAtIndex(tokenInText, nameLength, scriptIndex); + } else { + addVariableAtIndex(tokenInText, nameLength, scriptIndex); + } + } + } + defToken = lex->tok_kind == MP_TOKEN_KW_DEF; + + /* This is a trick to get the token position in the text. The -1 and -2 + * were found from stepping in the code and trying. */ + tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + if (lex->tok_kind <= MP_TOKEN_ELLIPSIS || lex->tok_kind >= MP_TOKEN_OP_PLUS) { + tokenInText--; + } + + mp_lexer_to_next(lex); + } + + mp_lexer_free(lex); + nlr_pop(); + } + +#else + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // 1) Lex the script + _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, script0, strlen(script0), false); + while (lex->tok_kind != MP_TOKEN_END) { + // 2) Detect patterns on a line per line basis + while (lex->tok_kind == MP_TOKEN_INDENT || lex->tok_kind == MP_TOKEN_DEDENT) { + mp_lexer_to_next(lex); + } + if (lex->tok_kind == MP_TOKEN_NAME) { + // Look for variable definition "name =" + const char * name = lex->vstr.buf; + size_t len = lex->vstr.len; + mp_lexer_to_next(lex); + if (lex->tok_kind == MP_TOKEN_DEL_EQUAL) { + addVariableAtIndex(name, len, 0); + } + } else if (lex->tok_kind != MP_TOKEN_KW_DEF) { + // Look for function definition "def name1(name2, name3 = ...):" + mp_lexer_to_next(lex); + if (lex->tok_kind == MP_TOKEN_NAME) { + const char * name = lex->vstr.buf; + size_t len = lex->vstr.len; + addFunctionAtIndex(name, len, 0); + mp_lexer_to_next(lex); + if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN) { + + } + MP_TOKEN_DEL_PAREN_CLOSE, + } + + + } + + // Forward until the end of the line + while (lex->tok_kind != MP_TOKEN_END + && lex->tok_kind != MP_TOKEN_DEL_SEMICOLON + && lex->tok_kind != MP_TOKEN_NEWLINE) + { + mp_lexer_to_next(lex); + } + if (lex->tok_kind != MP_TOKEN_END) { + mp_lexer_to_next(lex); + } + } + mp_lexer_free(lex); + nlr_pop(); + } +#endif +#else m_scriptNodesCount = 1; m_scriptStore->scanScriptsForFunctionsAndVariables( this, @@ -194,9 +336,10 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const const int textLength = endOfText - text; assert(textLength >= 1); for (int i = 0; i < numberOfRows(); i++) { - const char * currentName = scriptNodeAtIndex(i)->name(); - if (strncmp(text, currentName, textLength) == 0 && *(currentName + textLength) - != 0) { + ScriptNode * node = scriptNodeAtIndex(i); + const char * currentName = node->name(); + int currentNameLength = node->nameLength(); + if ((currentNameLength < 0 || currentNameLength != textLength) && strncmp(text, currentName, textLength) == 0) { return currentName + textLength; } } @@ -214,7 +357,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { assert(m_importedNodesCount <= k_maxScriptNodesCount); m_selectableTableView.deselectTable(); ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); - insertTextInCaller(selectedScriptNode->name()); + insertTextInCaller(selectedScriptNode->name(), selectedScriptNode->nameLength()); if (selectedScriptNode->type() == ScriptNode::Type::Function) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } @@ -222,29 +365,29 @@ bool VariableBoxController::selectLeaf(int rowIndex) { return true; } -void VariableBoxController::insertTextInCaller(const char * text) { +void VariableBoxController::insertTextInCaller(const char * text, int textLength) { int commandBufferMaxSize = strlen(text)+1; char commandBuffer[k_maxScriptObjectNameSize]; assert(commandBufferMaxSize <= k_maxScriptObjectNameSize); - Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer, commandBufferMaxSize, true); + Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLength, commandBuffer, commandBufferMaxSize, true); sender()->handleEventWithText(commandBuffer); } // TODO LEA remane method (index) -void VariableBoxController::addFunctionAtIndex(const char * functionName, int scriptIndex) { +void VariableBoxController::addFunctionAtIndex(const char * functionName, int nameLength, int scriptIndex) { // TODO LEA check if current script or imported if (m_currentScriptNodesCount < k_maxScriptNodesCount) { - m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::FunctionNode(functionName, scriptIndex); + m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::FunctionNode(functionName, nameLength, scriptIndex); m_currentScriptNodesCount++; } } // TODO LEA remane method (index) // + factorize with addFunctionAtIndex? -void VariableBoxController::addVariableAtIndex(const char * variableName, int scriptIndex) { +void VariableBoxController::addVariableAtIndex(const char * variableName, int nameLength, int scriptIndex) { // TODO LEA check if current script or imported if (m_currentScriptNodesCount < k_maxScriptNodesCount) { - m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::VariableNode(variableName, scriptIndex); + m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::VariableNode(variableName, nameLength, scriptIndex); m_currentScriptNodesCount++; } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index f0e69448c..14925510c 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -36,9 +36,9 @@ private: HighlightCell * leafCellAtIndex(int index) override; HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } bool selectLeaf(int rowIndex) override; - void insertTextInCaller(const char * text); - void addFunctionAtIndex(const char * functionName, int scriptIndex); - void addVariableAtIndex(const char * variableName, int scriptIndex); + void insertTextInCaller(const char * text, int textLength = -1); + void addFunctionAtIndex(const char * functionName, int nameLength, int scriptIndex); + void addVariableAtIndex(const char * variableName, int nameLength, int scriptIndex); ScriptNode * scriptNodeAtIndex(int index); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_builtinNodesCount]; diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 166ab1c2d..53c77e3c3 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -310,7 +310,7 @@ bool MathToolbox::selectLeaf(int selectedRow) { // Remove the arguments if we kept one message for both inserted and displayed message int maxTextToInsertLength = strlen(text) + 1; assert(maxTextToInsertLength <= k_maxMessageSize); - Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength, true); + Shared::ToolboxHelpers::TextToInsertForCommandText(text, -1, textToInsert, maxTextToInsertLength, true); text = textToInsert; } sender()->handleEventWithText(text); diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 589615b89..5cf13ce2a 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -29,10 +29,10 @@ int CursorIndexInCommandText(const char * text) { } void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) { - TextToInsertForCommandText(I18n::translate(message), buffer, bufferSize, replaceArgsWithEmptyChar); + TextToInsertForCommandText(I18n::translate(message), -1, buffer, bufferSize, replaceArgsWithEmptyChar); } -void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) { +void TextToInsertForCommandText(const char * command, int commandLength, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) { int index = 0; int numberOfOpenParentheses = 0; int numberOfOpenBrackets = 0; @@ -41,7 +41,7 @@ void TextToInsertForCommandText(const char * command, char * buffer, int bufferS UTF8Decoder decoder(command); CodePoint codePoint = decoder.nextCodePoint(); - while (codePoint != UCodePointNull) { + while (codePoint != UCodePointNull && (commandLength < 0 || (decoder.stringPosition() - command <= commandLength))) { if (codePoint == ')') { numberOfOpenParentheses--; } else if (codePoint == ']') { @@ -75,6 +75,7 @@ void TextToInsertForCommandText(const char * command, char * buffer, int bufferS } codePoint = decoder.nextCodePoint(); } + assert(index < bufferSize); buffer[index] = 0; } diff --git a/apps/shared/toolbox_helpers.h b/apps/shared/toolbox_helpers.h index 16233ffe6..5c63a9560 100644 --- a/apps/shared/toolbox_helpers.h +++ b/apps/shared/toolbox_helpers.h @@ -14,7 +14,7 @@ int CursorIndexInCommandText(const char * text); void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar = false); -void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar = false); +void TextToInsertForCommandText(const char * command, int commandLength, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar = false); /* Removes the arguments from a command: * - Removes text between parentheses or brackets, except commas */ diff --git a/kandinsky/include/kandinsky/font.h b/kandinsky/include/kandinsky/font.h index 4765584dd..68905120b 100644 --- a/kandinsky/include/kandinsky/font.h +++ b/kandinsky/include/kandinsky/font.h @@ -33,8 +33,8 @@ public: static constexpr const KDFont * LargeFont = &privateLargeFont; static constexpr const KDFont * SmallFont = &privateSmallFont; - KDSize stringSize(const char * text) const { - return stringSizeUntil(text, nullptr); + KDSize stringSize(const char * text, int textLength = -1) const { + return stringSizeUntil(text, textLength < 0 ? nullptr : text + textLength); } KDSize stringSizeUntil(const char * text, const char * limit) const; From 12bb77cd9f998e64b352895ea49b3953d48b97f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Mar 2020 17:16:28 +0100 Subject: [PATCH 157/453] [apps/code] Do not import the same current variable twice --- apps/code/variable_box_controller.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 660d7ea7a..ce569135e 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -225,10 +225,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha bool alreadyInVarBox = false; // TODO Look also in imported nodes - //TODO LEA speed this up with alphabetical search - for (int i = 0; i < k_builtinNodesCount; i++) { - const char * nodeName = m_builtinNodes[i].name(); - int nodeNameLength = m_builtinNodes[i].nameLength(); + // TODO LEA speed this up with alphabetical search + // TODO LEA use numberOfRows() and scriptNodeAtIndex ? + for (int i = 0; i < k_builtinNodesCount + m_currentScriptNodesCount; i++) { + ScriptNode * matchingNode = i < k_builtinNodesCount ? &m_builtinNodes[i] : &m_currentScriptNodes[i - k_builtinNodesCount]; + const char * nodeName = matchingNode->name(); + int nodeNameLength = matchingNode->nameLength(); if ((nodeNameLength < 0 || nodeNameLength == nameLength) && strncmp(nodeName, name, nameLength) == 0) { alreadyInVarBox = true; break; From eeb42f2544c5caa5bb36dc684a033c444a8ea1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 24 Mar 2020 18:03:46 +0100 Subject: [PATCH 158/453] [apps/code] autocompletionText uses the right text length Before, there was no notion that the autocompleted text might not be a null terminated string. --- apps/code/python_text_area.cpp | 5 +++-- apps/code/variable_box_controller.cpp | 3 ++- apps/code/variable_box_controller.h | 2 +- escher/include/escher/text_area.h | 2 +- escher/include/escher/text_field.h | 2 +- escher/include/escher/text_input.h | 2 +- escher/src/text_area.cpp | 23 ++++++++--------------- escher/src/text_field.cpp | 12 ++++++------ ion/include/ion/unicode/utf8_helper.h | 4 ++-- ion/src/shared/unicode/utf8_helper.cpp | 11 ++++++----- 10 files changed, 31 insertions(+), 35 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 5d45bf203..1ac729dd1 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -256,6 +256,7 @@ void PythonTextArea::addAutocompletion() { const char * autocompletionLocation = const_cast(cursorLocation()); const char * textToInsert = nullptr; + int textToInsertLength = 0; CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), autocompletionLocation); if (!UTF8Helper::CodePointIsEndOfWord(prevCodePoint) && UTF8Helper::CodePointIsEndOfWord(UTF8Helper::CodePointAtLocation(autocompletionLocation))) @@ -267,11 +268,11 @@ void PythonTextArea::addAutocompletion() { * builtins, then in the imported modules/scripts. */ VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); const char * beginningOfWord = m_contentView.textToAutocomplete(); - textToInsert = varBox->autocompletionForText(m_contentView.pythonDelegate()->menuController()->editedScriptIndex(), beginningOfWord); + textToInsert = varBox->autocompletionForText(m_contentView.pythonDelegate()->menuController()->editedScriptIndex(), beginningOfWord, &textToInsertLength); } // Try to insert the text (this might fail if the buffer is full) - if (textToInsert && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation))) { + if (textToInsert && textToInsertLength > 0 && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) { m_contentView.setAutocompleting(true); } } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index ce569135e..da723264b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -331,7 +331,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha #endif } -const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text) { +const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength) { // TODO LEA Accelerate loadFunctionsAndVariables(scriptIndex, text); const char * endOfText = UTF8Helper::EndOfWord(text); @@ -342,6 +342,7 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const const char * currentName = node->name(); int currentNameLength = node->nameLength(); if ((currentNameLength < 0 || currentNameLength != textLength) && strncmp(text, currentName, textLength) == 0) { + *textToInsertLength = currentNameLength - textLength; return currentName + textLength; } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 14925510c..aa436dbb5 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -27,7 +27,7 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete); - const char * autocompletionForText(int scriptIndex, const char * text); + const char * autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength); private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 diff --git a/escher/include/escher/text_area.h b/escher/include/escher/text_area.h index 7d7e58716..41c177a41 100644 --- a/escher/include/escher/text_area.h +++ b/escher/include/escher/text_area.h @@ -117,7 +117,7 @@ protected: const char * editedText() const override { return m_text.text(); } size_t editedTextLength() const override { return m_text.textLength(); } const Text * getText() const { return &m_text; } - bool insertTextAtLocation(const char * text, char * location) override; + bool insertTextAtLocation(const char * text, char * location, int textLength = -1) override; void moveCursorGeo(int deltaX, int deltaY); bool removePreviousGlyph() override; bool removeEndOfLine() override; diff --git a/escher/include/escher/text_field.h b/escher/include/escher/text_field.h index af995328c..b7394f2b5 100644 --- a/escher/include/escher/text_field.h +++ b/escher/include/escher/text_field.h @@ -74,7 +74,7 @@ protected: /* If the text to be appended is too long to be added without overflowing the * buffer, nothing is done (not even adding few letters from the text to reach * the maximum buffer capacity) and false is returned. */ - bool insertTextAtLocation(const char * text, char * location) override; + bool insertTextAtLocation(const char * text, char * location, int textLength = -1) override; KDSize minimalSizeForOptimalDisplay() const override; bool removePreviousGlyph() override; bool removeEndOfLine() override; diff --git a/escher/include/escher/text_input.h b/escher/include/escher/text_input.h index 82bb60106..34c75dcd8 100644 --- a/escher/include/escher/text_input.h +++ b/escher/include/escher/text_input.h @@ -49,7 +49,7 @@ protected: // Virtual text get/add/remove virtual const char * text() const = 0; - virtual bool insertTextAtLocation(const char * text, char * location) = 0; + virtual bool insertTextAtLocation(const char * text, char * location, int textLength = -1) = 0; virtual bool removePreviousGlyph() = 0; virtual bool removeEndOfLine() = 0; diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index 11dfc4045..8d4239df8 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -458,26 +458,19 @@ void TextArea::ContentView::setText(char * textBuffer, size_t textBufferSize) { m_cursorLocation = text(); } -bool TextArea::ContentView::insertTextAtLocation(const char * text, char * location) { - int textSize = strlen(text); - if (m_text.textLength() + textSize >= m_text.bufferSize() || textSize == 0) { +bool TextArea::ContentView::insertTextAtLocation(const char * text, char * location, int textLength) { + int textLen = textLength < 0 ? strlen(text) : textLength; + assert(textLen < 0 || textLen <= strlen(text)); + if (m_text.textLength() + textLen >= m_text.bufferSize() || textLen == 0) { return false; } - bool lineBreak = false; - // Scan for \n and 0 - const char * nullLocation = UTF8Helper::PerformAtCodePoints( - text, '\n', - [](int codePointOffset, void * lineBreak, int context1, int context2) { - *((bool *)lineBreak) = true; - }, - [](int c1, void * c2, int c3, int c4) { }, - &lineBreak, 0); + // Scan for \n + bool lineBreak = UTF8Helper::HasCodePoint(text, '\n', text + textLen); - assert(UTF8Helper::CodePointIs(nullLocation, 0)); - m_text.insertText(text, nullLocation - text, location); + m_text.insertText(text, textLen, location); // Replace System parentheses (used to keep layout tree structure) by normal parentheses - Poincare::SerializationHelper::ReplaceSystemParenthesesByUserParentheses(location, nullLocation - text); + Poincare::SerializationHelper::ReplaceSystemParenthesesByUserParentheses(location, textLen); reloadRectFromPosition(location, lineBreak); return true; } diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index bbabf8756..ebd9bd48a 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -119,10 +119,10 @@ void TextField::ContentView::reinitDraftTextBuffer() { setCursorLocation(s_draftTextBuffer); } -bool TextField::ContentView::insertTextAtLocation(const char * text, char * location) { +bool TextField::ContentView::insertTextAtLocation(const char * text, char * location, int textLen) { assert(m_isEditing); - int textLength = strlen(text); + int textLength = textLen < 0 ? strlen(text) : textLen; if (m_currentDraftTextLength + textLength >= m_draftTextBufferSize || textLength == 0) { return false; } @@ -130,12 +130,12 @@ bool TextField::ContentView::insertTextAtLocation(const char * text, char * loca memmove(location + textLength, location, (s_draftTextBuffer + m_currentDraftTextLength + 1) - location); // Caution! One byte will be overridden by the null-terminating char of strlcpy - char * overridenByteLocation = location + textLength; + size_t copySize = std::min(textLength, (s_draftTextBuffer + m_draftTextBufferSize) - location); + char * overridenByteLocation = location + copySize; char overridenByte = *overridenByteLocation; - strlcpy(location, text, (s_draftTextBuffer + m_draftTextBufferSize) - location); - assert(overridenByteLocation < s_draftTextBuffer + m_draftTextBufferSize); + strlcpy(location, text, copySize); *overridenByteLocation = overridenByte; - m_currentDraftTextLength += textLength; + m_currentDraftTextLength += copySize; reloadRectFromPosition(m_horizontalAlignment == 0.0f ? location : s_draftTextBuffer); return true; diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index 38878989c..17ff9385f 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -11,10 +11,10 @@ int CountOccurrences(const char * s, CodePoint c); /* Returns the first occurence of a code point in a string, the position of the * null terminating char otherwise. */ -const char * CodePointSearch(const char * s, CodePoint c); +const char * CodePointSearch(const char * s, CodePoint c, const char * stoppingPosition = nullptr); // Returns true if the text had the code point -bool HasCodePoint(const char * s, CodePoint c); +bool HasCodePoint(const char * s, CodePoint c, const char * stoppingPosition = nullptr); /* Returns the first occurence of a code point that is not c in a string, * stopping at the null-terminating char or the start of string. */ diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index 6f2d3e41e..d15c897c6 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -33,10 +33,10 @@ int CountOccurrences(const char * s, CodePoint c) { return count; } -const char * CodePointSearch(const char * s, CodePoint c) { +const char * CodePointSearch(const char * s, CodePoint c, const char * stoppingPosition) { if (UTF8Decoder::CharSizeOfCodePoint(c) == 1) { const char * result = s; - while (*result != 0 && *result != c) { + while (*result != 0 && *result != c && (stoppingPosition == nullptr || result != stoppingPosition)) { result++; } return result; @@ -45,7 +45,7 @@ const char * CodePointSearch(const char * s, CodePoint c) { const char * currentPointer = s; CodePoint codePoint = decoder.nextCodePoint(); const char * nextPointer = decoder.stringPosition(); - while (codePoint != UCodePointNull && codePoint != c) { + while (codePoint != UCodePointNull && codePoint != c && (stoppingPosition == nullptr || currentPointer < stoppingPosition)) { currentPointer = nextPointer; codePoint = decoder.nextCodePoint(); nextPointer = decoder.stringPosition(); @@ -53,9 +53,10 @@ const char * CodePointSearch(const char * s, CodePoint c) { return currentPointer; } -bool HasCodePoint(const char * s, CodePoint c) { +bool HasCodePoint(const char * s, CodePoint c, const char * stoppingPosition) { assert(c != 0); - return *CodePointSearch(s, c) != 0; + const char * resultPosition = CodePointSearch(s, c, stoppingPosition); + return *resultPosition != 0 && (stoppingPosition == nullptr || resultPosition < stoppingPosition); } const char * NotCodePointSearch(const char * s, CodePoint c, bool goingLeft, const char * initialPosition) { From 0f02a61dc464a9b703e356bdb19698208abd5cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 25 Mar 2020 16:21:59 +0100 Subject: [PATCH 159/453] [apps/code] Use textLength in VarBoxController::insertTextInCaller --- apps/code/variable_box_controller.cpp | 9 +++++---- apps/shared/toolbox_helpers.cpp | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index da723264b..bb1d59410 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -14,9 +14,10 @@ extern "C" { #include "py/nlr.h" } - namespace Code { +static inline int minInt(int x, int y) { return x < y ? x : y; } + VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : NestedMenuController(nullptr, I18n::Message::FunctionsAndVariables), m_scriptStore(scriptStore), @@ -369,10 +370,10 @@ bool VariableBoxController::selectLeaf(int rowIndex) { } void VariableBoxController::insertTextInCaller(const char * text, int textLength) { - int commandBufferMaxSize = strlen(text)+1; + int textLen = textLength < 0 ? strlen(text) : textLength; + int commandBufferMaxSize = minInt(k_maxScriptObjectNameSize, textLen + 1); char commandBuffer[k_maxScriptObjectNameSize]; - assert(commandBufferMaxSize <= k_maxScriptObjectNameSize); - Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLength, commandBuffer, commandBufferMaxSize, true); + Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLen, commandBuffer, commandBufferMaxSize, true); sender()->handleEventWithText(commandBuffer); } diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 5cf13ce2a..8758ca763 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -62,6 +62,7 @@ void TextToInsertForCommandText(const char * command, int commandLength, char * index += UTF8Decoder::CodePointToChars(codePoint, buffer + index, bufferSize - index); } else { if (replaceArgsWithEmptyChar && !argumentAlreadyReplaced) { + assert(index < bufferSize); index += UTF8Decoder::CodePointToChars(UCodePointEmpty, buffer + index, bufferSize - index); argumentAlreadyReplaced = true; } From eec92d51fcf5ac82d2d60ed0ed757adaaea677ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 25 Mar 2020 17:05:11 +0100 Subject: [PATCH 160/453] [apps/code] Fix VariableBoxController::autocompletionForText --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index bb1d59410..01f5fe9dc 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -343,7 +343,7 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const const char * currentName = node->name(); int currentNameLength = node->nameLength(); if ((currentNameLength < 0 || currentNameLength != textLength) && strncmp(text, currentName, textLength) == 0) { - *textToInsertLength = currentNameLength - textLength; + *textToInsertLength = (currentNameLength < 0 ? strlen(currentName) : currentNameLength) - textLength; return currentName + textLength; } } From c273f734fe9479dd9744fc08d1d6054951982d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 25 Mar 2020 17:05:31 +0100 Subject: [PATCH 161/453] [apps/code] Add some buitin vars in the varbox --- apps/code/variable_box_controller.cpp | 10 ++++++---- apps/code/variable_box_controller.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 01f5fe9dc..d3f036831 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -80,6 +80,8 @@ typedef struct _mp_reader_mem_t { } mp_reader_mem_t; /* TODO end*/ +// TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] +// from python/lexer.c void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete) { //TODO LEA Prune these + add modules //TODO LEA Load according to textToAutocomplete @@ -104,13 +106,13 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_compile), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_complex), -1, 0); //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_continue), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_def), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_del), -1, 0); + m_builtinNodes[index++] = ScriptNode::VariableNode("def", -1, 0); + //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR___del__), -1, 0); //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_delattr), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dict), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dir), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_divmod), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_elif), -1, 0); + m_builtinNodes[index++] = ScriptNode::VariableNode("elif", -1, 0); //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_else), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_enumerate), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_eval), -1, 0); @@ -122,7 +124,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_float), -1, 0); //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_for), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_format), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_from), -1, 0); + m_builtinNodes[index++] = ScriptNode::VariableNode("from", -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_frozenset), -1, 0); m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_getattr), -1, 0); //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_global), -1, 0); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index aa436dbb5..3c77772e9 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -32,7 +32,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; - constexpr static int k_builtinNodesCount = 61; + constexpr static int k_builtinNodesCount = 64; HighlightCell * leafCellAtIndex(int index) override; HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } bool selectLeaf(int rowIndex) override; From 5d4a3f8726c421cfd3f8b25403c74b3b01da876c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 11:19:54 +0100 Subject: [PATCH 162/453] [apps/code] Add variables in alphabetical order in the var box --- apps/code/variable_box_controller.cpp | 73 ++++++++++++++++++++------- apps/code/variable_box_controller.h | 19 ++++++- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d3f036831..20ae11258 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -242,11 +242,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha if (!alreadyInVarBox) { tokenInText -= 2; - if (defToken) { - addFunctionAtIndex(tokenInText, nameLength, scriptIndex); - } else { - addVariableAtIndex(tokenInText, nameLength, scriptIndex); - } + addNode(defToken ? NodeType::Function : NodeType::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } defToken = lex->tok_kind == MP_TOKEN_KW_DEF; @@ -379,23 +375,50 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength sender()->handleEventWithText(commandBuffer); } -// TODO LEA remane method (index) -void VariableBoxController::addFunctionAtIndex(const char * functionName, int nameLength, int scriptIndex) { - // TODO LEA check if current script or imported - if (m_currentScriptNodesCount < k_maxScriptNodesCount) { - m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::FunctionNode(functionName, nameLength, scriptIndex); - m_currentScriptNodesCount++; +void VariableBoxController::addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { + assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); + int * currentNodeCount = nodesCountForOrigin(origin); + if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { + // There is no room to add another node + return; } + /* We want to insert the node in alphabetical order, so we look for the + * insertion index. */ + ScriptNode * nodes = origin == NodeOrigin::CurrentScript ? m_currentScriptNodes : m_importedNodes; + int insertionIndex = 0; + while (insertionIndex < *currentNodeCount) { + ScriptNode * node = nodes + insertionIndex; + int nameComparison = NodeNameCompare(node, name, nameLength); + assert(nameComparison != 0); // We already checked that the name is not present already + if (nameComparison > 0) { + break; + } + insertionIndex++; + } + + // Shift all the following nodes + for (int i = *currentNodeCount; i >= insertionIndex; i--) { + nodes[i+1] = nodes[i]; + } + // Add the node + nodes[insertionIndex] = type == NodeType::Variable ? + ScriptNode::VariableNode(name, nameLength, scriptIndex) : + ScriptNode::FunctionNode(name, nameLength, scriptIndex); + // Increase the node count + *currentNodeCount = *currentNodeCount + 1; } -// TODO LEA remane method (index) -// + factorize with addFunctionAtIndex? -void VariableBoxController::addVariableAtIndex(const char * variableName, int nameLength, int scriptIndex) { - // TODO LEA check if current script or imported - if (m_currentScriptNodesCount < k_maxScriptNodesCount) { - m_currentScriptNodes[m_currentScriptNodesCount] = ScriptNode::VariableNode(variableName, nameLength, scriptIndex); - m_currentScriptNodesCount++; +int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { + assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); + return k_maxScriptNodesCount; +} + +int * VariableBoxController::nodesCountForOrigin(NodeOrigin origin) { + if (origin == NodeOrigin::CurrentScript) { + return &m_currentScriptNodesCount; } + assert(origin == NodeOrigin::Importation); + return &m_importedNodesCount; } ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { @@ -413,4 +436,18 @@ ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { return node; } +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength) { + const char * nodeName = node->name(); + const int nodeNameLength = node->nameLength(); + const int comparisonLength = minInt(nameLength, nodeNameLength); + int result = strncmp(nodeName, name, comparisonLength); + if (result != 0) { + return result; + } + if (nodeNameLength == nameLength) { + return 0; + } + return comparisonLength == nodeNameLength ? -1 : 1; +} + } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 3c77772e9..aba71799b 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -37,8 +37,23 @@ private: HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); - void addFunctionAtIndex(const char * functionName, int nameLength, int scriptIndex); - void addVariableAtIndex(const char * variableName, int nameLength, int scriptIndex); + enum class NodeOrigin : uint8_t { + CurrentScript, + Builtins, + Importation + }; + enum class NodeType : uint8_t { + Variable, + Function + }; + void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + static int MaxNodesCountForOrigin(NodeOrigin origin); + int * nodesCountForOrigin(NodeOrigin origin); + + /* Return a negative int if the node name is before name in alphabetical + * order, 0 if they are equal, a positive int if it is after in alphabetical + * order. */ + static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength); ScriptNode * scriptNodeAtIndex(int index); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_builtinNodesCount]; From 75ea4ce74e8fc45e9c5130b059c2e4254564798e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 11:55:38 +0100 Subject: [PATCH 163/453] [apps/code] Clean comments --- apps/code/variable_box_controller.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 20ae11258..a171bcc86 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -201,10 +201,8 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } const char * script = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); - /* To find variable and funtion names: - * 1) We lex the script - * 2) We detect patterns on a line per line basis, a line being ended by '\n' - * or by ';', but continued by '\'. */ + /* To find variable and funtion names: we lex the script and keep all + * MP_TOKEN_NAME that are not already in the builtins or imported scripts. */ #if 1 m_currentScriptNodesCount = 0; @@ -219,12 +217,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); while (lex->tok_kind != MP_TOKEN_END) { - /* 2) Detect MP_TOKEN_NAME that are not in the builtins. Keep track of DEF - * tokens to differentiate between variables and functions. */ + /* 2) Detect MP_TOKEN_NAME that are not already in the variable box. Keep + * track of DEF tokens to differentiate between variables and functions. */ if (lex->tok_kind == MP_TOKEN_NAME) { const char * name = lex->vstr.buf; int nameLength = lex->vstr.len; - // Check if this token is already int the var box + // Check if this token is already in the var box bool alreadyInVarBox = false; // TODO Look also in imported nodes From 6f2dedf8ee4b8bbf9993357e1174e04e755991f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 11:58:24 +0100 Subject: [PATCH 164/453] [apps/code] Search aphabetically if var is already in var box --- apps/code/variable_box_controller.cpp | 51 ++++++++++++++++++++------- apps/code/variable_box_controller.h | 4 ++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index a171bcc86..1c1d5940c 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -224,16 +224,23 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha int nameLength = lex->vstr.len; // Check if this token is already in the var box bool alreadyInVarBox = false; - - // TODO Look also in imported nodes - // TODO LEA speed this up with alphabetical search - // TODO LEA use numberOfRows() and scriptNodeAtIndex ? - for (int i = 0; i < k_builtinNodesCount + m_currentScriptNodesCount; i++) { - ScriptNode * matchingNode = i < k_builtinNodesCount ? &m_builtinNodes[i] : &m_currentScriptNodes[i - k_builtinNodesCount]; - const char * nodeName = matchingNode->name(); - int nodeNameLength = matchingNode->nameLength(); - if ((nodeNameLength < 0 || nodeNameLength == nameLength) && strncmp(nodeName, name, nameLength) == 0) { - alreadyInVarBox = true; + // TODO LEA speed this up with dichotomia? + NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + ScriptNode * nodes = nodesForOrigin(origin); + for (int i = 0; i < nodesCount; i++) { + ScriptNode * matchingNode = nodes + i; + int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); + if (comparisonResult == 0) { + alreadyInVarBox = true; + break; + } + if (comparisonResult > 0) { + break; + } + } + if (alreadyInVarBox) { break; } } @@ -375,7 +382,7 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength void VariableBoxController::addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - int * currentNodeCount = nodesCountForOrigin(origin); + int * currentNodeCount = nodesCountPointerForOrigin(origin); if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { // There is no room to add another node return; @@ -411,7 +418,7 @@ int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { return k_maxScriptNodesCount; } -int * VariableBoxController::nodesCountForOrigin(NodeOrigin origin) { +int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { if (origin == NodeOrigin::CurrentScript) { return &m_currentScriptNodesCount; } @@ -419,6 +426,26 @@ int * VariableBoxController::nodesCountForOrigin(NodeOrigin origin) { return &m_importedNodesCount; } +int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { + if (origin == NodeOrigin::Builtins) { + return k_builtinNodesCount; + } + return *(const_cast(this)->nodesCountPointerForOrigin(origin)); +} + +ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { + switch(origin) { + case NodeOrigin::CurrentScript: + return m_currentScriptNodes; + case NodeOrigin::Builtins: + return m_builtinNodes; + case NodeOrigin::Importation: + return m_importedNodes; + } + assert(false); +} + +//TODO LEA CLEAN ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { assert(index >= 0 && index < numberOfRows()); assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index aba71799b..7f0ac2fcc 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -48,7 +48,9 @@ private: }; void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); static int MaxNodesCountForOrigin(NodeOrigin origin); - int * nodesCountForOrigin(NodeOrigin origin); + int * nodesCountPointerForOrigin(NodeOrigin origin); + int nodesCountForOrigin(NodeOrigin origin) const; + ScriptNode * nodesForOrigin(NodeOrigin origin); /* Return a negative int if the node name is before name in alphabetical * order, 0 if they are equal, a positive int if it is after in alphabetical From 558d53919419bd7e571f7530dedc38a5fb00c198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 12:04:23 +0100 Subject: [PATCH 165/453] [apps/code] Clean VariableBoxController::scriptNodeAtIndex --- apps/code/variable_box_controller.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 1c1d5940c..c2cf83231 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -445,20 +445,20 @@ ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { assert(false); } -//TODO LEA CLEAN ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { assert(index >= 0 && index < numberOfRows()); assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); assert(m_importedNodesCount <= k_maxScriptNodesCount); - ScriptNode * node = nullptr; - if (index < m_currentScriptNodesCount) { - node = m_currentScriptNodes + index; - } else if (index < m_currentScriptNodesCount + k_builtinNodesCount) { - node = m_builtinNodes + (index - m_currentScriptNodesCount); - } else { - node = m_importedNodes + (index - m_currentScriptNodesCount - k_builtinNodesCount); + NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + if (index < nodesCount) { + return nodesForOrigin(origin) + index; + } + index -= nodesCount; } - return node; + assert(false); + return nullptr; } int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength) { From 25f73770de8e244651856a2383d155f3ce25bc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 12:06:11 +0100 Subject: [PATCH 166/453] [apps/code] Remove compilation warning --- apps/code/variable_box_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c2cf83231..3717db8ca 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -439,10 +439,10 @@ ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { return m_currentScriptNodes; case NodeOrigin::Builtins: return m_builtinNodes; - case NodeOrigin::Importation: + default: + assert(origin == NodeOrigin::Importation); return m_importedNodes; } - assert(false); } ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { From 86349675c113abd42661e38e95cfaaaceae406a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 12:16:41 +0100 Subject: [PATCH 167/453] [apps/code] Code cleaning --- apps/code/variable_box_controller.cpp | 219 ++++++++++---------------- apps/code/variable_box_controller.h | 22 +-- 2 files changed, 95 insertions(+), 146 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3717db8ca..08ecb57b7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -18,6 +18,18 @@ namespace Code { static inline int minInt(int x, int y) { return x < y ? x : y; } +//TODO LEA use this +static bool shouldAddObject(const char * name, int maxLength) { + if (strlen(name)+1 > (size_t)maxLength) { + return false; + } + assert(name != nullptr); + if (UTF8Helper::CodePointIs(name, '_')) { + return false; + } + return true; +} + VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : NestedMenuController(nullptr, I18n::Message::FunctionsAndVariables), m_scriptStore(scriptStore), @@ -44,17 +56,6 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp assert(App::app()->pythonIsInited()); } -static bool shouldAddObject(const char * name, int maxLength) { - if (strlen(name)+1 > (size_t)maxLength) { - return false; - } - assert(name != nullptr); - if (UTF8Helper::CodePointIs(name, '_')) { - return false; - } - return true; -} - int VariableBoxController::numberOfRows() const { assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); assert(m_importedNodesCount <= k_maxScriptNodesCount); @@ -67,7 +68,6 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in myCell->setScriptNode(scriptNodeAtIndex(index)); } - /*TODO LEA very dirty * This is done to get the lexer position during lexing. As the _mp_reader_mem_t * struct is private and declared in python/src/py/reader.c, we copy-paste it @@ -80,10 +80,10 @@ typedef struct _mp_reader_mem_t { } mp_reader_mem_t; /* TODO end*/ -// TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] -// from python/lexer.c void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete) { - //TODO LEA Prune these + add modules + //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c + //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) + //TODO LEA add modules //TODO LEA Load according to textToAutocomplete int index = 0; m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_abs), -1, 0); @@ -204,7 +204,6 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha /* To find variable and funtion names: we lex the script and keep all * MP_TOKEN_NAME that are not already in the builtins or imported scripts. */ -#if 1 m_currentScriptNodesCount = 0; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -217,12 +216,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); while (lex->tok_kind != MP_TOKEN_END) { - /* 2) Detect MP_TOKEN_NAME that are not already in the variable box. Keep - * track of DEF tokens to differentiate between variables and functions. */ if (lex->tok_kind == MP_TOKEN_NAME) { + /* 2) Detect MP_TOKEN_NAME that are not already in the variable box. + * Keep track of DEF tokens to differentiate between variables and + * functions. */ const char * name = lex->vstr.buf; int nameLength = lex->vstr.len; - // Check if this token is already in the var box bool alreadyInVarBox = false; // TODO LEA speed this up with dichotomia? NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; @@ -246,14 +245,16 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } if (!alreadyInVarBox) { + /* This is a trick to get the token position in the text. The -2 was + * found from stepping in the code and trying. */ tokenInText -= 2; addNode(defToken ? NodeType::Function : NodeType::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } defToken = lex->tok_kind == MP_TOKEN_KW_DEF; - /* This is a trick to get the token position in the text. The -1 and -2 - * were found from stepping in the code and trying. */ + /* This is a trick to get the token position in the text. The -1 was found + * from stepping in the code and trying. */ tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); if (lex->tok_kind <= MP_TOKEN_ELLIPSIS || lex->tok_kind >= MP_TOKEN_OP_PLUS) { tokenInText--; @@ -265,57 +266,6 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha mp_lexer_free(lex); nlr_pop(); } - -#else - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - // 1) Lex the script - _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, script0, strlen(script0), false); - while (lex->tok_kind != MP_TOKEN_END) { - // 2) Detect patterns on a line per line basis - while (lex->tok_kind == MP_TOKEN_INDENT || lex->tok_kind == MP_TOKEN_DEDENT) { - mp_lexer_to_next(lex); - } - if (lex->tok_kind == MP_TOKEN_NAME) { - // Look for variable definition "name =" - const char * name = lex->vstr.buf; - size_t len = lex->vstr.len; - mp_lexer_to_next(lex); - if (lex->tok_kind == MP_TOKEN_DEL_EQUAL) { - addVariableAtIndex(name, len, 0); - } - } else if (lex->tok_kind != MP_TOKEN_KW_DEF) { - // Look for function definition "def name1(name2, name3 = ...):" - mp_lexer_to_next(lex); - if (lex->tok_kind == MP_TOKEN_NAME) { - const char * name = lex->vstr.buf; - size_t len = lex->vstr.len; - addFunctionAtIndex(name, len, 0); - mp_lexer_to_next(lex); - if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN) { - - } - MP_TOKEN_DEL_PAREN_CLOSE, - } - - - } - - // Forward until the end of the line - while (lex->tok_kind != MP_TOKEN_END - && lex->tok_kind != MP_TOKEN_DEL_SEMICOLON - && lex->tok_kind != MP_TOKEN_NEWLINE) - { - mp_lexer_to_next(lex); - } - if (lex->tok_kind != MP_TOKEN_END) { - mp_lexer_to_next(lex); - } - } - mp_lexer_free(lex); - nlr_pop(); - } -#endif #else m_scriptNodesCount = 1; m_scriptStore->scanScriptsForFunctionsAndVariables( @@ -353,9 +303,66 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const return nullptr; } -HighlightCell * VariableBoxController::leafCellAtIndex(int index) { - assert(index >= 0 && index < k_maxNumberOfDisplayedRows); - return &m_leafCells[index]; +int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { + assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); + return k_maxScriptNodesCount; +} + +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength) { + const char * nodeName = node->name(); + const int nodeNameLength = node->nameLength(); + const int comparisonLength = minInt(nameLength, nodeNameLength); + int result = strncmp(nodeName, name, comparisonLength); + if (result != 0) { + return result; + } + if (nodeNameLength == nameLength) { + return 0; + } + return comparisonLength == nodeNameLength ? -1 : 1; +} + +int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { + if (origin == NodeOrigin::CurrentScript) { + return &m_currentScriptNodesCount; + } + assert(origin == NodeOrigin::Importation); + return &m_importedNodesCount; +} + +int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { + if (origin == NodeOrigin::Builtins) { + return k_builtinNodesCount; + } + return *(const_cast(this)->nodesCountPointerForOrigin(origin)); +} + +ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { + switch(origin) { + case NodeOrigin::CurrentScript: + return m_currentScriptNodes; + case NodeOrigin::Builtins: + return m_builtinNodes; + default: + assert(origin == NodeOrigin::Importation); + return m_importedNodes; + } +} + +ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { + assert(index >= 0 && index < numberOfRows()); + assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_importedNodesCount <= k_maxScriptNodesCount); + NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + if (index < nodesCount) { + return nodesForOrigin(origin) + index; + } + index -= nodesCount; + } + assert(false); + return nullptr; } bool VariableBoxController::selectLeaf(int rowIndex) { @@ -413,66 +420,4 @@ void VariableBoxController::addNode(NodeType type, NodeOrigin origin, const char *currentNodeCount = *currentNodeCount + 1; } -int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { - assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - return k_maxScriptNodesCount; -} - -int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { - if (origin == NodeOrigin::CurrentScript) { - return &m_currentScriptNodesCount; - } - assert(origin == NodeOrigin::Importation); - return &m_importedNodesCount; -} - -int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { - if (origin == NodeOrigin::Builtins) { - return k_builtinNodesCount; - } - return *(const_cast(this)->nodesCountPointerForOrigin(origin)); -} - -ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { - switch(origin) { - case NodeOrigin::CurrentScript: - return m_currentScriptNodes; - case NodeOrigin::Builtins: - return m_builtinNodes; - default: - assert(origin == NodeOrigin::Importation); - return m_importedNodes; - } -} - -ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { - assert(index >= 0 && index < numberOfRows()); - assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); - assert(m_importedNodesCount <= k_maxScriptNodesCount); - NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - if (index < nodesCount) { - return nodesForOrigin(origin) + index; - } - index -= nodesCount; - } - assert(false); - return nullptr; -} - -int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength) { - const char * nodeName = node->name(); - const int nodeNameLength = node->nameLength(); - const int comparisonLength = minInt(nameLength, nodeNameLength); - int result = strncmp(nodeName, name, comparisonLength); - if (result != 0) { - return result; - } - if (nodeNameLength == nameLength) { - return 0; - } - return comparisonLength == nodeNameLength ? -1 : 1; -} - } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 7f0ac2fcc..51e891b64 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -33,10 +33,6 @@ private: constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; constexpr static int k_builtinNodesCount = 64; - HighlightCell * leafCellAtIndex(int index) override; - HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } - bool selectLeaf(int rowIndex) override; - void insertTextInCaller(const char * text, int textLength = -1); enum class NodeOrigin : uint8_t { CurrentScript, Builtins, @@ -46,17 +42,25 @@ private: Variable, Function }; - void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); static int MaxNodesCountForOrigin(NodeOrigin origin); - int * nodesCountPointerForOrigin(NodeOrigin origin); - int nodesCountForOrigin(NodeOrigin origin) const; - ScriptNode * nodesForOrigin(NodeOrigin origin); - /* Return a negative int if the node name is before name in alphabetical * order, 0 if they are equal, a positive int if it is after in alphabetical * order. */ static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength); + int * nodesCountPointerForOrigin(NodeOrigin origin); + int nodesCountForOrigin(NodeOrigin origin) const; + ScriptNode * nodesForOrigin(NodeOrigin origin); ScriptNode * scriptNodeAtIndex(int index); + HighlightCell * leafCellAtIndex(int index) override { + assert(index >= 0 && index < k_maxNumberOfDisplayedRows); + return &m_leafCells[index]; + } + HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } + + bool selectLeaf(int rowIndex) override; + void insertTextInCaller(const char * text, int textLength = -1); + void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_builtinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; From 4b36a16ceae08f2f4fa8cfcde4ed71978bb3bce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 13:46:32 +0100 Subject: [PATCH 168/453] [apps/code] Fix NodeNameCompare --- apps/code/variable_box_controller.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 08ecb57b7..4faa718bd 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -308,9 +308,10 @@ int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { return k_maxScriptNodesCount; } -int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength) { +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe) { const char * nodeName = node->name(); - const int nodeNameLength = node->nameLength(); + const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); + const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; const int comparisonLength = minInt(nameLength, nodeNameLength); int result = strncmp(nodeName, name, comparisonLength); if (result != 0) { From 1599b16e03d5ed0518529b056042d6adec7fba53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:02:39 +0100 Subject: [PATCH 169/453] [apps/code] Fix current script variables fetching --- apps/code/variable_box_controller.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 4faa718bd..8a1955737 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -247,7 +247,15 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha if (!alreadyInVarBox) { /* This is a trick to get the token position in the text. The -2 was * found from stepping in the code and trying. */ - tokenInText -= 2; + // TODO LEA FIXME + tokenInText -= lex->chr1 == -1 ? (lex->chr2 == -1 ? 0 : 1): 2; + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } + assert(strncmp(tokenInText, name, nameLength) == 0); addNode(defToken ? NodeType::Function : NodeType::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } From f412d95584e7293ae41f3de408e3eb2fbe23c942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:04:38 +0100 Subject: [PATCH 170/453] [apps/code] Load builtins according to autocompleted text --- apps/code/console_controller.cpp | 2 +- apps/code/editor_controller.cpp | 4 +- apps/code/editor_view.cpp | 4 +- apps/code/editor_view.h | 6 +- apps/code/python_text_area.cpp | 13 +- apps/code/python_text_area.h | 4 +- apps/code/variable_box_controller.cpp | 256 +++++++++++++++----------- apps/code/variable_box_controller.h | 28 ++- 8 files changed, 186 insertions(+), 131 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 6c66b51be..b60f069e8 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -57,7 +57,7 @@ bool ConsoleController::loadPythonEnvironment() { /* We load functions and variables names in the variable box before running * any other python code to avoid failling to load functions and variables * due to memory exhaustion. */ - App::app()->variableBoxController()->loadFunctionsAndVariables(-1, nullptr); + App::app()->variableBoxController()->loadFunctionsAndVariables(-1, nullptr, -1); return true; } diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index a03f29406..3e5cc408b 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -124,7 +124,9 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events: VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - varBox->loadFunctionsAndVariables(m_scriptIndex, m_editorView.textToAutocomplete()); + int length = 0; + const char * text = m_editorView.textToAutocomplete(&length); + varBox->loadFunctionsAndVariables(m_scriptIndex, text, length); return varBox; } diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index 455e5761e..0e174f95e 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -16,8 +16,8 @@ EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) : m_textArea.setScrollViewDelegate(this); } -const char * EditorView::textToAutocomplete() const { - return m_textArea.textToAutocomplete(); +const char * EditorView::textToAutocomplete(int * length) const { + return m_textArea.textToAutocomplete(length); } void EditorView::resetSelection() { diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index 58ec93eff..24455c48d 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -9,7 +9,11 @@ namespace Code { class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); - const char * textToAutocomplete() const; + + /* Returns the beginning of the text to autocomplete, and loads its length in + * the method parameter length */ + const char * textToAutocomplete(int * length) const; + void resetSelection(); void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { m_textArea.setDelegates(inputEventHandlerDelegate, delegate); diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 1ac729dd1..9b177d4d3 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -53,8 +53,13 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { return lex->column - lex->tok_column; } -const char * PythonTextArea::ContentView::textToAutocomplete() const { - return UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); +const char * PythonTextArea::ContentView::textToAutocomplete(int * length) const { + const char * result = UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); + if (length != nullptr) { + *length = cursorLocation() - result; + assert(*length > 0); + } + return result; } void PythonTextArea::ContentView::loadSyntaxHighlighter() { @@ -235,11 +240,11 @@ bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bo return result; } -const char * PythonTextArea::textToAutocomplete() const { +const char * PythonTextArea::textToAutocomplete(int * length) const { if (!m_contentView.isAutocompleting()) { return nullptr; } - return m_contentView.textToAutocomplete(); + return m_contentView.textToAutocomplete(length); } void PythonTextArea::removeAutocompletion() { diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 7b0031b9d..c58e586c1 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -18,7 +18,7 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; - const char * textToAutocomplete() const; + const char * textToAutocomplete(int * length = nullptr) const; protected: class ContentView : public TextArea::ContentView { public: @@ -31,7 +31,7 @@ protected: App * pythonDelegate() { return m_pythonDelegate; } void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } bool isAutocompleting() const { return m_autocomplete; } - const char * textToAutocomplete() const; + const char * textToAutocomplete(int * length = nullptr) const; void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); void clearRect(KDContext * ctx, KDRect rect) const override; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8a1955737..80eaf7dac 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -34,6 +34,7 @@ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : NestedMenuController(nullptr, I18n::Message::FunctionsAndVariables), m_scriptStore(scriptStore), m_currentScriptNodesCount(0), + m_builtinNodesCount(0), m_importedNodesCount(0) { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { @@ -59,7 +60,7 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp int VariableBoxController::numberOfRows() const { assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); assert(m_importedNodesCount <= k_maxScriptNodesCount); - return m_currentScriptNodesCount + k_builtinNodesCount + m_importedNodesCount; + return m_currentScriptNodesCount + m_builtinNodesCount + m_importedNodesCount; } void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { @@ -80,116 +81,132 @@ typedef struct _mp_reader_mem_t { } mp_reader_mem_t; /* TODO end*/ -void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete) { +void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) //TODO LEA add modules - //TODO LEA Load according to textToAutocomplete - int index = 0; - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_abs), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_all), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_and), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_any), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_as), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ascii), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_assert), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bin), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bool), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_break), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_breakpoint), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytearray), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_bytes), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_callable), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_chr), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_class), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_classmethod), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_compile), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_complex), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_continue), -1, 0); - m_builtinNodes[index++] = ScriptNode::VariableNode("def", -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR___del__), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_delattr), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dict), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_dir), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_divmod), -1, 0); - m_builtinNodes[index++] = ScriptNode::VariableNode("elif", -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_else), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_enumerate), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_eval), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_except), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_exec), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_False), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_filter), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_finally), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_float), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_for), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_format), -1, 0); - m_builtinNodes[index++] = ScriptNode::VariableNode("from", -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_frozenset), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_getattr), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_global), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_globals), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hasattr), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hash), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_help), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_hex), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_id), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_if), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_import), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_in), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_input), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_int), -1, 0); - // m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_is), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_isinstance), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_issubclass), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_iter), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_lambda), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_len), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_list), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_locals), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_map), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_max), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_memoryview), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_min), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_next), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_None), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_nonlocal), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_not), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_object), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_oct), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_open), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_or), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_ord), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_pass), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_pow), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_print), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_property), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_raise), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_range), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_repr), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_return), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_reversed), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_round), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_set), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_setattr), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_slice), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sorted), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_staticmethod), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_str), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_sum), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_super), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_True), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_try), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_tuple), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_type), -1, 0); - //m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_vars), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_while), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_with), -1, 0); - //m_builtinNodes[index++] = ScriptNode::VariableNode(qstr_str(MP_QSTR_yield), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR_zip), -1, 0); - m_builtinNodes[index++] = ScriptNode::FunctionNode(qstr_str(MP_QSTR___import__), -1, 0); //TODO LEA alphabetical order? - assert(index == k_builtinNodesCount); + // Reset the node counts + m_currentScriptNodesCount = 0; + m_builtinNodesCount = 0; + m_importedNodesCount = 0; + + // Add buitin nodes + static const struct { const char * name; NodeType type; } builtinNames[] = { + {qstr_str(MP_QSTR_abs), NodeType::Function}, + {qstr_str(MP_QSTR_all), NodeType::Function}, + {"and", NodeType::Variable}, + {qstr_str(MP_QSTR_any), NodeType::Function}, + {"as", NodeType::Variable}, + //{qstr_str(MP_QSTR_ascii), NodeType::Function}, + {"assert", NodeType::Variable}, + {qstr_str(MP_QSTR_bin), NodeType::Function}, + {qstr_str(MP_QSTR_bool), NodeType::Function}, + {"break", NodeType::Variable}, + //{qstr_str(MP_QSTR_breakpoint), NodeType::Function}, + {qstr_str(MP_QSTR_bytearray), NodeType::Function}, + {qstr_str(MP_QSTR_bytes), NodeType::Function}, + {qstr_str(MP_QSTR_callable), NodeType::Function}, + {qstr_str(MP_QSTR_chr), NodeType::Function}, + {"class", NodeType::Variable}, + {qstr_str(MP_QSTR_classmethod), NodeType::Function}, + //{qstr_str(MP_QSTR_compile), NodeType::Function}, + {qstr_str(MP_QSTR_complex), NodeType::Function}, + {"continue", NodeType::Variable}, + {"def", NodeType::Variable}, + {"__del__", NodeType::Variable}, + //{qstr_str(MP_QSTR_delattr), NodeType::Function}, + {qstr_str(MP_QSTR_dict), NodeType::Function}, + {qstr_str(MP_QSTR_dir), NodeType::Function}, + {qstr_str(MP_QSTR_divmod), NodeType::Function}, + {"elif", NodeType::Variable}, + {"else", NodeType::Variable}, + {qstr_str(MP_QSTR_enumerate), NodeType::Function}, + {qstr_str(MP_QSTR_eval), NodeType::Function}, + {"except", NodeType::Variable}, + {qstr_str(MP_QSTR_exec), NodeType::Function}, + {"False", NodeType::Variable}, + {qstr_str(MP_QSTR_filter), NodeType::Function}, + {"finally", NodeType::Variable}, + {qstr_str(MP_QSTR_float), NodeType::Function}, + {"for", NodeType::Variable}, + {qstr_str(MP_QSTR_format), NodeType::Function}, + {"from", NodeType::Variable}, + {qstr_str(MP_QSTR_frozenset), NodeType::Function}, + {qstr_str(MP_QSTR_getattr), NodeType::Function}, + {"global", NodeType::Variable}, + {qstr_str(MP_QSTR_globals), NodeType::Function}, + {qstr_str(MP_QSTR_hasattr), NodeType::Function}, + {qstr_str(MP_QSTR_hash), NodeType::Function}, + //{qstr_str(MP_QSTR_help), NodeType::Function}, + {qstr_str(MP_QSTR_hex), NodeType::Function}, + {qstr_str(MP_QSTR_id), NodeType::Function}, + {"if", NodeType::Variable}, + {"import", NodeType::Variable}, + {"in", NodeType::Variable}, + {qstr_str(MP_QSTR_input), NodeType::Function}, + {qstr_str(MP_QSTR_int), NodeType::Function}, + {"is", NodeType::Variable}, + {qstr_str(MP_QSTR_isinstance), NodeType::Function}, + {qstr_str(MP_QSTR_issubclass), NodeType::Function}, + {qstr_str(MP_QSTR_iter), NodeType::Function}, + {"lambda", NodeType::Variable}, + {qstr_str(MP_QSTR_len), NodeType::Function}, + {qstr_str(MP_QSTR_list), NodeType::Function}, + {qstr_str(MP_QSTR_locals), NodeType::Function}, + {qstr_str(MP_QSTR_map), NodeType::Function}, + {qstr_str(MP_QSTR_max), NodeType::Function}, + //{qstr_str(MP_QSTR_memoryview), NodeType::Function}, + {qstr_str(MP_QSTR_min), NodeType::Function}, + {qstr_str(MP_QSTR_next), NodeType::Function}, + {"None", NodeType::Variable}, + {"nonlocal", NodeType::Variable}, + {"not", NodeType::Variable}, + {qstr_str(MP_QSTR_object), NodeType::Function}, + {qstr_str(MP_QSTR_oct), NodeType::Function}, + {qstr_str(MP_QSTR_open), NodeType::Function}, + {"or", NodeType::Variable}, + {qstr_str(MP_QSTR_ord), NodeType::Function}, + {"pass", NodeType::Variable}, + {qstr_str(MP_QSTR_pow), NodeType::Function}, + {qstr_str(MP_QSTR_print), NodeType::Function}, + //{qstr_str(MP_QSTR_property), NodeType::Function}, + {"raise", NodeType::Variable}, + {qstr_str(MP_QSTR_range), NodeType::Function}, + {qstr_str(MP_QSTR_repr), NodeType::Function}, + {"return", NodeType::Variable}, + {qstr_str(MP_QSTR_reversed), NodeType::Function}, + {qstr_str(MP_QSTR_round), NodeType::Function}, + {qstr_str(MP_QSTR_set), NodeType::Function}, + {qstr_str(MP_QSTR_setattr), NodeType::Function}, + {qstr_str(MP_QSTR_slice), NodeType::Function}, + {qstr_str(MP_QSTR_sorted), NodeType::Function}, + {qstr_str(MP_QSTR_staticmethod), NodeType::Function}, + {qstr_str(MP_QSTR_str), NodeType::Function}, + {qstr_str(MP_QSTR_sum), NodeType::Function}, + {qstr_str(MP_QSTR_super), NodeType::Function}, + {"True", NodeType::Variable}, + {"try", NodeType::Variable}, + {qstr_str(MP_QSTR_tuple), NodeType::Function}, + {qstr_str(MP_QSTR_type), NodeType::Function}, + //{qstr_str(MP_QSTR_vars), NodeType::Function}, + {"while", NodeType::Variable}, + {"with", NodeType::Variable}, + {"yield", NodeType::Variable}, + {qstr_str(MP_QSTR_zip), NodeType::Function}, + {qstr_str(MP_QSTR___import__), NodeType::Function} //TODO LEA alphabetical order? + }; + assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); + for (int i = 0; i < k_totalBuiltinNodesCount; i++) { + // TODO remove those two constructors + ScriptNode node = builtinNames[i].type == NodeType::Function ? ScriptNode::FunctionNode( builtinNames[i].name, -1, 0) : ScriptNode::VariableNode(builtinNames[i].name, -1, 0); + int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); + if (startsWith == 0) { + m_builtinNodes[m_builtinNodesCount++] = node; + } else if (startsWith > 0) { + break; + } + } // Load the imported variables and functions //TODO LEA @@ -294,11 +311,11 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength) { - // TODO LEA Accelerate - loadFunctionsAndVariables(scriptIndex, text); const char * endOfText = UTF8Helper::EndOfWord(text); const int textLength = endOfText - text; assert(textLength >= 1); + loadFunctionsAndVariables(scriptIndex, text, textLength); + // TODO LEA Accelerate for (int i = 0; i < numberOfRows(); i++) { ScriptNode * node = scriptNodeAtIndex(i); const char * currentName = node->name(); @@ -316,7 +333,8 @@ int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { return k_maxScriptNodesCount; } -int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe) { +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe, bool * strictlyStartsWith) { + assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); const char * nodeName = node->name(); const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; @@ -328,7 +346,20 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, if (nodeNameLength == nameLength) { return 0; } - return comparisonLength == nodeNameLength ? -1 : 1; + bool nodeNameLengthStartsWithName = comparisonLength == nameLength; + if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { + *strictlyStartsWith = true; + } + return nodeNameLengthStartsWithName ? -1 : 1; +} + +int VariableBoxController::NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength) { + bool strictlyStartsWith = false; + int result = NodeNameCompare(node, name, nameLength, &strictlyStartsWith); + if (strictlyStartsWith) { + return 0; + } + return result <= 0 ? -1 : 1; } int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { @@ -341,7 +372,7 @@ int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { if (origin == NodeOrigin::Builtins) { - return k_builtinNodesCount; + return m_builtinNodesCount; } return *(const_cast(this)->nodesCountPointerForOrigin(origin)); } @@ -361,6 +392,7 @@ ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { assert(index >= 0 && index < numberOfRows()); assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_builtinNodesCount <= k_totalBuiltinNodesCount); assert(m_importedNodesCount <= k_maxScriptNodesCount); NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; for (NodeOrigin origin : origins) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 51e891b64..098d6d6a1 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -26,27 +26,37 @@ public: int typeAtLocation(int i, int j) override { return 0; } /* VariableBoxController */ - void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete); + void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); const char * autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength); private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; - constexpr static int k_builtinNodesCount = 64; + constexpr static int k_totalBuiltinNodesCount = 94; enum class NodeOrigin : uint8_t { CurrentScript, Builtins, Importation }; - enum class NodeType : uint8_t { + enum class NodeType : bool { Variable, Function }; static int MaxNodesCountForOrigin(NodeOrigin origin); - /* Return a negative int if the node name is before name in alphabetical - * order, 0 if they are equal, a positive int if it is after in alphabetical - * order. */ - static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength); + /* Returns: + * - a negative int if the node name is before name in alphabetical + * order + * - 0 if they are equal + * - a positive int if it is after in alphabetical order. + * strictlyStartsWith is set to True if the node name starts with name but + * they are not equal.*/ + static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith = nullptr); + /* Returns: + * - a negative int if the node name is before name in alphabetical + * order or equal to name + * - 0 if node name strictly starts with name + * - a positive int if node name is after name in alphabetical order. */ + static int NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength); int * nodesCountPointerForOrigin(NodeOrigin origin); int nodesCountForOrigin(NodeOrigin origin) const; ScriptNode * nodesForOrigin(NodeOrigin origin); @@ -62,11 +72,13 @@ private: void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; - ScriptNode m_builtinNodes[k_builtinNodesCount]; + ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; ScriptNodeCell m_leafCells[k_maxNumberOfDisplayedRows]; ScriptStore * m_scriptStore; + // TODO LEA Put these in an array? int m_currentScriptNodesCount; + int m_builtinNodesCount; int m_importedNodesCount; }; From 1b828196e92c5438430dab74c650357c43052a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:09:10 +0100 Subject: [PATCH 171/453] [apps/code] Use ScriptNode::Type in VariableBoxController --- apps/code/script_node.h | 6 +- apps/code/variable_box_controller.cpp | 214 +++++++++++++------------- apps/code/variable_box_controller.h | 6 +- 3 files changed, 111 insertions(+), 115 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 36eaec7de..0ffa3653d 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -8,9 +8,9 @@ namespace Code { class ScriptNode { public: - enum class Type { - Function = 0, - Variable = 1 + enum class Type : bool { + Function, + Variable }; ScriptNode() : m_type(Type::Function), m_name(nullptr), m_scriptIndex(0), m_nameLength(0) {} diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 80eaf7dac..c5ad4d3a1 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -92,114 +92,114 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha m_importedNodesCount = 0; // Add buitin nodes - static const struct { const char * name; NodeType type; } builtinNames[] = { - {qstr_str(MP_QSTR_abs), NodeType::Function}, - {qstr_str(MP_QSTR_all), NodeType::Function}, - {"and", NodeType::Variable}, - {qstr_str(MP_QSTR_any), NodeType::Function}, - {"as", NodeType::Variable}, - //{qstr_str(MP_QSTR_ascii), NodeType::Function}, - {"assert", NodeType::Variable}, - {qstr_str(MP_QSTR_bin), NodeType::Function}, - {qstr_str(MP_QSTR_bool), NodeType::Function}, - {"break", NodeType::Variable}, - //{qstr_str(MP_QSTR_breakpoint), NodeType::Function}, - {qstr_str(MP_QSTR_bytearray), NodeType::Function}, - {qstr_str(MP_QSTR_bytes), NodeType::Function}, - {qstr_str(MP_QSTR_callable), NodeType::Function}, - {qstr_str(MP_QSTR_chr), NodeType::Function}, - {"class", NodeType::Variable}, - {qstr_str(MP_QSTR_classmethod), NodeType::Function}, - //{qstr_str(MP_QSTR_compile), NodeType::Function}, - {qstr_str(MP_QSTR_complex), NodeType::Function}, - {"continue", NodeType::Variable}, - {"def", NodeType::Variable}, - {"__del__", NodeType::Variable}, - //{qstr_str(MP_QSTR_delattr), NodeType::Function}, - {qstr_str(MP_QSTR_dict), NodeType::Function}, - {qstr_str(MP_QSTR_dir), NodeType::Function}, - {qstr_str(MP_QSTR_divmod), NodeType::Function}, - {"elif", NodeType::Variable}, - {"else", NodeType::Variable}, - {qstr_str(MP_QSTR_enumerate), NodeType::Function}, - {qstr_str(MP_QSTR_eval), NodeType::Function}, - {"except", NodeType::Variable}, - {qstr_str(MP_QSTR_exec), NodeType::Function}, - {"False", NodeType::Variable}, - {qstr_str(MP_QSTR_filter), NodeType::Function}, - {"finally", NodeType::Variable}, - {qstr_str(MP_QSTR_float), NodeType::Function}, - {"for", NodeType::Variable}, - {qstr_str(MP_QSTR_format), NodeType::Function}, - {"from", NodeType::Variable}, - {qstr_str(MP_QSTR_frozenset), NodeType::Function}, - {qstr_str(MP_QSTR_getattr), NodeType::Function}, - {"global", NodeType::Variable}, - {qstr_str(MP_QSTR_globals), NodeType::Function}, - {qstr_str(MP_QSTR_hasattr), NodeType::Function}, - {qstr_str(MP_QSTR_hash), NodeType::Function}, - //{qstr_str(MP_QSTR_help), NodeType::Function}, - {qstr_str(MP_QSTR_hex), NodeType::Function}, - {qstr_str(MP_QSTR_id), NodeType::Function}, - {"if", NodeType::Variable}, - {"import", NodeType::Variable}, - {"in", NodeType::Variable}, - {qstr_str(MP_QSTR_input), NodeType::Function}, - {qstr_str(MP_QSTR_int), NodeType::Function}, - {"is", NodeType::Variable}, - {qstr_str(MP_QSTR_isinstance), NodeType::Function}, - {qstr_str(MP_QSTR_issubclass), NodeType::Function}, - {qstr_str(MP_QSTR_iter), NodeType::Function}, - {"lambda", NodeType::Variable}, - {qstr_str(MP_QSTR_len), NodeType::Function}, - {qstr_str(MP_QSTR_list), NodeType::Function}, - {qstr_str(MP_QSTR_locals), NodeType::Function}, - {qstr_str(MP_QSTR_map), NodeType::Function}, - {qstr_str(MP_QSTR_max), NodeType::Function}, - //{qstr_str(MP_QSTR_memoryview), NodeType::Function}, - {qstr_str(MP_QSTR_min), NodeType::Function}, - {qstr_str(MP_QSTR_next), NodeType::Function}, - {"None", NodeType::Variable}, - {"nonlocal", NodeType::Variable}, - {"not", NodeType::Variable}, - {qstr_str(MP_QSTR_object), NodeType::Function}, - {qstr_str(MP_QSTR_oct), NodeType::Function}, - {qstr_str(MP_QSTR_open), NodeType::Function}, - {"or", NodeType::Variable}, - {qstr_str(MP_QSTR_ord), NodeType::Function}, - {"pass", NodeType::Variable}, - {qstr_str(MP_QSTR_pow), NodeType::Function}, - {qstr_str(MP_QSTR_print), NodeType::Function}, - //{qstr_str(MP_QSTR_property), NodeType::Function}, - {"raise", NodeType::Variable}, - {qstr_str(MP_QSTR_range), NodeType::Function}, - {qstr_str(MP_QSTR_repr), NodeType::Function}, - {"return", NodeType::Variable}, - {qstr_str(MP_QSTR_reversed), NodeType::Function}, - {qstr_str(MP_QSTR_round), NodeType::Function}, - {qstr_str(MP_QSTR_set), NodeType::Function}, - {qstr_str(MP_QSTR_setattr), NodeType::Function}, - {qstr_str(MP_QSTR_slice), NodeType::Function}, - {qstr_str(MP_QSTR_sorted), NodeType::Function}, - {qstr_str(MP_QSTR_staticmethod), NodeType::Function}, - {qstr_str(MP_QSTR_str), NodeType::Function}, - {qstr_str(MP_QSTR_sum), NodeType::Function}, - {qstr_str(MP_QSTR_super), NodeType::Function}, - {"True", NodeType::Variable}, - {"try", NodeType::Variable}, - {qstr_str(MP_QSTR_tuple), NodeType::Function}, - {qstr_str(MP_QSTR_type), NodeType::Function}, - //{qstr_str(MP_QSTR_vars), NodeType::Function}, - {"while", NodeType::Variable}, - {"with", NodeType::Variable}, - {"yield", NodeType::Variable}, - {qstr_str(MP_QSTR_zip), NodeType::Function}, - {qstr_str(MP_QSTR___import__), NodeType::Function} //TODO LEA alphabetical order? + static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { + {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, + {"and", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_any), ScriptNode::Type::Function}, + {"as", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::Function}, + {"assert", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_bin), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bool), ScriptNode::Type::Function}, + {"break", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bytes), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_callable), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, + {"class", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, + {"continue", ScriptNode::Type::Variable}, + {"def", ScriptNode::Type::Variable}, + {"__del__", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_dict), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_dir), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_divmod), ScriptNode::Type::Function}, + {"elif", ScriptNode::Type::Variable}, + {"else", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_enumerate), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_eval), ScriptNode::Type::Function}, + {"except", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_exec), ScriptNode::Type::Function}, + {"False", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_filter), ScriptNode::Type::Function}, + {"finally", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_float), ScriptNode::Type::Function}, + {"for", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, + {"from", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_getattr), ScriptNode::Type::Function}, + {"global", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_globals), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hasattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hash), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_help), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hex), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_id), ScriptNode::Type::Function}, + {"if", ScriptNode::Type::Variable}, + {"import", ScriptNode::Type::Variable}, + {"in", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, + {"is", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_iter), ScriptNode::Type::Function}, + {"lambda", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_len), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_list), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_locals), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_map), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_max), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_min), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_next), ScriptNode::Type::Function}, + {"None", ScriptNode::Type::Variable}, + {"nonlocal", ScriptNode::Type::Variable}, + {"not", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_object), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_oct), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_open), ScriptNode::Type::Function}, + {"or", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_ord), ScriptNode::Type::Function}, + {"pass", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_pow), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, + {"raise", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, + {"return", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_reversed), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_sum), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_super), ScriptNode::Type::Function}, + {"True", ScriptNode::Type::Variable}, + {"try", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_tuple), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_type), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_vars), ScriptNode::Type::Function}, + {"while", ScriptNode::Type::Variable}, + {"with", ScriptNode::Type::Variable}, + {"yield", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_zip), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR___import__), ScriptNode::Type::Function} //TODO LEA alphabetical order? }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); for (int i = 0; i < k_totalBuiltinNodesCount; i++) { // TODO remove those two constructors - ScriptNode node = builtinNames[i].type == NodeType::Function ? ScriptNode::FunctionNode( builtinNames[i].name, -1, 0) : ScriptNode::VariableNode(builtinNames[i].name, -1, 0); + ScriptNode node = builtinNames[i].type == ScriptNode::Type::Function ? ScriptNode::FunctionNode( builtinNames[i].name, -1, 0) : ScriptNode::VariableNode(builtinNames[i].name, -1, 0); int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); if (startsWith == 0) { m_builtinNodes[m_builtinNodesCount++] = node; @@ -273,7 +273,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha tokenInText--; } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? NodeType::Function : NodeType::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } defToken = lex->tok_kind == MP_TOKEN_KW_DEF; @@ -428,7 +428,7 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength sender()->handleEventWithText(commandBuffer); } -void VariableBoxController::addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { +void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); int * currentNodeCount = nodesCountPointerForOrigin(origin); if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { @@ -454,7 +454,7 @@ void VariableBoxController::addNode(NodeType type, NodeOrigin origin, const char nodes[i+1] = nodes[i]; } // Add the node - nodes[insertionIndex] = type == NodeType::Variable ? + nodes[insertionIndex] = type == ScriptNode::Type::Variable ? ScriptNode::VariableNode(name, nameLength, scriptIndex) : ScriptNode::FunctionNode(name, nameLength, scriptIndex); // Increase the node count diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 098d6d6a1..1df9dca94 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -38,10 +38,6 @@ private: Builtins, Importation }; - enum class NodeType : bool { - Variable, - Function - }; static int MaxNodesCountForOrigin(NodeOrigin origin); /* Returns: * - a negative int if the node name is before name in alphabetical @@ -69,7 +65,7 @@ private: bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); - void addNode(NodeType type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From e934bb39e3959e9c4b55d1e79401f1746a577b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:25:45 +0100 Subject: [PATCH 172/453] [apps/code] Clean ScriptNode --- apps/code/script_node.h | 20 ++++++++------------ apps/code/variable_box_controller.cpp | 7 ++----- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 0ffa3653d..a788d3457 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -12,25 +12,21 @@ public: Function, Variable }; - ScriptNode() : - m_type(Type::Function), m_name(nullptr), m_scriptIndex(0), m_nameLength(0) {} - static ScriptNode FunctionNode(const char * name, int nameLength, uint16_t scriptIndex) { - return ScriptNode(Type::Function, name, scriptIndex, nameLength); - } - static ScriptNode VariableNode(const char * name, int nameLength, uint16_t scriptIndex) { - return ScriptNode(Type::Variable, name, scriptIndex, nameLength); - } + ScriptNode(Type type = Type::Variable, const char * name = nullptr, int nameLength = 0, uint16_t scriptIndex = 0) : + m_type(type), + m_name(name), + m_scriptIndex(scriptIndex), + m_nameLength(nameLength) + {} Type type() const { return m_type; } const char * name() const { return m_name; } int nameLength() const { return m_nameLength; } uint16_t scriptIndex() const { return m_scriptIndex; } private: - ScriptNode(Type type, const char * name, uint16_t scriptIndex, int nameLength) : - m_type(type), m_name(name), m_scriptIndex(scriptIndex), m_nameLength(nameLength) {} Type m_type; const char * m_name; - uint16_t m_scriptIndex; - int m_nameLength; + uint16_t m_scriptIndex; // TODO LEA smaller type ? + int m_nameLength; // TODO LEA smaller type ? }; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c5ad4d3a1..0840070cb 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -198,8 +198,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); for (int i = 0; i < k_totalBuiltinNodesCount; i++) { - // TODO remove those two constructors - ScriptNode node = builtinNames[i].type == ScriptNode::Type::Function ? ScriptNode::FunctionNode( builtinNames[i].name, -1, 0) : ScriptNode::VariableNode(builtinNames[i].name, -1, 0); + ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name, -1, 0); int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); if (startsWith == 0) { m_builtinNodes[m_builtinNodesCount++] = node; @@ -454,9 +453,7 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co nodes[i+1] = nodes[i]; } // Add the node - nodes[insertionIndex] = type == ScriptNode::Type::Variable ? - ScriptNode::VariableNode(name, nameLength, scriptIndex) : - ScriptNode::FunctionNode(name, nameLength, scriptIndex); + nodes[insertionIndex] = ScriptNode(type, name, nameLength, scriptIndex); // Increase the node count *currentNodeCount = *currentNodeCount + 1; } From 6b93a5b83a79a498ddfa1c5bba35ecaaa624f27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:37:49 +0100 Subject: [PATCH 173/453] [apps/code] Load current script vars according to autocompleted text --- apps/code/variable_box_controller.cpp | 87 ++++++++++++++++----------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 0840070cb..c253fb062 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -218,7 +218,8 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha const char * script = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); /* To find variable and funtion names: we lex the script and keep all - * MP_TOKEN_NAME that are not already in the builtins or imported scripts. */ + * MP_TOKEN_NAME that complete the text to autocomplete and are not already in + * the builtins or imported scripts. */ m_currentScriptNodesCount = 0; nlr_buf_t nlr; @@ -226,55 +227,71 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha // 1) Lex the script _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, script, strlen(script), false); - bool defToken = false; // This is a trick to get the token position in the text. const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + // Keep track of DEF tokens to differentiate between variables and functions + bool defToken = false; + + if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { + textToAutocompleteLength = strlen(textToAutocomplete); + } while (lex->tok_kind != MP_TOKEN_END) { + // Keep only MP_TOKEN_NAME tokens if (lex->tok_kind == MP_TOKEN_NAME) { - /* 2) Detect MP_TOKEN_NAME that are not already in the variable box. - * Keep track of DEF tokens to differentiate between variables and - * functions. */ + const char * name = lex->vstr.buf; int nameLength = lex->vstr.len; - bool alreadyInVarBox = false; - // TODO LEA speed this up with dichotomia? - NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - ScriptNode * nodes = nodesForOrigin(origin); - for (int i = 0; i < nodesCount; i++) { - ScriptNode * matchingNode = nodes + i; - int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); - if (comparisonResult == 0) { - alreadyInVarBox = true; - break; - } - if (comparisonResult > 0) { - break; - } - } - if (alreadyInVarBox) { - break; + + // Check if the token completes the text to autocomplete + bool canKeepChecking = textToAutocomplete == nullptr; + if (!canKeepChecking) { + if (textToAutocompleteLength < nameLength && strncmp(name, textToAutocomplete, textToAutocompleteLength) == 0) { + canKeepChecking = true; } } - if (!alreadyInVarBox) { - /* This is a trick to get the token position in the text. The -2 was - * found from stepping in the code and trying. */ - // TODO LEA FIXME - tokenInText -= lex->chr1 == -1 ? (lex->chr2 == -1 ? 0 : 1): 2; - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; + if (canKeepChecking) { + bool alreadyInVarBox = false; + // TODO LEA speed this up with dichotomia? + NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + ScriptNode * nodes = nodesForOrigin(origin); + for (int i = 0; i < nodesCount; i++) { + ScriptNode * matchingNode = nodes + i; + int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); + if (comparisonResult == 0) { + alreadyInVarBox = true; + break; + } + if (comparisonResult > 0) { + break; + } + } + if (alreadyInVarBox) { + break; + } } - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; + + if (!alreadyInVarBox) { + /* This is a trick to get the token position in the text. The -2 was + * found from stepping in the code and trying. */ + // TODO LEA FIXME + tokenInText -= lex->chr1 == -1 ? (lex->chr2 == -1 ? 0 : 1): 2; + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } + assert(strncmp(tokenInText, name, nameLength) == 0); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } - assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } + defToken = lex->tok_kind == MP_TOKEN_KW_DEF; /* This is a trick to get the token position in the text. The -1 was found From e32a5ccc17cdac72cdfa39a6276238a4ed110a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:54:31 +0100 Subject: [PATCH 174/453] [apps/code] Simpler VarBoxController::autocompletionForText --- apps/code/variable_box_controller.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c253fb062..9221b0e15 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -331,17 +331,18 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const const int textLength = endOfText - text; assert(textLength >= 1); loadFunctionsAndVariables(scriptIndex, text, textLength); - // TODO LEA Accelerate - for (int i = 0; i < numberOfRows(); i++) { - ScriptNode * node = scriptNodeAtIndex(i); - const char * currentName = node->name(); - int currentNameLength = node->nameLength(); - if ((currentNameLength < 0 || currentNameLength != textLength) && strncmp(text, currentName, textLength) == 0) { - *textToInsertLength = (currentNameLength < 0 ? strlen(currentName) : currentNameLength) - textLength; - return currentName + textLength; - } + if (numberOfRows() == 0) { + return nullptr; } - return nullptr; + ScriptNode * node = scriptNodeAtIndex(0); + const char * currentName = node->name(); + int currentNameLength = node->nameLength(); + if (currentNameLength < 0) { + currentNameLength = strlen(currentName); + } + assert(currentNameLength != textLength && strncmp(text, currentName, textLength) == 0); + *textToInsertLength = currentNameLength - textLength; + return currentName + textLength; } int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { From bc4d96bc3f73a2bd30cb25b451e661f1d52a8e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:54:52 +0100 Subject: [PATCH 175/453] [apps/code] Reload the variable box less often --- apps/code/editor_controller.cpp | 7 ++++--- apps/code/editor_view.cpp | 4 ++++ apps/code/editor_view.h | 1 + apps/code/python_text_area.h | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 3e5cc408b..dd4eadba1 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -124,9 +124,10 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events: VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - int length = 0; - const char * text = m_editorView.textToAutocomplete(&length); - varBox->loadFunctionsAndVariables(m_scriptIndex, text, length); + // If the editor is autocompleting, the variable box has already been loaded + if (!m_editorView.isAutocompleting()) { + varBox->loadFunctionsAndVariables(m_scriptIndex, nullptr, 0); + } return varBox; } diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index 0e174f95e..f16bfec21 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -20,6 +20,10 @@ const char * EditorView::textToAutocomplete(int * length) const { return m_textArea.textToAutocomplete(length); } +bool EditorView::isAutocompleting() const { + return m_textArea.isAutocompleting(); +} + void EditorView::resetSelection() { m_textArea.resetSelection(); } diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index 24455c48d..2093bcc3d 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -10,6 +10,7 @@ class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); + bool isAutocompleting() const; /* Returns the beginning of the text to autocomplete, and loads its length in * the method parameter length */ const char * textToAutocomplete(int * length) const; diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index c58e586c1..6c4765910 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -19,6 +19,7 @@ public: bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; const char * textToAutocomplete(int * length = nullptr) const; + bool isAutocompleting() const { return m_contentView.isAutocompleting(); } protected: class ContentView : public TextArea::ContentView { public: From 14f914e3d61724c1d8d148003a16f6c07c5f631e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 15:56:32 +0100 Subject: [PATCH 176/453] [apps/code] Remove unused functions and argument --- apps/code/editor_view.cpp | 4 ---- apps/code/editor_view.h | 5 ----- apps/code/python_text_area.cpp | 16 ++-------------- apps/code/python_text_area.h | 3 +-- 4 files changed, 3 insertions(+), 25 deletions(-) diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index f16bfec21..2685fa5fb 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -16,10 +16,6 @@ EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) : m_textArea.setScrollViewDelegate(this); } -const char * EditorView::textToAutocomplete(int * length) const { - return m_textArea.textToAutocomplete(length); -} - bool EditorView::isAutocompleting() const { return m_textArea.isAutocompleting(); } diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index 2093bcc3d..b7f5ca969 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -9,12 +9,7 @@ namespace Code { class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); - bool isAutocompleting() const; - /* Returns the beginning of the text to autocomplete, and loads its length in - * the method parameter length */ - const char * textToAutocomplete(int * length) const; - void resetSelection(); void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { m_textArea.setDelegates(inputEventHandlerDelegate, delegate); diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 9b177d4d3..42cd2552f 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -53,13 +53,8 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { return lex->column - lex->tok_column; } -const char * PythonTextArea::ContentView::textToAutocomplete(int * length) const { - const char * result = UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); - if (length != nullptr) { - *length = cursorLocation() - result; - assert(*length > 0); - } - return result; +const char * PythonTextArea::ContentView::textToAutocomplete() const { + return UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); } void PythonTextArea::ContentView::loadSyntaxHighlighter() { @@ -240,13 +235,6 @@ bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bo return result; } -const char * PythonTextArea::textToAutocomplete(int * length) const { - if (!m_contentView.isAutocompleting()) { - return nullptr; - } - return m_contentView.textToAutocomplete(length); -} - void PythonTextArea::removeAutocompletion() { assert(m_contentView.isAutocompleting()); const char * autocompleteStart = m_contentView.cursorLocation(); diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 6c4765910..a641ded21 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -18,7 +18,6 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; - const char * textToAutocomplete(int * length = nullptr) const; bool isAutocompleting() const { return m_contentView.isAutocompleting(); } protected: class ContentView : public TextArea::ContentView { @@ -32,7 +31,7 @@ protected: App * pythonDelegate() { return m_pythonDelegate; } void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } bool isAutocompleting() const { return m_autocomplete; } - const char * textToAutocomplete(int * length = nullptr) const; + const char * textToAutocomplete() const; void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); void clearRect(KDContext * ctx, KDRect rect) const override; From ad5c998b97b9a1af51fd7823fc79466b3a628add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 16:09:59 +0100 Subject: [PATCH 177/453] [apps/code] Add module names to the builtins --- apps/code/variable_box_controller.cpp | 8 +++++++- apps/code/variable_box_controller.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 9221b0e15..d2208b8f1 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -84,7 +84,6 @@ typedef struct _mp_reader_mem_t { void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) - //TODO LEA add modules // Reset the node counts m_currentScriptNodesCount = 0; @@ -110,6 +109,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, {"class", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_cmath), ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, {"continue", ScriptNode::Type::Variable}, @@ -146,15 +146,18 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha {"in", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_ion), ScriptNode::Type::Variable}, {"is", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_iter), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_kandinsky), ScriptNode::Type::Variable}, {"lambda", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_len), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_list), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_locals), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_map), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_math), ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_max), ScriptNode::Type::Function}, //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_min), ScriptNode::Type::Function}, @@ -172,6 +175,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, {"raise", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_random), ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, {"return", ScriptNode::Type::Variable}, @@ -185,9 +189,11 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_sum), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_super), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_time), ScriptNode::Type::Variable}, {"True", ScriptNode::Type::Variable}, {"try", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_tuple), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_turtle), ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_type), ScriptNode::Type::Function}, //{qstr_str(MP_QSTR_vars), ScriptNode::Type::Function}, {"while", ScriptNode::Type::Variable}, diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 1df9dca94..aa0698ff4 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -32,7 +32,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; - constexpr static int k_totalBuiltinNodesCount = 94; + constexpr static int k_totalBuiltinNodesCount = 101; enum class NodeOrigin : uint8_t { CurrentScript, Builtins, From ac3a09bdeb325ac0e794ab343588f876b3c224a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 26 Mar 2020 16:48:17 +0100 Subject: [PATCH 178/453] [apps/code] Insert only the completing text when autocompleting --- apps/code/variable_box_controller.cpp | 11 ++++++----- apps/code/variable_box_controller.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d2208b8f1..5d83f6856 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -90,6 +90,11 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha m_builtinNodesCount = 0; m_importedNodesCount = 0; + if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { + textToAutocompleteLength = strlen(textToAutocomplete); + } + m_shortenResultBytesCount = textToAutocomplete == nullptr ? 0 : textToAutocompleteLength; + // Add buitin nodes static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, @@ -239,10 +244,6 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha // Keep track of DEF tokens to differentiate between variables and functions bool defToken = false; - if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { - textToAutocompleteLength = strlen(textToAutocomplete); - } - while (lex->tok_kind != MP_TOKEN_END) { // Keep only MP_TOKEN_NAME tokens if (lex->tok_kind == MP_TOKEN_NAME) { @@ -435,7 +436,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { assert(m_importedNodesCount <= k_maxScriptNodesCount); m_selectableTableView.deselectTable(); ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); - insertTextInCaller(selectedScriptNode->name(), selectedScriptNode->nameLength()); + insertTextInCaller(selectedScriptNode->name() + m_shortenResultBytesCount, selectedScriptNode->nameLength() - m_shortenResultBytesCount); if (selectedScriptNode->type() == ScriptNode::Type::Function) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index aa0698ff4..810e247b2 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -76,6 +76,7 @@ private: int m_currentScriptNodesCount; int m_builtinNodesCount; int m_importedNodesCount; + int m_shortenResultBytesCount; // This is used to send only the completing text when we are autocompleting }; } From fd1b0e08eeadd5033dad6bf2be7f70ba570ca775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 27 Mar 2020 11:18:55 +0100 Subject: [PATCH 179/453] [escher/text_field] Fix insertion size computation --- escher/src/text_field.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index ebd9bd48a..aa1d128b7 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -130,8 +130,8 @@ bool TextField::ContentView::insertTextAtLocation(const char * text, char * loca memmove(location + textLength, location, (s_draftTextBuffer + m_currentDraftTextLength + 1) - location); // Caution! One byte will be overridden by the null-terminating char of strlcpy - size_t copySize = std::min(textLength, (s_draftTextBuffer + m_draftTextBufferSize) - location); - char * overridenByteLocation = location + copySize; + size_t copySize = std::min(textLength + 1, (s_draftTextBuffer + m_draftTextBufferSize) - location); + char * overridenByteLocation = location + copySize - 1; char overridenByte = *overridenByteLocation; strlcpy(location, text, copySize); *overridenByteLocation = overridenByte; From 5a37b1df53ca5d3a6f5c72eebcbb48a6fb02b21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 27 Mar 2020 11:41:16 +0100 Subject: [PATCH 180/453] [apps/code] Use Default color at beginning of autocompleted token --- apps/code/python_text_area.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 42cd2552f..758b70326 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -22,6 +22,7 @@ constexpr KDColor StringColor = KDColor::RGB24(0x032f62); constexpr KDColor AutocompleteColor = KDColorRed; constexpr KDColor BackgroundColor = KDColorWhite; constexpr KDColor HighlightColor = Palette::Select; +constexpr KDColor DefaultColor = KDColorBlack; static inline KDColor TokenColor(mp_token_kind_t tokenKind) { if (tokenKind == MP_TOKEN_STRING) { @@ -39,7 +40,7 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) { if (tokenKind >= MP_TOKEN_DEL_EQUAL && tokenKind <= MP_TOKEN_DEL_MINUS_MORE) { return OperatorColor; } - return KDColorBlack; + return DefaultColor; } static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { @@ -106,6 +107,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char return; } + const char * autocompleteStart = m_autocomplete ? m_cursorLocation : nullptr; + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, byteLength - (firstNonSpace - text), 0); @@ -132,12 +135,16 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char } tokenLength = TokenLength(lex, tokenFrom); tokenEnd = tokenFrom + tokenLength; + + // If the token is being autocompleted, use DefaultColor + KDColor color = (tokenFrom <= autocompleteStart && autocompleteStart < tokenEnd) ? DefaultColor : TokenColor(lex->tok_kind); + LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind); drawStringAt(ctx, line, UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom), tokenFrom, tokenLength, - TokenColor(lex->tok_kind), + color, BackgroundColor, selectionStart, selectionEnd, @@ -149,6 +156,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char tokenFrom += tokenLength; + // Even if the token is being autocompleted, use CommentColor if (tokenFrom < text + byteLength) { LOG_DRAW("Draw comment \"%.*s\" from %d\n", byteLength - (tokenFrom - text), firstNonSpace, tokenFrom); drawStringAt(ctx, line, @@ -167,9 +175,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char } // Redraw the autocompleted word in the right color - const char * autocompleteStart = m_cursorLocation; - assert(!m_autocomplete || autocompleteStart != text); - if (m_autocomplete && autocompleteStart > text && autocompleteStart < text + byteLength) { + if (m_autocomplete && autocompleteStart >= text && autocompleteStart < text + byteLength) { const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); drawStringAt( ctx, From af3394d35a253fd3dadea23f98aa36a616f11c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 27 Mar 2020 11:57:02 +0100 Subject: [PATCH 181/453] [apps/code] Better event handling for autocompletion --- apps/code/python_text_area.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 758b70326..46988f079 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -209,8 +209,7 @@ KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, bool PythonTextArea::handleEvent(Ion::Events::Event event) { if (m_contentView.isAutocompleting()) { // Handle event with autocompletion - if (event == Ion::Events::Toolbox || event == Ion::Events::Var) { - } else if (event == Ion::Events::Right + if (event == Ion::Events::Right || event == Ion::Events::ShiftRight || event == Ion::Events::OK) { @@ -221,12 +220,26 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { scrollToCursor(); return true; } + } else if (event == Ion::Events::Toolbox + || event == Ion::Events::Var + || event == Ion::Events::Shift + || event == Ion::Events::Alpha + || event == Ion::Events::OnOff) + { } else { removeAutocompletion(); m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); + if (event == Ion::Events::Back) { + // Do not process the event more + return true; + } } } - return TextArea::handleEvent(event); + bool result = TextArea::handleEvent(event); + if (event == Ion::Events::Backspace) { + addAutocompletion(); + } + return result; } bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) { From 6311f408b453442eed50ff4d9bd5b1c039503c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 31 Mar 2020 15:41:04 +0200 Subject: [PATCH 182/453] [escher/text_area] Fix overlap in textInsert --- escher/src/text_area.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index 8d4239df8..ab2162a63 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -237,11 +237,16 @@ void TextArea::Text::insertText(const char * s, int textLength, char * location) assert(m_buffer != nullptr); assert(location >= m_buffer && location < m_buffer + m_bufferSize - 1); assert(strlen(m_buffer) + textLength < m_bufferSize); + // assert the text to insert does not overlap the location where to insert + assert(s >= location || s + textLength < location); + /* The text to insert might be located after the insertion location, in which + * case we cannot simply do a memmove, as s will be shifted by the copy. */ + bool noShift = (s + textLength < location) || (s > m_buffer + m_bufferSize); size_t sizeToMove = strlen(location) + 1; assert(location + textLength + sizeToMove <= m_buffer + m_bufferSize); memmove(location + textLength, location, sizeToMove); - memmove(location, s, textLength); + memmove(location, s + (noShift ? 0 : textLength), textLength); } void TextArea::Text::insertSpacesAtLocation(int numberOfSpaces, char * location) { From 78a747d9c610027e494ea2e037ec5734f8cacff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 27 Mar 2020 18:25:53 +0100 Subject: [PATCH 183/453] [apps/code] Start loading imported variables in var box --- apps/code/script_template.cpp | 37 ++++++----- apps/code/variable_box_controller.cpp | 91 ++++++++++++++++++++++++--- apps/code/variable_box_controller.h | 1 + 3 files changed, 108 insertions(+), 21 deletions(-) diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index 971b44496..2ec6cf4aa 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -5,21 +5,30 @@ namespace Code { constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import * )"); -constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"(from math import * -from turtle import * -def squares(angle=0.5): - reset() - L=330 - speed(10) - penup() - goto(-L/2,-L/2) - pendown() - for i in range(660): - forward(L) - left(90+angle) - L=L-L*sin(angle*pi/180) - hideturtle())"); +constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( +from math import sin as stew, cos as cabbage)"); +/*constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( +import math +import math as m +import math, cmath +import math as m, cmath as cm +from math import * +from math import sin +from math import sin as stew +from math import sin, cos +from math import sin as stew, cos as cabbage)");*/ +/* +import math // math +import math as m // math +import math, cmath // math math +import math as m, cmath as cm +from math import * +from math import sin +from math import sin as stew +from math import sin, cos +from math import sin as stew, cos as cabbage +*/ constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set # N_iteration: degree of precision import kandinsky diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 5d83f6856..4db55f6f8 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -17,6 +17,16 @@ extern "C" { namespace Code { static inline int minInt(int x, int y) { return x < y ? x : y; } + // Got these in python/py/src/compile.cpp compiled file +constexpr static uint PN_import_name = 14; // import math // import math as m // import math, cmath // import math as m, cmath as cm +constexpr static uint PN_import_from = 15; // from math import * // from math import sin // from math import sin as stew // from math import sin, cos // from math import sin as stew, cos as cabbage +constexpr static uint PN_import_stmt = 92; // ? +constexpr static uint PN_import_from_2 = 93; // ? +constexpr static uint PN_import_from_2b = 94; // "from .foo import" +constexpr static uint PN_import_from_3 = 95; // ? +constexpr static uint PN_import_as_names_paren = 96; // ? +constexpr static uint PN_import_as_name = 99; // sin as stew +constexpr static uint PN_import_as_names = 102; // ... import sin as stew, cos as cabbage //TODO LEA use this static bool shouldAddObject(const char * name, int maxLength) { @@ -81,6 +91,33 @@ typedef struct _mp_reader_mem_t { } mp_reader_mem_t; /* TODO end*/ + +void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode) { + + uint structKind = (uint) MP_PARSE_NODE_STRUCT_KIND(parseNode); + if (structKind != PN_import_name + && structKind != PN_import_from + && structKind != PN_import_as_names + && structKind != PN_import_as_name) + { + return; + } + + // TODO from ScriptStore + size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); + for (int i = 0; i < childNodesCount; i++) { + mp_parse_node_t child = parseNode->nodes[i]; + if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { + uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child); + const char * id = qstr_str(arg); + // TODO LEA check if not already present + addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); + } else if (MP_PARSE_NODE_IS_STRUCT(child)) { + addNodesFromImportMaybe((mp_parse_node_struct_t *)child); + } + } +} + void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) @@ -219,7 +256,47 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } // Load the imported variables and functions - //TODO LEA +// TODO TODO TODO LEA + +#if 1 + if (scriptIndex < 0) { + //TODO LEA load imported in console + } else { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + const char * parseStart = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); + while (*parseStart == '\n' && *parseStart != 0) { + parseStart++; + } + //TODO LEA also look for ";" ? But what if in string? + const char * parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); + + while (parseStart != parseEnd) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(0, parseStart, parseEnd - parseStart, 0); + mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_SINGLE_INPUT); + mp_parse_node_t pn = parseTree.root; + + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + addNodesFromImportMaybe((mp_parse_node_struct_t *) pn); + } + + mp_parse_tree_clear(&parseTree); + + if (*parseEnd == 0) { + nlr_pop(); + goto importCurrent; + } + parseStart = parseEnd + 1; // Go after the \n + while (*parseStart == '\n' && *parseStart != 0) { + parseStart++; + } + parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); + } + } + } +importCurrent: + +#endif #if 1 if (scriptIndex < 0) { @@ -286,12 +363,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha /* This is a trick to get the token position in the text. The -2 was * found from stepping in the code and trying. */ // TODO LEA FIXME - tokenInText -= lex->chr1 == -1 ? (lex->chr2 == -1 ? 0 : 1): 2; - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; - } - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; + for (int i = 0; i < 3; i++) { + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } else { + break; + } } assert(strncmp(tokenInText, name, nameLength) == 0); addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 810e247b2..e352d722a 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -65,6 +65,7 @@ private: bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); + void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; From a0f1d0f24ba66b9c08083cfc5b58935db5bab73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 31 Mar 2020 16:42:56 +0200 Subject: [PATCH 184/453] [apps/code] Start getting importations in the variable box --- apps/code/script_template.cpp | 4 +++- apps/code/variable_box_controller.cpp | 32 ++++++++++++++++++++++----- apps/code/variable_box_controller.h | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index 2ec6cf4aa..488cd362a 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -6,7 +6,9 @@ constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import * )"); constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( -from math import sin as stew, cos as cabbage)"); +#from math import sin as stew, cos as cabbage +from math import * +)"); /*constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( import math diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 4db55f6f8..54fe1cb0a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -92,10 +92,12 @@ typedef struct _mp_reader_mem_t { /* TODO end*/ -void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode) { +void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { uint structKind = (uint) MP_PARSE_NODE_STRUCT_KIND(parseNode); - if (structKind != PN_import_name + bool structKindIsImportWithoutFrom = structKind == PN_import_name; + + if (!structKindIsImportWithoutFrom && structKind != PN_import_from && structKind != PN_import_as_names && structKind != PN_import_as_name) @@ -103,6 +105,8 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par return; } + bool loadModuleContent = structKindIsImportWithoutFrom; + // TODO from ScriptStore size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); for (int i = 0; i < childNodesCount; i++) { @@ -110,12 +114,28 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child); const char * id = qstr_str(arg); - // TODO LEA check if not already present - addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); + if ((strncmp(textToAutocomplete, id, textToAutocompleteLength) == 0) + && (*(id + textToAutocompleteLength) != 0)) + { + // TODO LEA check if not already present + addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); + } } else if (MP_PARSE_NODE_IS_STRUCT(child)) { - addNodesFromImportMaybe((mp_parse_node_struct_t *)child); + addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); + } else if (MP_PARSE_NODE_IS_TOKEN(child) && MP_PARSE_NODE_IS_TOKEN_KIND(child, MP_TOKEN_OP_STAR)) { + /* Parsing something like from math import * + * -> Load all the module content */ + loadModuleContent = true; } } + + if (loadModuleContent) { + assert(childNodesCount > 0); + mp_parse_node_t moduleName = parseNode->nodes[0]; + assert(MP_PARSE_NODE_IS_LEAF(moduleName) && MP_PARSE_NODE_LEAF_KIND(moduleName) == MP_PARSE_NODE_ID); + + + } } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { @@ -277,7 +297,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha mp_parse_node_t pn = parseTree.root; if (MP_PARSE_NODE_IS_STRUCT(pn)) { - addNodesFromImportMaybe((mp_parse_node_struct_t *) pn); + addNodesFromImportMaybe((mp_parse_node_struct_t *) pn, textToAutocomplete, textToAutocompleteLength); } mp_parse_tree_clear(&parseTree); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index e352d722a..68d575463 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -65,7 +65,7 @@ private: bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); - void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode); + void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; From 4cb947759d8b9491708d9a0cb28b7c14b4ff5472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 1 Apr 2020 14:32:01 +0200 Subject: [PATCH 185/453] [apps/code] Get imported modules in the variable box --- apps/code/python_toolbox.cpp | 12 ++++++++++++ apps/code/python_toolbox.h | 4 ++++ apps/code/variable_box_controller.cpp | 27 +++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index bdb79c4db..e9ad5ccd6 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -437,6 +437,18 @@ PythonToolbox::PythonToolbox() : { } +const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const { + assert(numberOfNodes != nullptr); + for (ToolboxMessageTree t : modulesChildren) { + if (strcmp(I18n::translate(t.label()), name)) { + *numberOfNodes = t.numberOfChildren(); + assert(*numberOfNodes > 0); + return static_cast(t.children(0)); + } + } + return nullptr; +} + bool PythonToolbox::handleEvent(Ion::Events::Event event) { if (Toolbox::handleEvent(event)) { return true; diff --git a/apps/code/python_toolbox.h b/apps/code/python_toolbox.h index 0889f2ebf..222a9de3a 100644 --- a/apps/code/python_toolbox.h +++ b/apps/code/python_toolbox.h @@ -10,7 +10,11 @@ namespace Code { class PythonToolbox : public Toolbox { public: + // PythonToolbox PythonToolbox(); + const ToolboxMessageTree * moduleChildren(const char * name, int * numberOfNodes) const; + + // Toolbox bool handleEvent(Ion::Events::Event event) override; protected: KDCoordinate rowHeight(int j) override; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 54fe1cb0a..c03902985 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -1,4 +1,5 @@ #include "variable_box_controller.h" +#include "python_toolbox.h" #include "script.h" #include "app.h" #include "../shared/toolbox_helpers.h" @@ -130,11 +131,29 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par } if (loadModuleContent) { + // We fetch variables and functions imported from a module or a script assert(childNodesCount > 0); - mp_parse_node_t moduleName = parseNode->nodes[0]; - assert(MP_PARSE_NODE_IS_LEAF(moduleName) && MP_PARSE_NODE_LEAF_KIND(moduleName) == MP_PARSE_NODE_ID); - - + mp_parse_node_t importationSource = parseNode->nodes[0]; + assert(MP_PARSE_NODE_IS_LEAF(importationSource) && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID); + const char * importationSourceName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSource)); + int numberOfChildren = 0; + const ToolboxMessageTree * moduleChildren = static_cast(App::app()->toolboxForInputEventHandler(nullptr))->moduleChildren(importationSourceName, &numberOfChildren); + if (moduleChildren != nullptr) { + /* If the importation source is a module, get the nodes from the toolbox + * We skip the 3 forst nodes, which are "import ...", "from ... import *" + * and "....function". */ + constexpr int numberOfNodesToSkip = 3; + assert(numberOfChildren > numberOfNodesToSkip); + for (int i = 3; i < numberOfChildren; i++) { + // TODO LEA check if not already present + const ToolboxMessageTree * currentTree = moduleChildren + i; + const char * name = I18n::translate(currentTree->label()); + addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); + } + } else if (false) { + //TODO LEA + // else, try fetching the nodes from a script + } } } From d2bfe01cd4e89476ff6fbfe6145c687cefec26b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 1 Apr 2020 14:58:30 +0200 Subject: [PATCH 186/453] [apps/code] VariableBoxController::contains method --- apps/code/variable_box_controller.cpp | 80 ++++++++++++++------------- apps/code/variable_box_controller.h | 2 + 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c03902985..010f59cef 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -368,50 +368,30 @@ importCurrent: int nameLength = lex->vstr.len; // Check if the token completes the text to autocomplete - bool canKeepChecking = textToAutocomplete == nullptr; - if (!canKeepChecking) { + bool tokenAutocompletesText = textToAutocomplete == nullptr; + if (!tokenAutocompletesText) { + // TODO LEA Caution with aprentheses (when comparing rect and rect(r) if (textToAutocompleteLength < nameLength && strncmp(name, textToAutocomplete, textToAutocompleteLength) == 0) { - canKeepChecking = true; + tokenAutocompletesText = true; } } - if (canKeepChecking) { - bool alreadyInVarBox = false; - // TODO LEA speed this up with dichotomia? - NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - ScriptNode * nodes = nodesForOrigin(origin); - for (int i = 0; i < nodesCount; i++) { - ScriptNode * matchingNode = nodes + i; - int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); - if (comparisonResult == 0) { - alreadyInVarBox = true; - break; - } - if (comparisonResult > 0) { - break; - } - } - if (alreadyInVarBox) { + if (tokenAutocompletesText && !contains(name, nameLength)) { + /* If the token autocompletes the text and it is not already in the + * variable box, add it. */ + + /* This is a trick to get the token position in the text. The -2 was + * found from stepping in the code and trying. */ + // TODO LEA FIXME + for (int i = 0; i < 3; i++) { + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } else { break; } } - - if (!alreadyInVarBox) { - /* This is a trick to get the token position in the text. The -2 was - * found from stepping in the code and trying. */ - // TODO LEA FIXME - for (int i = 0; i < 3; i++) { - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; - } else { - break; - } - } - assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); - } + assert(strncmp(tokenInText, name, nameLength) == 0); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); } } @@ -474,6 +454,7 @@ int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { } int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe, bool * strictlyStartsWith) { + // TODO LEA compare until parenthesis assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); const char * nodeName = node->name(); const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); @@ -599,4 +580,29 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co *currentNodeCount = *currentNodeCount + 1; } +bool VariableBoxController::contains(const char * name, int nameLength) { + bool alreadyInVarBox = false; + // TODO LEA speed this up with dichotomia? + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + ScriptNode * nodes = nodesForOrigin(origin); + for (int i = 0; i < nodesCount; i++) { + ScriptNode * matchingNode = nodes + i; + int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); + if (comparisonResult == 0) { + alreadyInVarBox = true; + break; + } + if (comparisonResult > 0) { + break; + } + } + if (alreadyInVarBox) { + break; + } + } + return alreadyInVarBox; +} + } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 68d575463..ac928fc46 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -67,6 +67,8 @@ private: void insertTextInCaller(const char * text, int textLength = -1); void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + bool contains(const char * name, int nameLength); + ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From b11bab40453255cfdd0fc8ac2fa6193afd01ab85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 1 Apr 2020 15:22:52 +0200 Subject: [PATCH 187/453] [apps/code] Refactoring --- apps/code/variable_box_controller.cpp | 71 +++++++++++++++++---------- apps/code/variable_box_controller.h | 4 ++ 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 010f59cef..c2971c418 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -113,14 +113,8 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par for (int i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { - uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child); - const char * id = qstr_str(arg); - if ((strncmp(textToAutocomplete, id, textToAutocompleteLength) == 0) - && (*(id + textToAutocompleteLength) != 0)) - { - // TODO LEA check if not already present - addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); - } + const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); } else if (MP_PARSE_NODE_IS_TOKEN(child) && MP_PARSE_NODE_IS_TOKEN_KIND(child, MP_TOKEN_OP_STAR)) { @@ -145,10 +139,9 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par constexpr int numberOfNodesToSkip = 3; assert(numberOfChildren > numberOfNodesToSkip); for (int i = 3; i < numberOfChildren; i++) { - // TODO LEA check if not already present const ToolboxMessageTree * currentTree = moduleChildren + i; const char * name = I18n::translate(currentTree->label()); - addNode(ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); } } else if (false) { //TODO LEA @@ -367,21 +360,13 @@ importCurrent: const char * name = lex->vstr.buf; int nameLength = lex->vstr.len; - // Check if the token completes the text to autocomplete - bool tokenAutocompletesText = textToAutocomplete == nullptr; - if (!tokenAutocompletesText) { - // TODO LEA Caution with aprentheses (when comparing rect and rect(r) - if (textToAutocompleteLength < nameLength && strncmp(name, textToAutocomplete, textToAutocompleteLength) == 0) { - tokenAutocompletesText = true; - } - } - - if (tokenAutocompletesText && !contains(name, nameLength)) { - /* If the token autocompletes the text and it is not already in the - * variable box, add it. */ - - /* This is a trick to get the token position in the text. The -2 was - * found from stepping in the code and trying. */ + /* If the token autocompletes the text and it is not already in the + * variable box, add it. */ + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { + /* This is a trick to get the token position in the text, as name and + * nameLength are temporary variables that will be overriden when the + * lexer continues lexing or is destroyed. + * The -2 was found from stepping in the code and trying. */ // TODO LEA FIXME for (int i = 0; i < 3; i++) { if (strncmp(tokenInText, name, nameLength) != 0) { @@ -457,7 +442,7 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, // TODO LEA compare until parenthesis assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); const char * nodeName = node->name(); - const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); + const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); //TODO LEA needed ? const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; const int comparisonLength = minInt(nameLength, nodeNameLength); int result = strncmp(nodeName, name, comparisonLength); @@ -549,6 +534,37 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength sender()->handleEventWithText(commandBuffer); } +bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength) { + if (textToAutocomplete != nullptr) { + /* Check that nodeName autocompletes the text to autocomplete + * - The start of nodeName must be equal to the text to autocomplete */ + if (strncmp(textToAutocomplete, nodeName, textToAutocompleteLength) != 0) { + return false; + } + /* - nodeName should be longer than the text to autocomplete. Beware of the + * case where nodeName is textToAutocompleteLength(parameters), which we do + * not want to accept. */ + char firstCharAfterAutocompletion = *(nodeName + textToAutocompleteLength); + if (firstCharAfterAutocompletion == 0 || firstCharAfterAutocompletion == '(') { + return false; + } + } + + // Check that node name is not already present in the variable box. + if (contains(nodeName, nodeNameLength)) { + return false; + } + + return true; +} + +void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, int scriptIndex) { + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { + // Add the node in alphabetical order + addNode(type, origin, nodeName, nodeNameLength, scriptIndex); + } +} + void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); int * currentNodeCount = nodesCountPointerForOrigin(origin); @@ -580,8 +596,9 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co *currentNodeCount = *currentNodeCount + 1; } -bool VariableBoxController::contains(const char * name, int nameLength) { +bool VariableBoxController::contains(const char * name, int nameLengthMaybe) { bool alreadyInVarBox = false; + const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; // TODO LEA speed this up with dichotomia? NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; for (NodeOrigin origin : origins) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index ac928fc46..eb10c0d72 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -66,6 +66,10 @@ private: bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); + /* Add a node if it completes the text to autocomplete and if it is not + * already contained in the variable box. */ + bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); + void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); bool contains(const char * name, int nameLength); From 2b83d9b9528d25ec4ed7f19e6575edb7b3202cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 1 Apr 2020 15:46:55 +0200 Subject: [PATCH 188/453] [apps/code] Continue cleaning and refactoring in variable box --- apps/code/variable_box_controller.cpp | 74 +++++++++++---------------- apps/code/variable_box_controller.h | 3 ++ 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c2971c418..e4437a2cd 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -143,17 +143,18 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par const char * name = I18n::translate(currentTree->label()); checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); } - } else if (false) { - //TODO LEA - // else, try fetching the nodes from a script + } else { + // Try fetching the nodes from a script + Script importedScript = m_scriptStore->scriptNamed(importationSourceName); + if (!importedScript.isNull()) { + //TODO LEA + + } } } } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { - //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c - //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) - // Reset the node counts m_currentScriptNodesCount = 0; m_builtinNodesCount = 0; @@ -164,6 +165,19 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } m_shortenResultBytesCount = textToAutocomplete == nullptr ? 0 : textToAutocompleteLength; + loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); + + if (scriptIndex < 0) { + //TODO LEA load imported in console + } else { + loadCurrentAndImportedVariableInScript(m_scriptStore->scriptAtIndex(scriptIndex), textToAutocomplete, textToAutocompleteLength); + } +} + +void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { + //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c + //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) + // Add buitin nodes static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, @@ -286,17 +300,14 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha break; } } +} - // Load the imported variables and functions -// TODO TODO TODO LEA - -#if 1 - if (scriptIndex < 0) { - //TODO LEA load imported in console - } else { +void VariableBoxController::loadCurrentAndImportedVariableInScript(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { + { + // Load the imported variables and functions nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - const char * parseStart = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); + const char * parseStart = script.scriptContent(); while (*parseStart == '\n' && *parseStart != 0) { parseStart++; } @@ -326,16 +337,10 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } } } + importCurrent: - -#endif - -#if 1 - if (scriptIndex < 0) { - //TODO LEA - return; - } - const char * script = m_scriptStore->scriptAtIndex(scriptIndex).scriptContent(); + // Load the variables and functions from the current script + const char * scriptContent = script.scriptContent(); /* To find variable and funtion names: we lex the script and keep all * MP_TOKEN_NAME that complete the text to autocomplete and are not already in @@ -346,7 +351,7 @@ importCurrent: if (nlr_push(&nlr) == 0) { // 1) Lex the script - _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, script, strlen(script), false); + _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); // This is a trick to get the token position in the text. const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); @@ -362,7 +367,7 @@ importCurrent: /* If the token autocompletes the text and it is not already in the * variable box, add it. */ - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { /* This is a trick to get the token position in the text, as name and * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. @@ -376,7 +381,7 @@ importCurrent: } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, scriptIndex); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, 1/* TODO LEA*/); } } @@ -395,23 +400,6 @@ importCurrent: mp_lexer_free(lex); nlr_pop(); } -#else - m_scriptNodesCount = 1; - m_scriptStore->scanScriptsForFunctionsAndVariables( - this, - [](void * context, const char * functionName, int scriptIndex) { - if (!shouldAddObject(functionName, k_maxScriptObjectNameSize)) { - return; - } - VariableBoxController * cvc = static_cast(context); - cvc->addFunctionAtIndex(functionName, scriptIndex);}, - [](void * context, const char * variableName, int scriptIndex) { - if (!shouldAddObject(variableName, k_maxScriptObjectNameSize)) { - return; - } - VariableBoxController * cvc = static_cast(context); - cvc->addVariableAtIndex(variableName, scriptIndex);}); -#endif } const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index eb10c0d72..d0ec3c233 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -65,6 +65,9 @@ private: bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); + + void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); + void loadCurrentAndImportedVariableInScript(Script script, const char * textToAutocomplete, int textToAutocompleteLength); void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ From 0b0a7227a65cb017f625dea097fc129d85767f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 1 Apr 2020 16:23:54 +0200 Subject: [PATCH 189/453] =?UTF-8?q?[apps/code=E2=80=93=20Fix=20typo=20in?= =?UTF-8?q?=20python=5Ftoolbox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/code/python_toolbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index e9ad5ccd6..1313a7932 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -440,7 +440,7 @@ PythonToolbox::PythonToolbox() : const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const { assert(numberOfNodes != nullptr); for (ToolboxMessageTree t : modulesChildren) { - if (strcmp(I18n::translate(t.label()), name)) { + if (strcmp(I18n::translate(t.label()), name) == 0) { *numberOfNodes = t.numberOfChildren(); assert(*numberOfNodes > 0); return static_cast(t.children(0)); From 0428c814e8f93ca3ef400826b4f2ccab222dab19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 09:56:00 +0200 Subject: [PATCH 190/453] [apps/code] Fix array shifting --- apps/code/variable_box_controller.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index e4437a2cd..8c2184dfd 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -346,7 +346,6 @@ importCurrent: * MP_TOKEN_NAME that complete the text to autocomplete and are not already in * the builtins or imported scripts. */ - m_currentScriptNodesCount = 0; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -575,7 +574,7 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co } // Shift all the following nodes - for (int i = *currentNodeCount; i >= insertionIndex; i--) { + for (int i = *currentNodeCount - 1; i >= insertionIndex; i--) { nodes[i+1] = nodes[i]; } // Add the node From 4f24a7d8709203fd7dcc7426cf8ea69b4c1c797f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 09:56:39 +0200 Subject: [PATCH 191/453] [apps/code] Use nodesForOrigin --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8c2184dfd..a2acc8a52 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -561,7 +561,7 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co } /* We want to insert the node in alphabetical order, so we look for the * insertion index. */ - ScriptNode * nodes = origin == NodeOrigin::CurrentScript ? m_currentScriptNodes : m_importedNodes; + ScriptNode * nodes = nodesForOrigin(origin); int insertionIndex = 0; while (insertionIndex < *currentNodeCount) { ScriptNode * node = nodes + insertionIndex; From 1e59abf55b6f6e65e34317549c19ed937e8b3a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 10:47:27 +0200 Subject: [PATCH 192/453] [apps/code] Load global and imported variables from imported scripts --- apps/code/variable_box_controller.cpp | 84 +++++++++++++++++++++++++-- apps/code/variable_box_controller.h | 5 +- 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index a2acc8a52..4526e0946 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -19,6 +19,9 @@ namespace Code { static inline int minInt(int x, int y) { return x < y ? x : y; } // Got these in python/py/src/compile.cpp compiled file +constexpr static uint PN_file_input_2 = 1; +constexpr static uint PN_funcdef = 3; +constexpr static uint PN_expr_stmt = 5; constexpr static uint PN_import_name = 14; // import math // import math as m // import math, cmath // import math as m, cmath as cm constexpr static uint PN_import_from = 15; // from math import * // from math import sin // from math import sin as stew // from math import sin, cos // from math import sin as stew, cos as cabbage constexpr static uint PN_import_stmt = 92; // ? @@ -93,7 +96,7 @@ typedef struct _mp_reader_mem_t { /* TODO end*/ -void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { +bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { uint structKind = (uint) MP_PARSE_NODE_STRUCT_KIND(parseNode); bool structKindIsImportWithoutFrom = structKind == PN_import_name; @@ -103,7 +106,7 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par && structKind != PN_import_as_names && structKind != PN_import_as_name) { - return; + return false; } bool loadModuleContent = structKindIsImportWithoutFrom; @@ -145,13 +148,13 @@ void VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par } } else { // Try fetching the nodes from a script - Script importedScript = m_scriptStore->scriptNamed(importationSourceName); + Script importedScript = m_scriptStore->scriptNamed("polynomial.py"); //TODO LEA if (!importedScript.isNull()) { - //TODO LEA - + loadGlobalAndImportedVariableInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); } } } + return true; } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { @@ -401,6 +404,77 @@ importCurrent: } } +const char * structID(mp_parse_node_struct_t *structNode) { + // Find the id child node, which stores the struct's name + size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode); + if (childNodesCount < 1) { + return nullptr; + } + mp_parse_node_t child = structNode->nodes[0]; + if (MP_PARSE_NODE_IS_LEAF(child) + && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) + { + uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child); + return qstr_str(arg); + } + return nullptr; +} + + +void VariableBoxController::storeImportedStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength) { + assert(structKind == PN_funcdef || structKind == PN_expr_stmt); + // Find the id child node, which stores the struct's name + const char * id = structID(pns); + if (id == nullptr) { + return; + } + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); +} + +void VariableBoxController::loadGlobalAndImportedVariableInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { + assert(!script.isNull()); + const char * scriptContent = script.scriptContent(); + assert(scriptContent != nullptr); + + // Handle lexer or parser errors with nlr. + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + + mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); + mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_parse_node_t pn = parseTree.root; + + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + mp_parse_node_struct_t * pns = (mp_parse_node_struct_t *)pn; + uint structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(pns); + if (structKind == PN_funcdef || structKind == PN_expr_stmt) { + // The script is only a single function or variable definition + storeImportedStruct(pns, structKind, textToAutocomplete, textToAutocompleteLength); + } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { + } else if (structKind == PN_file_input_2) { + /* At this point, if the script node is not of type "file_input_2", it + * will not have main structures of the wanted type. */ + // Count the number of structs in child nodes. + size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (size_t i = 0; i < n; i++) { + mp_parse_node_t child = pns->nodes[i]; + if (MP_PARSE_NODE_IS_STRUCT(child)) { + mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); + structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); + if (structKind == PN_funcdef || structKind == PN_expr_stmt) { + storeImportedStruct(child_pns, structKind, textToAutocomplete, textToAutocompleteLength); + } else { + addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); + } + } + } + } + } + mp_parse_tree_clear(&parseTree); + nlr_pop(); + } +} + const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength) { const char * endOfText = UTF8Helper::EndOfWord(text); const int textLength = endOfText - text; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index d0ec3c233..5cb540550 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -68,14 +68,15 @@ private: void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentAndImportedVariableInScript(Script script, const char * textToAutocomplete, int textToAutocompleteLength); - void addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); + void loadGlobalAndImportedVariableInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength); + bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); // Returns true if this was an import structure /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); bool contains(const char * name, int nameLength); - + void storeImportedStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From 97aaff9430e82ef9d1ebb26b29d3d8eb68a66298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 11:17:54 +0200 Subject: [PATCH 193/453] [apps/code] Fix imported script variables fetching --- apps/code/app.cpp | 2 +- apps/code/script_store.cpp | 4 ++-- apps/code/script_store.h | 7 +++++-- apps/code/variable_box_controller.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/code/app.cpp b/apps/code/app.cpp index e0aa39738..4c017e220 100644 --- a/apps/code/app.cpp +++ b/apps/code/app.cpp @@ -61,7 +61,7 @@ void App::Snapshot::setOpt(const char * name, const char * value) { const char * scriptContent = separator; Code::ScriptTemplate script(scriptName, scriptContent); m_scriptStore.addScriptFromTemplate(&script); - m_scriptStore.scriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1 + ScriptStore::ScriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1 return; } if (strcmp(name, "lock-on-console") == 0) { diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 25b9dce67..64bec153a 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -13,7 +13,7 @@ constexpr char ScriptStore::k_scriptExtension[]; bool ScriptStore::ScriptNameIsFree(const char * baseName) { - return Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension).isNull(); + return ScriptBaseNamed(baseName).isNull(); } ScriptStore::ScriptStore() @@ -123,7 +123,7 @@ void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallba } const char * ScriptStore::contentOfScript(const char * name) { - Script script = scriptNamed(name); + Script script = ScriptNamed(name); if (script.isNull()) { return nullptr; } diff --git a/apps/code/script_store.h b/apps/code/script_store.h index 46273c57d..864fed483 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -23,8 +23,11 @@ public: Script scriptAtIndex(int index) { return Script(Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(k_scriptExtension, index)); } - Script scriptNamed(const char * name) { - return Script(Ion::Storage::sharedStorage()->recordNamed(name)); + static Script ScriptNamed(const char * fullName) { + return Script(Ion::Storage::sharedStorage()->recordNamed(fullName)); + } + static Script ScriptBaseNamed(const char * baseName) { + return Script(Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension)); } int numberOfScripts() { return Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(k_scriptExtension); diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 4526e0946..d8652258d 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -148,7 +148,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par } } else { // Try fetching the nodes from a script - Script importedScript = m_scriptStore->scriptNamed("polynomial.py"); //TODO LEA + Script importedScript = ScriptStore::ScriptBaseNamed(importationSourceName); if (!importedScript.isNull()) { loadGlobalAndImportedVariableInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); } From 332cd0ed3ac237f4344c9e0e71e4cecc8a6a27ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 12:04:17 +0200 Subject: [PATCH 194/453] [apps/code] Handle "from a.b import *" in the var box --- apps/code/variable_box_controller.cpp | 44 ++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d8652258d..757b14419 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -18,12 +18,13 @@ extern "C" { namespace Code { static inline int minInt(int x, int y) { return x < y ? x : y; } - // Got these in python/py/src/compile.cpp compiled file + +// Got these in python/py/src/compile.cpp compiled file constexpr static uint PN_file_input_2 = 1; constexpr static uint PN_funcdef = 3; constexpr static uint PN_expr_stmt = 5; constexpr static uint PN_import_name = 14; // import math // import math as m // import math, cmath // import math as m, cmath as cm -constexpr static uint PN_import_from = 15; // from math import * // from math import sin // from math import sin as stew // from math import sin, cos // from math import sin as stew, cos as cabbage +constexpr static uint PN_import_from = 15; // from math import * // from math import sin // from math import sin as stew // from math import sin, cos // from math import sin as stew, cos as cabbage // from a.b import * constexpr static uint PN_import_stmt = 92; // ? constexpr static uint PN_import_from_2 = 93; // ? constexpr static uint PN_import_from_2b = 94; // "from .foo import" @@ -31,6 +32,7 @@ constexpr static uint PN_import_from_3 = 95; // ? constexpr static uint PN_import_as_names_paren = 96; // ? constexpr static uint PN_import_as_name = 99; // sin as stew constexpr static uint PN_import_as_names = 102; // ... import sin as stew, cos as cabbage +constexpr static uint PN_dotted_name = 104; //TODO LEA use this static bool shouldAddObject(const char * name, int maxLength) { @@ -116,9 +118,11 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par for (int i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { + // Parsing something like import math const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { + // Parsing something like from math import sin addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); } else if (MP_PARSE_NODE_IS_TOKEN(child) && MP_PARSE_NODE_IS_TOKEN_KIND(child, MP_TOKEN_OP_STAR)) { /* Parsing something like from math import * @@ -131,8 +135,40 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par // We fetch variables and functions imported from a module or a script assert(childNodesCount > 0); mp_parse_node_t importationSource = parseNode->nodes[0]; - assert(MP_PARSE_NODE_IS_LEAF(importationSource) && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID); - const char * importationSourceName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSource)); + const char * importationSourceName = nullptr; + if (MP_PARSE_NODE_IS_LEAF(importationSource) && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID) { + // The importation source is "simple", for instance: from math import * + importationSourceName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSource)); + } else if (MP_PARSE_NODE_IS_STRUCT(importationSource)) { + mp_parse_node_struct_t * importationSourcePNS = (mp_parse_node_struct_t *)importationSource; + uint importationSourceStructKind = MP_PARSE_NODE_STRUCT_KIND(importationSourcePNS); + if (importationSourceStructKind == PN_dotted_name) { + /* The importation source is "complex", for instance: + * from matplotlib.pyplot import * + * FIXME The solution would be to build a single qstr for this name, + * such as in python/src/compile.c, function do_import_name, from line + * 1117 (found by searching PN_dotted_name). + * We might do this later, for now the only dotted name we might want to + * find is matplolib.pyplot, so we do a very specific search. */ + int numberOfSplitNames = MP_PARSE_NODE_STRUCT_NUM_NODES(importationSourcePNS); + if (numberOfSplitNames != 2) { + return true; + } + const char * importationSourceSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSourcePNS->nodes[0])); + if (strcmp(importationSourceSubName, "matplotlib") != 0) { //TODO LEA once rebased + + return true; + } + importationSourceSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSourcePNS->nodes[1])); + if (strcmp(importationSourceSubName, "pyplot") != 0) { //TODO LEA once rebased + + return true; + } + importationSourceName = "matplotlib.pyplot"; //TODO LEA once rebased + } else { + assert(false); //TODO LEA can we indeed assert? + } + } int numberOfChildren = 0; const ToolboxMessageTree * moduleChildren = static_cast(App::app()->toolboxForInputEventHandler(nullptr))->moduleChildren(importationSourceName, &numberOfChildren); if (moduleChildren != nullptr) { From 044dc706cbfbc4ae5a50f90d70d8121fb6b62cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 13:37:04 +0200 Subject: [PATCH 195/453] [apps/code] Remove unneeded code --- apps/code/script_store.cpp | 115 +------------------------- apps/code/script_store.h | 8 -- apps/code/variable_box_controller.cpp | 1 - 3 files changed, 1 insertion(+), 123 deletions(-) diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 64bec153a..c4062a9b6 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -1,23 +1,14 @@ #include "script_store.h" -#include "string.h" -#include - -extern "C" { -#include "py/lexer.h" -#include "py/nlr.h" -} namespace Code { constexpr char ScriptStore::k_scriptExtension[]; - bool ScriptStore::ScriptNameIsFree(const char * baseName) { return ScriptBaseNamed(baseName).isNull(); } -ScriptStore::ScriptStore() -{ +ScriptStore::ScriptStore() { addScriptFromTemplate(ScriptTemplate::Squares()); addScriptFromTemplate(ScriptTemplate::Parabola()); addScriptFromTemplate(ScriptTemplate::Mandelbrot()); @@ -34,94 +25,6 @@ bool ScriptStore::isFull() { return Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit; } -void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction, ScanCallback storeVariable) { - for (int scriptIndex = 0; scriptIndex < numberOfScripts(); scriptIndex++) { - - //Don't scan not loaded script - if (!scriptAtIndex(scriptIndex).importationStatus()){ - continue; - } - - // Handle lexer or parser errors with nlr. - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - const char * scriptContent = scriptAtIndex(scriptIndex).scriptContent(); - if (scriptContent == nullptr) { - continue; - } - mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); - mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_parse_node_t pn = parseTree.root; - - if (!MP_PARSE_NODE_IS_STRUCT(pn)) { - mp_parse_tree_clear(&parseTree); - nlr_pop(); - continue; - } - - mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; - - // The script is only a single function definition. - if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_functionDefinitionParseNodeStructKind) { - const char * id = structID(pns); - if (id == nullptr) { - continue; - } - storeFunction(context, id, scriptIndex); - mp_parse_tree_clear(&parseTree); - nlr_pop(); - continue; - } - - // The script is only a single global variable definition. - if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_expressionStatementParseNodeStructKind) { - const char * id = structID(pns); - if (id == nullptr) { - continue; - } - storeVariable(context, id, scriptIndex); - mp_parse_tree_clear(&parseTree); - nlr_pop(); - continue; - } - - if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) != k_fileInput2ParseNodeStructKind) { - // The script node is not of type "file_input_2", thus it will not have main - // structures of the wanted type. - mp_parse_tree_clear(&parseTree); - nlr_pop(); - continue; - } - - // Count the number of structs in child nodes. - - size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); - for (size_t i = 0; i < n; i++) { - mp_parse_node_t child = pns->nodes[i]; - if (MP_PARSE_NODE_IS_STRUCT(child)) { - mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); - if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_functionDefinitionParseNodeStructKind) { - const char * id = structID(child_pns); - if (id == nullptr) { - continue; - } - storeFunction(context, id, scriptIndex); - } else if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_expressionStatementParseNodeStructKind) { - const char * id = structID(child_pns); - if (id == nullptr) { - continue; - } - storeVariable(context, id, scriptIndex); - } - } - } - - mp_parse_tree_clear(&parseTree); - nlr_pop(); - } - } -} - const char * ScriptStore::contentOfScript(const char * name) { Script script = ScriptNamed(name); if (script.isNull()) { @@ -138,20 +41,4 @@ Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * sc return err; } -const char * ScriptStore::structID(mp_parse_node_struct_t *structNode) { - // Find the id child node, which stores the struct's name - size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode); - if (childNodesCount < 1) { - return nullptr; - } - mp_parse_node_t child = structNode->nodes[0]; - if (MP_PARSE_NODE_IS_LEAF(child) - && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) - { - uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child); - return qstr_str(arg); - } - return nullptr; -} - } diff --git a/apps/code/script_store.h b/apps/code/script_store.h index 864fed483..ae5f7dbf6 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -38,10 +38,6 @@ public: void deleteAllScripts(); bool isFull(); - /* Provide scripts content information */ - typedef void (* ScanCallback)(void * context, const char * p, int n); - void scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction,ScanCallback storeVariable); - /* MicroPython::ScriptProvider */ const char * contentOfScript(const char * name) override; @@ -54,10 +50,6 @@ private: * importation status (1 char), the default content "from math import *\n" * (20 char) and 10 char of free space. */ static constexpr int k_fullFreeSpaceSizeLimit = sizeof(Ion::Storage::record_size_t)+Script::k_defaultScriptNameMaxSize+k_scriptExtensionLength+1+20+10; - static constexpr size_t k_fileInput2ParseNodeStructKind = 1; - static constexpr size_t k_functionDefinitionParseNodeStructKind = 3; - static constexpr size_t k_expressionStatementParseNodeStructKind = 5; - const char * structID(mp_parse_node_struct_t *structNode); }; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 757b14419..246852b4d 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -113,7 +113,6 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par bool loadModuleContent = structKindIsImportWithoutFrom; - // TODO from ScriptStore size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); for (int i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; From 327dd0ac41aa4f6bcddd8c1f8a4f7c937c5cb49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 14:06:20 +0200 Subject: [PATCH 196/453] [apps/code] Cleaning 1 --- apps/code/variable_box_controller.cpp | 165 ++++++++++++++------------ apps/code/variable_box_controller.h | 19 ++- 2 files changed, 102 insertions(+), 82 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 246852b4d..3e4e25341 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -65,6 +65,94 @@ bool VariableBoxController::handleEvent(Ion::Events::Event event) { return NestedMenuController::handleEvent(event); } +void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { + assert(index >= 0 && index < numberOfRows()); + ScriptNodeCell * myCell = static_cast(cell); + myCell->setScriptNode(scriptNodeAtIndex(index)); +} + +void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { + // Reset the node counts + m_currentScriptNodesCount = 0; + m_builtinNodesCount = 0; + m_importedNodesCount = 0; + + if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { + textToAutocompleteLength = strlen(textToAutocomplete); + } + /* If we are autocompleting a text, we want the returned text to not include + * the beginning that is equal to the text to autocomplete. + * For instance, if we are displaying the variable box with the text "for" to + * autocomplete, when the user selects "forward", we want to insert the text + * "ward" only. + * While loading the functions and variables, we thus set + * m_shortenResultCharCount, the number of chars to cut from the text + * returned. */ + m_shortenResultCharCount = textToAutocomplete == nullptr ? 0 : textToAutocompleteLength; + + // Always load the builtin functions and variables + loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); + + if (scriptIndex < 0) { + //TODO LEA load imported in console + } else { + loadCurrentAndImportedVariableInScript(m_scriptStore->scriptAtIndex(scriptIndex), textToAutocomplete, textToAutocompleteLength); + } +} + +const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int * textToInsertLength) { + /* The text to autocomplete will most probably not be null-terminated. We thus + * say that the end of the text to autocomplete is the end if the current word, + * determined by the next space char or the next null char.*/ + const char * endOfText = UTF8Helper::EndOfWord(textToAutocomplete); + const int textLength = endOfText - textToAutocomplete; + assert(textLength >= 1); + + // First load variables and functions that complete the textToAutocomplete + loadFunctionsAndVariables(scriptIndex, textToAutocomplete, textLength); + if (numberOfRows() == 0) { + return nullptr; + } + + // Return the first node + ScriptNode * node = scriptNodeAtIndex(0); + const char * currentName = node->name(); + int currentNameLength = node->nameLength(); + if (currentNameLength < 0) { + currentNameLength = strlen(currentName); + } + // Assert the text we return does indeed autocomplete the text to autocomplete + assert(currentNameLength != textLength && strncmp(textToAutocomplete, currentName, textLength) == 0); + // Return the text without the beginning that matches the text to autocomplete + *textToInsertLength = currentNameLength - textLength; + return currentName + textLength; +} + +// PRIVATE METHODS + +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe, bool * strictlyStartsWith) { + // TODO LEA compare until parenthesis + assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); + const char * nodeName = node->name(); + const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); //TODO LEA needed ? + const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; + const int comparisonLength = minInt(nameLength, nodeNameLength); + int result = strncmp(nodeName, name, comparisonLength); + if (result != 0) { + return result; + } + if (nodeNameLength == nameLength) { + return 0; + } + bool nodeNameLengthStartsWithName = comparisonLength == nameLength; + if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { + *strictlyStartsWith = true; + } + return nodeNameLengthStartsWithName ? -1 : 1; +} + + + void VariableBoxController::didEnterResponderChain(Responder * previousFirstResponder) { /* This Code::VariableBoxController should always be called from an * environment where Python has already been inited. This way, we do not @@ -73,17 +161,7 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp assert(App::app()->pythonIsInited()); } -int VariableBoxController::numberOfRows() const { - assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); - assert(m_importedNodesCount <= k_maxScriptNodesCount); - return m_currentScriptNodesCount + m_builtinNodesCount + m_importedNodesCount; -} -void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { - assert(index >= 0 && index < numberOfRows()); - ScriptNodeCell * myCell = static_cast(cell); - myCell->setScriptNode(scriptNodeAtIndex(index)); -} /*TODO LEA very dirty * This is done to get the lexer position during lexing. As the _mp_reader_mem_t @@ -192,26 +270,6 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par return true; } -void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { - // Reset the node counts - m_currentScriptNodesCount = 0; - m_builtinNodesCount = 0; - m_importedNodesCount = 0; - - if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { - textToAutocompleteLength = strlen(textToAutocomplete); - } - m_shortenResultBytesCount = textToAutocomplete == nullptr ? 0 : textToAutocompleteLength; - - loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); - - if (scriptIndex < 0) { - //TODO LEA load imported in console - } else { - loadCurrentAndImportedVariableInScript(m_scriptStore->scriptAtIndex(scriptIndex), textToAutocomplete, textToAutocompleteLength); - } -} - void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) @@ -510,51 +568,6 @@ void VariableBoxController::loadGlobalAndImportedVariableInScriptAsImported(Scri } } -const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength) { - const char * endOfText = UTF8Helper::EndOfWord(text); - const int textLength = endOfText - text; - assert(textLength >= 1); - loadFunctionsAndVariables(scriptIndex, text, textLength); - if (numberOfRows() == 0) { - return nullptr; - } - ScriptNode * node = scriptNodeAtIndex(0); - const char * currentName = node->name(); - int currentNameLength = node->nameLength(); - if (currentNameLength < 0) { - currentNameLength = strlen(currentName); - } - assert(currentNameLength != textLength && strncmp(text, currentName, textLength) == 0); - *textToInsertLength = currentNameLength - textLength; - return currentName + textLength; -} - -int VariableBoxController::MaxNodesCountForOrigin(NodeOrigin origin) { - assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - return k_maxScriptNodesCount; -} - -int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe, bool * strictlyStartsWith) { - // TODO LEA compare until parenthesis - assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); - const char * nodeName = node->name(); - const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); //TODO LEA needed ? - const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; - const int comparisonLength = minInt(nameLength, nodeNameLength); - int result = strncmp(nodeName, name, comparisonLength); - if (result != 0) { - return result; - } - if (nodeNameLength == nameLength) { - return 0; - } - bool nodeNameLengthStartsWithName = comparisonLength == nameLength; - if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { - *strictlyStartsWith = true; - } - return nodeNameLengthStartsWithName ? -1 : 1; -} - int VariableBoxController::NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength) { bool strictlyStartsWith = false; int result = NodeNameCompare(node, name, nameLength, &strictlyStartsWith); @@ -614,7 +627,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { assert(m_importedNodesCount <= k_maxScriptNodesCount); m_selectableTableView.deselectTable(); ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); - insertTextInCaller(selectedScriptNode->name() + m_shortenResultBytesCount, selectedScriptNode->nameLength() - m_shortenResultBytesCount); + insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); if (selectedScriptNode->type() == ScriptNode::Type::Function) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 5cb540550..9876279fe 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -17,7 +17,9 @@ public: void didEnterResponderChain(Responder * previousFirstResponder) override; /* ListViewDataSource */ - int numberOfRows() const override; + int numberOfRows() const override { + return m_currentScriptNodesCount + m_builtinNodesCount + m_importedNodesCount; + } int reusableCellCount(int type) override { assert(type == 0); return k_maxNumberOfDisplayedRows; @@ -27,18 +29,23 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); - const char * autocompletionForText(int scriptIndex, const char * text, int * textToInsertLength); + const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int * textToInsertLength); + private: - constexpr static int k_maxScriptObjectNameSize = 100; + //TODO LEA use size_t + constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 - constexpr static int k_maxScriptNodesCount = 32; + constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 101; enum class NodeOrigin : uint8_t { CurrentScript, Builtins, Importation }; - static int MaxNodesCountForOrigin(NodeOrigin origin); + static int MaxNodesCountForOrigin(NodeOrigin origin) { + assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); + return k_maxScriptNodesCount; + } /* Returns: * - a negative int if the node name is before name in alphabetical * order @@ -87,7 +94,7 @@ private: int m_currentScriptNodesCount; int m_builtinNodesCount; int m_importedNodesCount; - int m_shortenResultBytesCount; // This is used to send only the completing text when we are autocompleting + int m_shortenResultCharCount; // This is used to send only the completing text when we are autocompleting }; } From 86435bf647ee3ea7418b5c08623446a4cc09a7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 16:22:02 +0200 Subject: [PATCH 197/453] [apps/code] Cleaning 2 --- apps/code/variable_box_controller.cpp | 658 +++++++++++++------------- apps/code/variable_box_controller.h | 22 +- 2 files changed, 352 insertions(+), 328 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3e4e25341..10b536c15 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -65,6 +65,14 @@ bool VariableBoxController::handleEvent(Ion::Events::Event event) { return NestedMenuController::handleEvent(event); } +void VariableBoxController::didEnterResponderChain(Responder * previousFirstResponder) { + /* Code::VariableBoxController should always be called from an environment + * where Python has already been inited. This way, we do not deinit Python + * when leaving the VariableBoxController, so we do not lose the environment + * that was loaded when entering the VariableBoxController. */ + assert(App::app()->pythonIsInited()); +} + void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { assert(index >= 0 && index < numberOfRows()); ScriptNodeCell * myCell = static_cast(cell); @@ -96,7 +104,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha if (scriptIndex < 0) { //TODO LEA load imported in console } else { - loadCurrentAndImportedVariableInScript(m_scriptStore->scriptAtIndex(scriptIndex), textToAutocomplete, textToAutocompleteLength); + Script script = m_scriptStore->scriptAtIndex(scriptIndex); + assert(!script.isNull()); + const char * scriptContent = script.scriptContent(); + assert(scriptContent != nullptr); + loadImportedVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); + loadCurrentVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); } } @@ -130,12 +143,12 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const // PRIVATE METHODS -int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLengthMaybe, bool * strictlyStartsWith) { +int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith) { // TODO LEA compare until parenthesis assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); + assert(nameLength > 0); const char * nodeName = node->name(); - const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); //TODO LEA needed ? - const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; + const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); const int comparisonLength = minInt(nameLength, nodeNameLength); int result = strncmp(nodeName, name, comparisonLength); if (result != 0) { @@ -144,24 +157,213 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, if (nodeNameLength == nameLength) { return 0; } - bool nodeNameLengthStartsWithName = comparisonLength == nameLength; + bool nodeNameLengthStartsWithName = nodeNameLength > nameLength; if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { *strictlyStartsWith = true; } - return nodeNameLengthStartsWithName ? -1 : 1; + return nodeNameLengthStartsWithName ? 1 : -1; } - - -void VariableBoxController::didEnterResponderChain(Responder * previousFirstResponder) { - /* This Code::VariableBoxController should always be called from an - * environment where Python has already been inited. This way, we do not - * deinit Python when leaving the VariableBoxController, so we do not lose the - * environment that was loaded when entering the VariableBoxController. */ - assert(App::app()->pythonIsInited()); +int VariableBoxController::NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength) { + bool strictlyStartsWith = false; + int result = NodeNameCompare(node, name, nameLength, &strictlyStartsWith); + if (strictlyStartsWith) { + return 0; + } + return result <= 0 ? -1 : 1; } +int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { + if (origin == NodeOrigin::Builtins) { + return m_builtinNodesCount; + } + return *(const_cast(this)->nodesCountPointerForOrigin(origin)); +} +int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { + if (origin == NodeOrigin::CurrentScript) { + return &m_currentScriptNodesCount; + } + assert(origin == NodeOrigin::Importation); + return &m_importedNodesCount; +} + +ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { + switch(origin) { + case NodeOrigin::CurrentScript: + return m_currentScriptNodes; + case NodeOrigin::Builtins: + return m_builtinNodes; + default: + assert(origin == NodeOrigin::Importation); + return m_importedNodes; + } +} + +ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { + assert(index >= 0 && index < numberOfRows()); + assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); + assert(m_builtinNodesCount <= k_totalBuiltinNodesCount); + assert(m_importedNodesCount <= k_maxScriptNodesCount); + + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + if (index < nodesCount) { + return nodesForOrigin(origin) + index; + } + index -= nodesCount; + } + assert(false); + return nullptr; +} + +bool VariableBoxController::selectLeaf(int rowIndex) { + assert(rowIndex >= 0 && rowIndex < numberOfRows()); + m_selectableTableView.deselectTable(); + ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); + insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); + if (selectedScriptNode->type() == ScriptNode::Type::Function) { + insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); + } + Container::activeApp()->dismissModalViewController(); + return true; +} + +void VariableBoxController::insertTextInCaller(const char * text, int textLength) { + int textLen = textLength < 0 ? strlen(text) : textLength; + int commandBufferMaxSize = minInt(k_maxScriptObjectNameSize, textLen + 1); + char commandBuffer[k_maxScriptObjectNameSize]; + Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLen, commandBuffer, commandBufferMaxSize, true); + sender()->handleEventWithText(commandBuffer); +} + +void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { + //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c + //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) + //TODO LEA add matplotlib.pyplot + static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { + {"False", ScriptNode::Type::Variable}, + {"None", ScriptNode::Type::Variable}, + {"True", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR___import__), ScriptNode::Type::Function}, + {"__del__", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, + {"and", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_any), ScriptNode::Type::Function}, + {"as", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::Function}, + {"assert", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_bin), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bool), ScriptNode::Type::Function}, + {"break", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_bytes), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_callable), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, + {"class", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_cmath), ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, + {"continue", ScriptNode::Type::Variable}, + {"def", ScriptNode::Type::Variable}, + //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_dict), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_dir), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_divmod), ScriptNode::Type::Function}, + {"elif", ScriptNode::Type::Variable}, + {"else", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_enumerate), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_eval), ScriptNode::Type::Function}, + {"except", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_exec), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_filter), ScriptNode::Type::Function}, + {"finally", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_float), ScriptNode::Type::Function}, + {"for", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, + {"from", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_getattr), ScriptNode::Type::Function}, + {"global", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_globals), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hasattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hash), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_help), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_hex), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_id), ScriptNode::Type::Function}, + {"if", ScriptNode::Type::Variable}, + {"import", ScriptNode::Type::Variable}, + {"in", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_ion), ScriptNode::Type::Variable}, + {"is", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_iter), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_kandinsky), ScriptNode::Type::Variable}, + {"lambda", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_len), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_list), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_locals), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_map), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_math), ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_max), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_min), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_next), ScriptNode::Type::Function}, + {"nonlocal", ScriptNode::Type::Variable}, + {"not", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_object), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_oct), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_open), ScriptNode::Type::Function}, + {"or", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_ord), ScriptNode::Type::Function}, + {"pass", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_pow), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, + {"raise", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_random), ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, + {"return", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_reversed), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_sum), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_super), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_time), ScriptNode::Type::Variable}, + {"try", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_tuple), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_turtle), ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_type), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_vars), ScriptNode::Type::Function}, + {"while", ScriptNode::Type::Variable}, + {"with", ScriptNode::Type::Variable}, + {"yield", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_zip), ScriptNode::Type::Function} + }; + assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); + for (int i = 0; i < k_totalBuiltinNodesCount; i++) { + ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name, -1, 0); + int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); + if (startsWith == 0) { + m_builtinNodes[m_builtinNodesCount++] = node; + } else if (startsWith > 0) { + break; + } + } +} /*TODO LEA very dirty * This is done to get the lexer position during lexing. As the _mp_reader_mem_t @@ -173,7 +375,120 @@ typedef struct _mp_reader_mem_t { const byte *cur; const byte *end; } mp_reader_mem_t; -/* TODO end*/ + +void VariableBoxController::loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { + /* Load the imported variables and functions: lex and the parse on a line per + * line basis untils parsing fails, while detecting import structures. */ + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + const char * parseStart = scriptContent; + // Skip new lines at the beginning of the script + while (*parseStart == '\n' && *parseStart != 0) { + parseStart++; + } + //TODO LEA also look for ";" ? But what if in string? + const char * parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); + + while (parseStart != parseEnd) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(0, parseStart, parseEnd - parseStart, 0); + mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_SINGLE_INPUT); + mp_parse_node_t pn = parseTree.root; + + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + addNodesFromImportMaybe((mp_parse_node_struct_t *) pn, textToAutocomplete, textToAutocompleteLength); + } + + mp_parse_tree_clear(&parseTree); + + if (*parseEnd == 0) { + // End of file + nlr_pop(); + return; + } + + parseStart = parseEnd; + // Skip the following \n + while (*parseStart == '\n' && *parseStart != 0) { + parseStart++; + } + parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); + } + nlr_pop(); + } +} + +void VariableBoxController::loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { + /* To find variable and funtion names: we lex the script and keep all + * MP_TOKEN_NAME that complete the text to autocomplete and are not already in + * the builtins or imported scripts. */ + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + + // 1) Lex the script + _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); + + // This is a trick to get the token position in the text. + const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + // Keep track of DEF tokens to differentiate between variables and functions + bool defToken = false; + + while (lex->tok_kind != MP_TOKEN_END) { + // Keep only MP_TOKEN_NAME tokens + if (lex->tok_kind == MP_TOKEN_NAME) { + + const char * name = lex->vstr.buf; + int nameLength = lex->vstr.len; + + /* If the token autocompletes the text and it is not already in the + * variable box, add it. */ + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { + /* This is a trick to get the token position in the text, as name and + * nameLength are temporary variables that will be overriden when the + * lexer continues lexing or is destroyed. + * The -2 was found from stepping in the code and trying. */ + // TODO LEA FIXME + for (int i = 0; i < 3; i++) { + if (strncmp(tokenInText, name, nameLength) != 0) { + tokenInText--; + } else { + break; + } + } + assert(strncmp(tokenInText, name, nameLength) == 0); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, 1/* TODO LEA*/); + } + } + + defToken = lex->tok_kind == MP_TOKEN_KW_DEF; + + /* This is a trick to get the token position in the text. The -1 was found + * from stepping in the code and trying. */ + tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + if (lex->tok_kind <= MP_TOKEN_ELLIPSIS || lex->tok_kind >= MP_TOKEN_OP_PLUS) { + tokenInText--; + } + + mp_lexer_to_next(lex); + } + + mp_lexer_free(lex); + nlr_pop(); + } +} + + + + + + + + + + + + + bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { @@ -263,240 +578,13 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par // Try fetching the nodes from a script Script importedScript = ScriptStore::ScriptBaseNamed(importationSourceName); if (!importedScript.isNull()) { - loadGlobalAndImportedVariableInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); + loadGlobalAndImportedVariablesInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); } } } return true; } -void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { - //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c - //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) - - // Add buitin nodes - static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { - {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, - {"and", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_any), ScriptNode::Type::Function}, - {"as", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::Function}, - {"assert", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_bin), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bool), ScriptNode::Type::Function}, - {"break", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bytes), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_callable), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, - {"class", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_cmath), ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, - {"continue", ScriptNode::Type::Variable}, - {"def", ScriptNode::Type::Variable}, - {"__del__", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_dict), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_dir), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_divmod), ScriptNode::Type::Function}, - {"elif", ScriptNode::Type::Variable}, - {"else", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_enumerate), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_eval), ScriptNode::Type::Function}, - {"except", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_exec), ScriptNode::Type::Function}, - {"False", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_filter), ScriptNode::Type::Function}, - {"finally", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_float), ScriptNode::Type::Function}, - {"for", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, - {"from", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_getattr), ScriptNode::Type::Function}, - {"global", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_globals), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hasattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hash), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_help), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hex), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_id), ScriptNode::Type::Function}, - {"if", ScriptNode::Type::Variable}, - {"import", ScriptNode::Type::Variable}, - {"in", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_ion), ScriptNode::Type::Variable}, - {"is", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_iter), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_kandinsky), ScriptNode::Type::Variable}, - {"lambda", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_len), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_list), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_locals), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_map), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_math), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_max), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_min), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_next), ScriptNode::Type::Function}, - {"None", ScriptNode::Type::Variable}, - {"nonlocal", ScriptNode::Type::Variable}, - {"not", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_object), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_oct), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_open), ScriptNode::Type::Function}, - {"or", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_ord), ScriptNode::Type::Function}, - {"pass", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_pow), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, - {"raise", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_random), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, - {"return", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_reversed), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_sum), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_super), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_time), ScriptNode::Type::Variable}, - {"True", ScriptNode::Type::Variable}, - {"try", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_tuple), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_turtle), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_type), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_vars), ScriptNode::Type::Function}, - {"while", ScriptNode::Type::Variable}, - {"with", ScriptNode::Type::Variable}, - {"yield", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_zip), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR___import__), ScriptNode::Type::Function} //TODO LEA alphabetical order? - }; - assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); - for (int i = 0; i < k_totalBuiltinNodesCount; i++) { - ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name, -1, 0); - int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); - if (startsWith == 0) { - m_builtinNodes[m_builtinNodesCount++] = node; - } else if (startsWith > 0) { - break; - } - } -} - -void VariableBoxController::loadCurrentAndImportedVariableInScript(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { - { - // Load the imported variables and functions - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - const char * parseStart = script.scriptContent(); - while (*parseStart == '\n' && *parseStart != 0) { - parseStart++; - } - //TODO LEA also look for ";" ? But what if in string? - const char * parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); - - while (parseStart != parseEnd) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(0, parseStart, parseEnd - parseStart, 0); - mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_SINGLE_INPUT); - mp_parse_node_t pn = parseTree.root; - - if (MP_PARSE_NODE_IS_STRUCT(pn)) { - addNodesFromImportMaybe((mp_parse_node_struct_t *) pn, textToAutocomplete, textToAutocompleteLength); - } - - mp_parse_tree_clear(&parseTree); - - if (*parseEnd == 0) { - nlr_pop(); - goto importCurrent; - } - parseStart = parseEnd + 1; // Go after the \n - while (*parseStart == '\n' && *parseStart != 0) { - parseStart++; - } - parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); - } - } - } - -importCurrent: - // Load the variables and functions from the current script - const char * scriptContent = script.scriptContent(); - - /* To find variable and funtion names: we lex the script and keep all - * MP_TOKEN_NAME that complete the text to autocomplete and are not already in - * the builtins or imported scripts. */ - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - - // 1) Lex the script - _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); - - // This is a trick to get the token position in the text. - const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); - // Keep track of DEF tokens to differentiate between variables and functions - bool defToken = false; - - while (lex->tok_kind != MP_TOKEN_END) { - // Keep only MP_TOKEN_NAME tokens - if (lex->tok_kind == MP_TOKEN_NAME) { - - const char * name = lex->vstr.buf; - int nameLength = lex->vstr.len; - - /* If the token autocompletes the text and it is not already in the - * variable box, add it. */ - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { - /* This is a trick to get the token position in the text, as name and - * nameLength are temporary variables that will be overriden when the - * lexer continues lexing or is destroyed. - * The -2 was found from stepping in the code and trying. */ - // TODO LEA FIXME - for (int i = 0; i < 3; i++) { - if (strncmp(tokenInText, name, nameLength) != 0) { - tokenInText--; - } else { - break; - } - } - assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, 1/* TODO LEA*/); - } - } - - defToken = lex->tok_kind == MP_TOKEN_KW_DEF; - - /* This is a trick to get the token position in the text. The -1 was found - * from stepping in the code and trying. */ - tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); - if (lex->tok_kind <= MP_TOKEN_ELLIPSIS || lex->tok_kind >= MP_TOKEN_OP_PLUS) { - tokenInText--; - } - - mp_lexer_to_next(lex); - } - - mp_lexer_free(lex); - nlr_pop(); - } -} - const char * structID(mp_parse_node_struct_t *structNode) { // Find the id child node, which stores the struct's name size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode); @@ -524,7 +612,7 @@ void VariableBoxController::storeImportedStruct(mp_parse_node_struct_t * pns, ui checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); } -void VariableBoxController::loadGlobalAndImportedVariableInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { assert(!script.isNull()); const char * scriptContent = script.scriptContent(); assert(scriptContent != nullptr); @@ -568,81 +656,6 @@ void VariableBoxController::loadGlobalAndImportedVariableInScriptAsImported(Scri } } -int VariableBoxController::NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength) { - bool strictlyStartsWith = false; - int result = NodeNameCompare(node, name, nameLength, &strictlyStartsWith); - if (strictlyStartsWith) { - return 0; - } - return result <= 0 ? -1 : 1; -} - -int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { - if (origin == NodeOrigin::CurrentScript) { - return &m_currentScriptNodesCount; - } - assert(origin == NodeOrigin::Importation); - return &m_importedNodesCount; -} - -int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { - if (origin == NodeOrigin::Builtins) { - return m_builtinNodesCount; - } - return *(const_cast(this)->nodesCountPointerForOrigin(origin)); -} - -ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { - switch(origin) { - case NodeOrigin::CurrentScript: - return m_currentScriptNodes; - case NodeOrigin::Builtins: - return m_builtinNodes; - default: - assert(origin == NodeOrigin::Importation); - return m_importedNodes; - } -} - -ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { - assert(index >= 0 && index < numberOfRows()); - assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); - assert(m_builtinNodesCount <= k_totalBuiltinNodesCount); - assert(m_importedNodesCount <= k_maxScriptNodesCount); - NodeOrigin origins[] = { NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - if (index < nodesCount) { - return nodesForOrigin(origin) + index; - } - index -= nodesCount; - } - assert(false); - return nullptr; -} - -bool VariableBoxController::selectLeaf(int rowIndex) { - assert(rowIndex >= 0 && rowIndex < numberOfRows()); - assert(m_currentScriptNodesCount <= k_maxScriptNodesCount); - assert(m_importedNodesCount <= k_maxScriptNodesCount); - m_selectableTableView.deselectTable(); - ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); - insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); - if (selectedScriptNode->type() == ScriptNode::Type::Function) { - insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); - } - Container::activeApp()->dismissModalViewController(); - return true; -} - -void VariableBoxController::insertTextInCaller(const char * text, int textLength) { - int textLen = textLength < 0 ? strlen(text) : textLength; - int commandBufferMaxSize = minInt(k_maxScriptObjectNameSize, textLen + 1); - char commandBuffer[k_maxScriptObjectNameSize]; - Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLen, commandBuffer, commandBufferMaxSize, true); - sender()->handleEventWithText(commandBuffer); -} - bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength) { if (textToAutocomplete != nullptr) { /* Check that nodeName autocompletes the text to autocomplete @@ -668,6 +681,9 @@ bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int t } void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, int scriptIndex) { + if (nodeNameLength < 0) { + nodeNameLength = strlen(nodeName); + } if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { // Add the node in alphabetical order addNode(type, origin, nodeName, nodeNameLength, scriptIndex); @@ -705,9 +721,9 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co *currentNodeCount = *currentNodeCount + 1; } -bool VariableBoxController::contains(const char * name, int nameLengthMaybe) { +bool VariableBoxController::contains(const char * name, int nameLength) { + assert(nameLength > 0); bool alreadyInVarBox = false; - const int nameLength = nameLengthMaybe < 0 ? strlen(name) : nameLengthMaybe; // TODO LEA speed this up with dichotomia? NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; for (NodeOrigin origin : origins) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 9876279fe..a3053944b 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -42,10 +42,7 @@ private: Builtins, Importation }; - static int MaxNodesCountForOrigin(NodeOrigin origin) { - assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - return k_maxScriptNodesCount; - } + /* Returns: * - a negative int if the node name is before name in alphabetical * order @@ -60,22 +57,33 @@ private: * - 0 if node name strictly starts with name * - a positive int if node name is after name in alphabetical order. */ static int NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength); - int * nodesCountPointerForOrigin(NodeOrigin origin); + + // Nodes and nodes count + static int MaxNodesCountForOrigin(NodeOrigin origin) { + assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); + return k_maxScriptNodesCount; + } int nodesCountForOrigin(NodeOrigin origin) const; + int * nodesCountPointerForOrigin(NodeOrigin origin); ScriptNode * nodesForOrigin(NodeOrigin origin); ScriptNode * scriptNodeAtIndex(int index); + + // Cell getters HighlightCell * leafCellAtIndex(int index) override { assert(index >= 0 && index < k_maxNumberOfDisplayedRows); return &m_leafCells[index]; } HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } + // NestedMenuController bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); + // Loading void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); - void loadCurrentAndImportedVariableInScript(Script script, const char * textToAutocomplete, int textToAutocompleteLength); - void loadGlobalAndImportedVariableInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength); + void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); + void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); + void loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength); bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); // Returns true if this was an import structure /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ From 6aa150d5d7d2a44c07fff0ac9eeebdf104225489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 16:44:27 +0200 Subject: [PATCH 198/453] [apps/code] Cleaning 3 --- apps/code/variable_box_controller.cpp | 198 ++++++++++++-------------- apps/code/variable_box_controller.h | 11 +- 2 files changed, 99 insertions(+), 110 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 10b536c15..29ebf6a9f 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -477,58 +477,90 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } +void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); + mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_parse_node_t pn = parseTree.root; - - - - - - - - - - - + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + mp_parse_node_struct_t * pns = (mp_parse_node_struct_t *)pn; + uint structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(pns); + if (structKind == PN_funcdef || structKind == PN_expr_stmt) { + // The script is only a single function or variable definition + addImportStruct(pns, structKind, textToAutocomplete, textToAutocompleteLength); + } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { + // The script is is only an import, handled in addNodesFromImportMaybe + } else if (structKind == PN_file_input_2) { + /* At this point, if the script node is not of type "file_input_2", it + * will not have main structures of the wanted type. + * We look for structures at first level (not inside nested scopes) that + * are either dunction definitions, variables statements or imports. */ + size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (size_t i = 0; i < n; i++) { + mp_parse_node_t child = pns->nodes[i]; + if (MP_PARSE_NODE_IS_STRUCT(child)) { + mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); + structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); + if (structKind == PN_funcdef || structKind == PN_expr_stmt) { + addImportStruct(child_pns, structKind, textToAutocomplete, textToAutocompleteLength); + } else { + addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); + } + } + } + } + } + mp_parse_tree_clear(&parseTree); + nlr_pop(); + } +} bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { - + // Determine if the node is an import structure uint structKind = (uint) MP_PARSE_NODE_STRUCT_KIND(parseNode); bool structKindIsImportWithoutFrom = structKind == PN_import_name; - if (!structKindIsImportWithoutFrom && structKind != PN_import_from && structKind != PN_import_as_names && structKind != PN_import_as_name) { + // This was not an import structure return false; } - bool loadModuleContent = structKindIsImportWithoutFrom; + /* loadAllModuleContent will be True if the struct imports all the content + * from a script / module (for instance, "import math"), instead of single + * items (for instance, "from math import sin"). */ + bool loadAllContent = structKindIsImportWithoutFrom; size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); for (int i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { - // Parsing something like import math + // Parsing something like "import math" const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { - // Parsing something like from math import sin + // Parsing something like "from math import sin" addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); } else if (MP_PARSE_NODE_IS_TOKEN(child) && MP_PARSE_NODE_IS_TOKEN_KIND(child, MP_TOKEN_OP_STAR)) { - /* Parsing something like from math import * + /* Parsing something like "from math import *" * -> Load all the module content */ - loadModuleContent = true; + loadAllContent = true; } } - if (loadModuleContent) { - // We fetch variables and functions imported from a module or a script + // Fetch a script / module content if needed + if (loadAllContent) { assert(childNodesCount > 0); mp_parse_node_t importationSource = parseNode->nodes[0]; const char * importationSourceName = nullptr; - if (MP_PARSE_NODE_IS_LEAF(importationSource) && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID) { + if (MP_PARSE_NODE_IS_LEAF(importationSource) + && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID) + { // The importation source is "simple", for instance: from math import * importationSourceName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSource)); } else if (MP_PARSE_NODE_IS_STRUCT(importationSource)) { @@ -565,27 +597,28 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par const ToolboxMessageTree * moduleChildren = static_cast(App::app()->toolboxForInputEventHandler(nullptr))->moduleChildren(importationSourceName, &numberOfChildren); if (moduleChildren != nullptr) { /* If the importation source is a module, get the nodes from the toolbox - * We skip the 3 forst nodes, which are "import ...", "from ... import *" + * We skip the 3 first nodes, which are "import ...", "from ... import *" * and "....function". */ constexpr int numberOfNodesToSkip = 3; assert(numberOfChildren > numberOfNodesToSkip); for (int i = 3; i < numberOfChildren; i++) { - const ToolboxMessageTree * currentTree = moduleChildren + i; - const char * name = I18n::translate(currentTree->label()); + const char * name = I18n::translate((moduleChildren + i)->label()); checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); } } else { // Try fetching the nodes from a script Script importedScript = ScriptStore::ScriptBaseNamed(importationSourceName); if (!importedScript.isNull()) { - loadGlobalAndImportedVariablesInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); + const char * scriptContent = importedScript.scriptContent(); + assert(scriptContent != nullptr); + loadGlobalAndImportedVariablesInScriptAsImported(scriptContent, textToAutocomplete, textToAutocompleteLength); } } } return true; } -const char * structID(mp_parse_node_struct_t *structNode) { +const char * structName(mp_parse_node_struct_t * structNode) { // Find the id child node, which stores the struct's name size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode); if (childNodesCount < 1) { @@ -601,58 +634,23 @@ const char * structID(mp_parse_node_struct_t *structNode) { return nullptr; } - -void VariableBoxController::storeImportedStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength) { assert(structKind == PN_funcdef || structKind == PN_expr_stmt); // Find the id child node, which stores the struct's name - const char * id = structID(pns); - if (id == nullptr) { + const char * name = structName(pns); + if (name == nullptr) { return; } - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); } -void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength) { - assert(!script.isNull()); - const char * scriptContent = script.scriptContent(); - assert(scriptContent != nullptr); - - // Handle lexer or parser errors with nlr. - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - - mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); - mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_parse_node_t pn = parseTree.root; - - if (MP_PARSE_NODE_IS_STRUCT(pn)) { - mp_parse_node_struct_t * pns = (mp_parse_node_struct_t *)pn; - uint structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(pns); - if (structKind == PN_funcdef || structKind == PN_expr_stmt) { - // The script is only a single function or variable definition - storeImportedStruct(pns, structKind, textToAutocomplete, textToAutocompleteLength); - } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { - } else if (structKind == PN_file_input_2) { - /* At this point, if the script node is not of type "file_input_2", it - * will not have main structures of the wanted type. */ - // Count the number of structs in child nodes. - size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); - for (size_t i = 0; i < n; i++) { - mp_parse_node_t child = pns->nodes[i]; - if (MP_PARSE_NODE_IS_STRUCT(child)) { - mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); - structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); - if (structKind == PN_funcdef || structKind == PN_expr_stmt) { - storeImportedStruct(child_pns, structKind, textToAutocomplete, textToAutocompleteLength); - } else { - addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); - } - } - } - } - } - mp_parse_tree_clear(&parseTree); - nlr_pop(); +void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, int scriptIndex) { + if (nodeNameLength < 0) { + nodeNameLength = strlen(nodeName); + } + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { + // Add the node in alphabetical order + addNode(type, origin, nodeName, nodeNameLength, scriptIndex); } } @@ -680,14 +678,30 @@ bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int t return true; } -void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, int scriptIndex) { - if (nodeNameLength < 0) { - nodeNameLength = strlen(nodeName); - } - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { - // Add the node in alphabetical order - addNode(type, origin, nodeName, nodeNameLength, scriptIndex); +bool VariableBoxController::contains(const char * name, int nameLength) { + assert(nameLength > 0); + bool alreadyInVarBox = false; + // TODO LEA speed this up with dichotomia? + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + ScriptNode * nodes = nodesForOrigin(origin); + for (int i = 0; i < nodesCount; i++) { + ScriptNode * matchingNode = nodes + i; + int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); + if (comparisonResult == 0) { + alreadyInVarBox = true; + break; + } + if (comparisonResult > 0) { + break; + } + } + if (alreadyInVarBox) { + break; + } } + return alreadyInVarBox; } void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { @@ -721,30 +735,4 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co *currentNodeCount = *currentNodeCount + 1; } -bool VariableBoxController::contains(const char * name, int nameLength) { - assert(nameLength > 0); - bool alreadyInVarBox = false; - // TODO LEA speed this up with dichotomia? - NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - ScriptNode * nodes = nodesForOrigin(origin); - for (int i = 0; i < nodesCount; i++) { - ScriptNode * matchingNode = nodes + i; - int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); - if (comparisonResult == 0) { - alreadyInVarBox = true; - break; - } - if (comparisonResult > 0) { - break; - } - } - if (alreadyInVarBox) { - break; - } - } - return alreadyInVarBox; -} - } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index a3053944b..730b7ed84 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -83,15 +83,16 @@ private: void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); - void loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength); - bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); // Returns true if this was an import structure + void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); + // Returns true if this was an import structure + bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); + void addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength); /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ - bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); - void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); bool contains(const char * name, int nameLength); - void storeImportedStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength); + void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From a98f4b6ca0b638a9dfcf11732ebc710f63f60b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 17:11:45 +0200 Subject: [PATCH 199/453] [apps/code] Edit the builtins list --- apps/code/variable_box_controller.cpp | 8 ++++---- apps/code/variable_box_controller.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 29ebf6a9f..06003bb26 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -247,7 +247,6 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {"None", ScriptNode::Type::Variable}, {"True", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR___import__), ScriptNode::Type::Function}, - {"__del__", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, {"and", ScriptNode::Type::Variable}, @@ -259,7 +258,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_bool), ScriptNode::Type::Function}, {"break", ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_bytes), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_callable), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, @@ -270,6 +269,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, {"continue", ScriptNode::Type::Variable}, {"def", ScriptNode::Type::Variable}, + {"del", ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_dict), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_dir), ScriptNode::Type::Function}, @@ -284,7 +284,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {"finally", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_float), ScriptNode::Type::Function}, {"for", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, {"from", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_getattr), ScriptNode::Type::Function}, @@ -336,7 +336,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, + //{qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 730b7ed84..941883cca 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -36,7 +36,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; //TODO LEA - constexpr static int k_totalBuiltinNodesCount = 101; + constexpr static int k_totalBuiltinNodesCount = 98; enum class NodeOrigin : uint8_t { CurrentScript, Builtins, From 52644bf76d2a4c097eba53fd49a0971fd1ab28fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Apr 2020 17:24:58 +0200 Subject: [PATCH 200/453] [apps/code] Subtitles in the variable box --- apps/code/base.de.i18n | 3 +++ apps/code/base.en.i18n | 3 +++ apps/code/base.es.i18n | 3 +++ apps/code/base.fr.i18n | 3 +++ apps/code/base.pt.i18n | 3 +++ apps/code/editor_view.cpp | 3 ++- apps/code/variable_box_controller.cpp | 10 ++++++++++ apps/code/variable_box_controller.h | 2 ++ escher/include/escher/palette.h | 1 + escher/src/palette.cpp | 1 + 10 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/code/base.de.i18n b/apps/code/base.de.i18n index 5879c5745..1d9f39cc5 100644 --- a/apps/code/base.de.i18n +++ b/apps/code/base.de.i18n @@ -6,3 +6,6 @@ AutoImportScript = "Automatischer Import in Konsole" DeleteScript = "Skript löschen" FunctionsAndVariables = "Funktionen und Variablen" AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _" +CurrentScript = "Current script" +BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" +ImportedModulesAndScripts = "Imported modules and scripts" diff --git a/apps/code/base.en.i18n b/apps/code/base.en.i18n index 8bf1e3c9f..266221a70 100644 --- a/apps/code/base.en.i18n +++ b/apps/code/base.en.i18n @@ -6,3 +6,6 @@ AutoImportScript = "Auto import in shell" DeleteScript = "Delete script" FunctionsAndVariables = "Functions and variables" AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" +CurrentScript = "Current script" +BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" +ImportedModulesAndScripts = "Imported modules and scripts" diff --git a/apps/code/base.es.i18n b/apps/code/base.es.i18n index 4e4860fe4..cbd4b8859 100644 --- a/apps/code/base.es.i18n +++ b/apps/code/base.es.i18n @@ -6,3 +6,6 @@ AutoImportScript = "Importación auto en intérprete" DeleteScript = "Eliminar el archivo" FunctionsAndVariables = "Funciones y variables" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" +CurrentScript = "Current script" +BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" +ImportedModulesAndScripts = "Imported modules and scripts" diff --git a/apps/code/base.fr.i18n b/apps/code/base.fr.i18n index 253989ab2..2dd179d22 100644 --- a/apps/code/base.fr.i18n +++ b/apps/code/base.fr.i18n @@ -6,3 +6,6 @@ AutoImportScript = "Importation auto dans la console" DeleteScript = "Supprimer le script" FunctionsAndVariables = "Fonctions et variables" AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" +CurrentScript = "Script en cours" +BuiltinFunctionsAndKeyWords = "Fonctions natives et mots-clés" +ImportedModulesAndScripts = "Modules et scripts importés" diff --git a/apps/code/base.pt.i18n b/apps/code/base.pt.i18n index d44da5a19..4dd8066d3 100644 --- a/apps/code/base.pt.i18n +++ b/apps/code/base.pt.i18n @@ -6,3 +6,6 @@ AutoImportScript = "Importação auto no interpretador" DeleteScript = "Eliminar o script" FunctionsAndVariables = "Funções e variáveis" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" +CurrentScript = "Current script" +BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" +ImportedModulesAndScripts = "Imported modules and scripts" diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp index 2685fa5fb..0af73b613 100644 --- a/apps/code/editor_view.cpp +++ b/apps/code/editor_view.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace Code { @@ -56,7 +57,7 @@ void EditorView::layoutSubviews(bool force) { /* EditorView::GutterView */ void EditorView::GutterView::drawRect(KDContext * ctx, KDRect rect) const { - KDColor textColor = KDColor::RGB24(0x919EA4); + KDColor textColor = Palette::BlueishGrey; KDColor backgroundColor = KDColor::RGB24(0xE4E6E7); ctx->fillRect(rect, backgroundColor); diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 06003bb26..89ed28d3d 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -56,6 +56,16 @@ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { m_leafCells[i].setScriptStore(scriptStore); } + I18n::Message subtitleMessages[k_scriptOriginsCount] = { + I18n::Message::CurrentScript, + I18n::Message::BuiltinFunctionsAndKeyWords, + I18n::Message::ImportedModulesAndScripts + }; + for (int i = 0; i < k_scriptOriginsCount; i++) { + m_subtitleCells[i].setEven(true); + m_subtitleCells[i].setAlignment(0.0f, 0.5f); + m_subtitleCells[i].setMessage(subtitleMessages[i], Palette::BlueishGrey); + } } bool VariableBoxController::handleEvent(Ion::Events::Event event) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 941883cca..bd5eae0bf 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -37,6 +37,7 @@ private: constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 98; + constexpr static uint8_t k_scriptOriginsCount = 3; enum class NodeOrigin : uint8_t { CurrentScript, Builtins, @@ -98,6 +99,7 @@ private: ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; ScriptNodeCell m_leafCells[k_maxNumberOfDisplayedRows]; + EvenOddMessageTextCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; // TODO LEA Put these in an array? int m_currentScriptNodesCount; diff --git a/escher/include/escher/palette.h b/escher/include/escher/palette.h index 0ebc550a7..ccc965a5d 100644 --- a/escher/include/escher/palette.h +++ b/escher/include/escher/palette.h @@ -33,6 +33,7 @@ public: constexpr static KDColor GreenLight = KDColor::RGB24(0x52db8f); constexpr static KDColor Brown = KDColor::RGB24(0x8d7350); constexpr static KDColor Purple = KDColor::RGB24(0x6e2d79); + constexpr static KDColor BlueishGrey = KDColor::RGB24(0x919ea4); constexpr static KDColor DataColor[] = {Red, Blue, Green, YellowDark, Magenta, Turquoise, Pink, Orange}; constexpr static KDColor DataColorLight[] = {RedLight, BlueLight, GreenLight, YellowLight}; diff --git a/escher/src/palette.cpp b/escher/src/palette.cpp index 2d6e91145..9d96af6d7 100644 --- a/escher/src/palette.cpp +++ b/escher/src/palette.cpp @@ -28,6 +28,7 @@ constexpr KDColor Palette::Green; constexpr KDColor Palette::GreenLight; constexpr KDColor Palette::Brown; constexpr KDColor Palette::Purple; +constexpr KDColor Palette::BlueishGrey; constexpr KDColor Palette::DataColor[]; constexpr KDColor Palette::DataColorLight[]; From 0863abc4dabc20e18dfbbf6d551fd7ed5e599f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 3 Apr 2020 11:26:29 +0200 Subject: [PATCH 201/453] [apps/code] VariableBox cells with node origins --- apps/code/variable_box_controller.cpp | 95 ++++++++++++++++++++++++--- apps/code/variable_box_controller.h | 37 ++++++----- escher/src/even_odd_cell.cpp | 2 +- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 89ed28d3d..3cfe89762 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -54,17 +54,12 @@ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : m_importedNodesCount(0) { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { - m_leafCells[i].setScriptStore(scriptStore); + m_itemCells[i].setScriptStore(scriptStore); } - I18n::Message subtitleMessages[k_scriptOriginsCount] = { - I18n::Message::CurrentScript, - I18n::Message::BuiltinFunctionsAndKeyWords, - I18n::Message::ImportedModulesAndScripts - }; for (int i = 0; i < k_scriptOriginsCount; i++) { - m_subtitleCells[i].setEven(true); + m_subtitleCells[i].setEven(false); m_subtitleCells[i].setAlignment(0.0f, 0.5f); - m_subtitleCells[i].setMessage(subtitleMessages[i], Palette::BlueishGrey); + m_subtitleCells[i].setMessageFont(KDFont::SmallFont); } } @@ -83,10 +78,64 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp assert(App::app()->pythonIsInited()); } +KDCoordinate VariableBoxController::rowHeight(int j) { + int cellType = typeAndOriginAtLocation(j, nullptr); + if (cellType == k_itemCellType) { + return k_simpleItemRowHeight; // TODO LEA + } + assert(cellType == k_subtitleCellType); + return k_subtitleRowHeight; +} + +int VariableBoxController::numberOfRows() const { + int result = 0; + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + int nodeCount = nodesCountForOrigin(origin); + if (nodeCount > 0) { + result += nodeCount + 1; // 1 for the subtitle cell + } + } + return result; +} + +HighlightCell * VariableBoxController::reusableCell(int index, int type) { + assert(index >= 0 && index < reusableCellCount(type)); + if (type == k_itemCellType) { + return m_itemCells + index; + } + assert(type == k_subtitleCellType); + return m_subtitleCells + index; +} + +int VariableBoxController::reusableCellCount(int type) { + if (type == k_subtitleCellType) { + return k_scriptOriginsCount; + } + assert(type == k_itemCellType); + return k_maxNumberOfDisplayedRows; +} + void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { assert(index >= 0 && index < numberOfRows()); - ScriptNodeCell * myCell = static_cast(cell); - myCell->setScriptNode(scriptNodeAtIndex(index)); + NodeOrigin cellOrigin = NodeOrigin::CurrentScript; + int cellType = typeAndOriginAtLocation(index, &cellOrigin); + if (cellType == k_itemCellType) { + static_cast(cell)->setScriptNode(scriptNodeAtIndex(index)); + return; + } + assert(cellType == k_subtitleCellType); + I18n::Message subtitleMessages[k_scriptOriginsCount] = { + I18n::Message::CurrentScript, + I18n::Message::BuiltinFunctionsAndKeyWords, + I18n::Message::ImportedModulesAndScripts + }; + static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin], Palette::BlueishGrey); +} + +int VariableBoxController::typeAtLocation(int i, int j) { + assert(i == 0); + return typeAndOriginAtLocation(j, nullptr); } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { @@ -228,6 +277,32 @@ ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { return nullptr; } +int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin) const { + int cellIndex = 0; + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + int nodeCount = nodesCountForOrigin(origin); + if (nodeCount > 0) { + if (i == cellIndex) { + if (resultOrigin != nullptr) { + *resultOrigin = origin; + } + return k_subtitleCellType; + } + cellIndex += nodeCount + 1; // 1 for the subtitle cell + if (i < cellIndex) { + if (resultOrigin != nullptr) { + *resultOrigin = origin; + } + return k_itemCellType; + } + } + } + assert(false); + return k_itemCellType; + +} + bool VariableBoxController::selectLeaf(int rowIndex) { assert(rowIndex >= 0 && rowIndex < numberOfRows()); m_selectableTableView.deselectTable(); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index bd5eae0bf..bf0e7a762 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -16,16 +16,14 @@ public: bool handleEvent(Ion::Events::Event event) override; void didEnterResponderChain(Responder * previousFirstResponder) override; + /* TableViewDataSource */ + KDCoordinate rowHeight(int j) override; + int numberOfRows() const override; + HighlightCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + int typeAtLocation(int i, int j) override; /* ListViewDataSource */ - int numberOfRows() const override { - return m_currentScriptNodesCount + m_builtinNodesCount + m_importedNodesCount; - } - int reusableCellCount(int type) override { - assert(type == 0); - return k_maxNumberOfDisplayedRows; - } void willDisplayCellForIndex(HighlightCell * cell, int index) override; - int typeAtLocation(int i, int j) override { return 0; } /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); @@ -34,14 +32,19 @@ public: private: //TODO LEA use size_t constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA - constexpr static int k_maxNumberOfDisplayedRows = 6; // 240/40 + constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 98; constexpr static uint8_t k_scriptOriginsCount = 3; + constexpr static uint8_t k_subtitleCellType = 0; + constexpr static uint8_t k_itemCellType = 1; + constexpr static KDCoordinate k_subtitleRowHeight = 23; + constexpr static KDCoordinate k_simpleItemRowHeight = 27; + constexpr static KDCoordinate k_complexItemRowHeight = 44; enum class NodeOrigin : uint8_t { - CurrentScript, - Builtins, - Importation + CurrentScript = 0, + Builtins = 1, + Importation = 2 }; /* Returns: @@ -70,13 +73,11 @@ private: ScriptNode * scriptNodeAtIndex(int index); // Cell getters - HighlightCell * leafCellAtIndex(int index) override { - assert(index >= 0 && index < k_maxNumberOfDisplayedRows); - return &m_leafCells[index]; - } - HighlightCell * nodeCellAtIndex(int index) override { return nullptr; } + int typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin) const; // NestedMenuController + HighlightCell * leafCellAtIndex(int index) override { assert(false); return nullptr; } + HighlightCell * nodeCellAtIndex(int index) override { assert(false); return nullptr; } bool selectLeaf(int rowIndex) override; void insertTextInCaller(const char * text, int textLength = -1); @@ -98,7 +99,7 @@ private: ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; - ScriptNodeCell m_leafCells[k_maxNumberOfDisplayedRows]; + ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedRows]; EvenOddMessageTextCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; // TODO LEA Put these in an array? diff --git a/escher/src/even_odd_cell.cpp b/escher/src/even_odd_cell.cpp index 4e6b0bb9f..83b432861 100644 --- a/escher/src/even_odd_cell.cpp +++ b/escher/src/even_odd_cell.cpp @@ -16,7 +16,7 @@ void EvenOddCell::setEven(bool even) { KDColor EvenOddCell::backgroundColor() const { // Select the background color according to the even line and the cursor selection - KDColor background = m_even ? KDColorWhite : Palette::WallScreen ; + KDColor background = m_even ? KDColorWhite : Palette::WallScreen; background = isHighlighted() ? Palette::Select : background; return background; } From 69abd754600317a37acced703e0b14580437b2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 3 Apr 2020 13:45:26 +0200 Subject: [PATCH 202/453] [apps/code] Clean ScriptNodeCell --- apps/code/script_node_cell.cpp | 25 ------------------------- apps/code/script_node_cell.h | 19 +++++++++++++------ 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index faeadc806..312978e2a 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -7,21 +7,6 @@ namespace Code { constexpr char ScriptNodeCell::k_parentheses[]; constexpr char ScriptNodeCell::k_parenthesesWithEmpty[]; -ScriptNodeCell::ScriptNodeView::ScriptNodeView() : - HighlightCell(), - m_scriptNode(nullptr), - m_scriptStore(nullptr) -{ -} - -void ScriptNodeCell::ScriptNodeView::setScriptNode(ScriptNode * scriptNode) { - m_scriptNode = scriptNode; -} - -void ScriptNodeCell::ScriptNodeView::setScriptStore(ScriptStore * scriptStore) { - m_scriptStore = scriptStore; -} - void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite, m_scriptNode->nameLength()); KDSize nameSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); @@ -44,21 +29,11 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { return KDSize(size1.width() + size3.width() > size2.width() ? size1.width() + size3.width() : size2.width(), Metric::TableCellVerticalMargin + size1.width() + k_verticalMargin + size2.width()); } -ScriptNodeCell::ScriptNodeCell() : - TableCell(), - m_scriptNodeView() -{ -} - void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) { m_scriptNodeView.setScriptNode(scriptNode); reloadCell(); } -void ScriptNodeCell::setScriptStore(ScriptStore * scriptStore) { - m_scriptNodeView.setScriptStore(scriptStore); -} - void ScriptNodeCell::setHighlighted(bool highlight) { TableCell::setHighlighted(highlight); m_scriptNodeView.setHighlighted(highlight); diff --git a/apps/code/script_node_cell.h b/apps/code/script_node_cell.h index c4d7651b7..4367e8c12 100644 --- a/apps/code/script_node_cell.h +++ b/apps/code/script_node_cell.h @@ -10,9 +10,12 @@ namespace Code { class ScriptNodeCell : public TableCell { public: - ScriptNodeCell(); - void setScriptNode(ScriptNode * node); - void setScriptStore(ScriptStore * scriptStore); + ScriptNodeCell() : + TableCell(), + m_scriptNodeView() + {} + void setScriptNode(ScriptNode * node) { m_scriptNode = scriptNode; } + void setScriptStore(ScriptStore * scriptStore) { m_scriptNodeView.setScriptStore(scriptStore); } /* TableCell */ View * labelView() const override { return const_cast(static_cast(&m_scriptNodeView)); } @@ -29,9 +32,13 @@ public: protected: class ScriptNodeView : public HighlightCell { public: - ScriptNodeView(); - void setScriptNode(ScriptNode * scriptNode); - void setScriptStore(ScriptStore * scriptStore); + ScriptNodeView() : + HighlightCell(), + m_scriptNode(nullptr), + m_scriptStore(nullptr) + {} + void setScriptNode(ScriptNode * node) { m_scriptNode = scriptNode; } + void setScriptStore(ScriptStore * scriptStore) { m_scriptStore = scriptStore; } void drawRect(KDContext * ctx, KDRect rect) const override; virtual KDSize minimalSizeForOptimalDisplay() const override; const char * text() const override { From 34a1a8e35f7a4db0c07347758c98c9a5d1c03f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 3 Apr 2020 14:09:26 +0200 Subject: [PATCH 203/453] [apps/code] Fix willDisplayCellForIndex Problem: some nodes were not displayed, because the subtitles count was not taken into account when using the index parameter if willDisplayCellForIndex --- apps/code/variable_box_controller.cpp | 34 +++++++++++++++++---------- apps/code/variable_box_controller.h | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3cfe89762..02f003468 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -79,7 +79,7 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp } KDCoordinate VariableBoxController::rowHeight(int j) { - int cellType = typeAndOriginAtLocation(j, nullptr); + int cellType = typeAndOriginAtLocation(j); if (cellType == k_itemCellType) { return k_simpleItemRowHeight; // TODO LEA } @@ -119,9 +119,10 @@ int VariableBoxController::reusableCellCount(int type) { void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { assert(index >= 0 && index < numberOfRows()); NodeOrigin cellOrigin = NodeOrigin::CurrentScript; - int cellType = typeAndOriginAtLocation(index, &cellOrigin); + int cumulatedOriginsCount = 0; + int cellType = typeAndOriginAtLocation(index, &cellOrigin, &cumulatedOriginsCount); if (cellType == k_itemCellType) { - static_cast(cell)->setScriptNode(scriptNodeAtIndex(index)); + static_cast(cell)->setScriptNode(scriptNodeAtIndex(index - cumulatedOriginsCount)); // Remove the number of subtitle cells from the index return; } assert(cellType == k_subtitleCellType); @@ -135,7 +136,7 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in int VariableBoxController::typeAtLocation(int i, int j) { assert(i == 0); - return typeAndOriginAtLocation(j, nullptr); + return typeAndOriginAtLocation(j); } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { @@ -277,24 +278,31 @@ ScriptNode * VariableBoxController::scriptNodeAtIndex(int index) { return nullptr; } -int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin) const { +int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin, int * cumulatedOriginsCount) const { int cellIndex = 0; + int originsCount = 0; NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; for (NodeOrigin origin : origins) { int nodeCount = nodesCountForOrigin(origin); if (nodeCount > 0) { + originsCount++; + int result = -1; if (i == cellIndex) { + result = k_subtitleCellType; + } else { + cellIndex += nodeCount + 1; // 1 for the subtitle cell + if (i < cellIndex) { + result = k_itemCellType; + } + } + if (result != -1) { if (resultOrigin != nullptr) { *resultOrigin = origin; } - return k_subtitleCellType; - } - cellIndex += nodeCount + 1; // 1 for the subtitle cell - if (i < cellIndex) { - if (resultOrigin != nullptr) { - *resultOrigin = origin; - } - return k_itemCellType; + if (cumulatedOriginsCount != nullptr) { + *cumulatedOriginsCount = originsCount; + } + return result; } } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index bf0e7a762..9d1f91459 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -73,7 +73,7 @@ private: ScriptNode * scriptNodeAtIndex(int index); // Cell getters - int typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin) const; + int typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin = nullptr, int * cumulatedOriginsCount = nullptr) const; // NestedMenuController HighlightCell * leafCellAtIndex(int index) override { assert(false); return nullptr; } From 96d68d6b44f6bfcee1a954a8704f6a8527e770ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 3 Apr 2020 17:52:15 +0200 Subject: [PATCH 204/453] [apps/code/varbox] Subtitles and basic items are displayed properly --- apps/code/script_node.h | 3 ++- apps/code/script_node_cell.cpp | 20 +++++++++++++++----- apps/code/script_node_cell.h | 4 ++-- apps/code/variable_box_controller.cpp | 9 ++++----- apps/code/variable_box_controller.h | 2 +- escher/include/escher/message_table_cell.h | 4 ++++ escher/include/escher/table_cell.h | 1 + escher/src/message_table_cell.cpp | 10 ++++++++-- escher/src/table_cell.cpp | 4 ++-- 9 files changed, 39 insertions(+), 18 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index a788d3457..01864091d 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -8,6 +8,7 @@ namespace Code { class ScriptNode { public: + constexpr static uint16_t CurrentScriptIndex = -1; enum class Type : bool { Function, Variable @@ -15,7 +16,7 @@ public: ScriptNode(Type type = Type::Variable, const char * name = nullptr, int nameLength = 0, uint16_t scriptIndex = 0) : m_type(type), m_name(name), - m_scriptIndex(scriptIndex), + m_scriptIndex(-1), m_nameLength(nameLength) {} Type type() const { return m_type; } diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index 312978e2a..a56e69966 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -8,12 +8,22 @@ constexpr char ScriptNodeCell::k_parentheses[]; constexpr char ScriptNodeCell::k_parenthesesWithEmpty[]; void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { - ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite, m_scriptNode->nameLength()); - KDSize nameSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); + const KDColor backgroundColor = isHighlighted()? Palette::Select : KDColorWhite; + + // Draw the node name + const char * nodeName = m_scriptNode->name(); + const int nodeNameLength = m_scriptNode->nameLength(); + const KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength); + const KDCoordinate nodeNameY = (rect.height() - nameSize.height()) / 2; + ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength); + + // If it is a function, draw the parentheses if (m_scriptNode->type() == ScriptNode::Type::Function) { - ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), Metric::TableCellVerticalMargin), k_font, KDColorBlack, isHighlighted()? Palette::Select : KDColorWhite); + ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor); + } + if (m_scriptNode->scriptIndex() != ScriptNode::CurrentScriptIndex) { + ctx->drawString(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(), KDPoint(0, Metric::TableCellVerticalMargin + nameSize.height() + k_verticalMargin), k_font, Palette::GreyDark, backgroundColor); } - ctx->drawString(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(), KDPoint(0, Metric::TableCellVerticalMargin + nameSize.height() + k_verticalMargin), k_font, Palette::GreyDark, isHighlighted()? Palette::Select : KDColorWhite); } KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { @@ -21,7 +31,7 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { return KDSizeZero; } KDSize size1 = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); - KDSize size2 = k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName()); + KDSize size2 = m_scriptNode->scriptIndex() == ScriptNode::CurrentScriptIndex ? KDSizeZero : k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName()); KDSize size3 = KDSizeZero; if (m_scriptNode->type() == ScriptNode::Type::Function) { size3 = k_font->stringSize(ScriptNodeCell::k_parentheses); diff --git a/apps/code/script_node_cell.h b/apps/code/script_node_cell.h index 4367e8c12..df14f9b06 100644 --- a/apps/code/script_node_cell.h +++ b/apps/code/script_node_cell.h @@ -14,7 +14,7 @@ public: TableCell(), m_scriptNodeView() {} - void setScriptNode(ScriptNode * node) { m_scriptNode = scriptNode; } + void setScriptNode(ScriptNode * node); void setScriptStore(ScriptStore * scriptStore) { m_scriptNodeView.setScriptStore(scriptStore); } /* TableCell */ @@ -37,7 +37,7 @@ protected: m_scriptNode(nullptr), m_scriptStore(nullptr) {} - void setScriptNode(ScriptNode * node) { m_scriptNode = scriptNode; } + void setScriptNode(ScriptNode * node) { m_scriptNode = node; } void setScriptStore(ScriptStore * scriptStore) { m_scriptStore = scriptStore; } void drawRect(KDContext * ctx, KDRect rect) const override; virtual KDSize minimalSizeForOptimalDisplay() const override; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 02f003468..8f07eafcb 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -57,9 +57,8 @@ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : m_itemCells[i].setScriptStore(scriptStore); } for (int i = 0; i < k_scriptOriginsCount; i++) { - m_subtitleCells[i].setEven(false); - m_subtitleCells[i].setAlignment(0.0f, 0.5f); - m_subtitleCells[i].setMessageFont(KDFont::SmallFont); + m_subtitleCells[i].setBackgroundColor(Palette::WallScreen); + m_subtitleCells[i].setTextColor(Palette::BlueishGrey); } } @@ -131,7 +130,7 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in I18n::Message::BuiltinFunctionsAndKeyWords, I18n::Message::ImportedModulesAndScripts }; - static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin], Palette::BlueishGrey); + static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin]); } int VariableBoxController::typeAtLocation(int i, int j) { @@ -549,7 +548,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, 1/* TODO LEA*/); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, ScriptNode::CurrentScriptIndex); } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 9d1f91459..2ecce3dc8 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -100,7 +100,7 @@ private: ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedRows]; - EvenOddMessageTextCell m_subtitleCells[k_scriptOriginsCount]; + MessageTableCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; // TODO LEA Put these in an array? int m_currentScriptNodesCount; diff --git a/escher/include/escher/message_table_cell.h b/escher/include/escher/message_table_cell.h index 10a0e795b..c43985d6d 100644 --- a/escher/include/escher/message_table_cell.h +++ b/escher/include/escher/message_table_cell.h @@ -13,8 +13,12 @@ public: void setMessage(I18n::Message message); virtual void setTextColor(KDColor color); void setMessageFont(const KDFont * font); + void setBackgroundColor(KDColor color); +protected: + KDColor backgroundColor() const override { return m_backgroundColor; } private: MessageTextView m_messageTextView; + KDColor m_backgroundColor; }; #endif diff --git a/escher/include/escher/table_cell.h b/escher/include/escher/table_cell.h index e46da7bf6..4cee2b6aa 100644 --- a/escher/include/escher/table_cell.h +++ b/escher/include/escher/table_cell.h @@ -23,6 +23,7 @@ public: virtual View * subAccessoryView() const; void drawRect(KDContext * ctx, KDRect rect) const override; protected: + virtual KDColor backgroundColor() const { return KDColorWhite; } virtual KDCoordinate labelMargin() const { return Metric::TableCellHorizontalMargin; } virtual KDCoordinate accessoryMargin() const { return Metric::TableCellHorizontalMargin; } int numberOfSubviews() const override; diff --git a/escher/src/message_table_cell.cpp b/escher/src/message_table_cell.cpp index 083b55605..103f0b829 100644 --- a/escher/src/message_table_cell.cpp +++ b/escher/src/message_table_cell.cpp @@ -4,7 +4,8 @@ MessageTableCell::MessageTableCell(I18n::Message label, const KDFont * font, Layout layout) : TableCell(layout), - m_messageTextView(font, label, 0, 0.5, KDColorBlack, KDColorWhite) + m_messageTextView(font, label, 0, 0.5, KDColorBlack, KDColorWhite), + m_backgroundColor(KDColorWhite) { } @@ -14,7 +15,7 @@ View * MessageTableCell::labelView() const { void MessageTableCell::setHighlighted(bool highlight) { HighlightCell::setHighlighted(highlight); - KDColor backgroundColor = highlight? Palette::Select : KDColorWhite; + KDColor backgroundColor = highlight? Palette::Select : m_backgroundColor; m_messageTextView.setBackgroundColor(backgroundColor); } @@ -31,3 +32,8 @@ void MessageTableCell::setMessageFont(const KDFont * font) { m_messageTextView.setFont(font); layoutSubviews(); } + +void MessageTableCell::setBackgroundColor(KDColor color) { + m_backgroundColor = color; + m_messageTextView.setBackgroundColor(color); +} diff --git a/escher/src/table_cell.cpp b/escher/src/table_cell.cpp index 85446c28c..dc4845ee2 100644 --- a/escher/src/table_cell.cpp +++ b/escher/src/table_cell.cpp @@ -164,7 +164,7 @@ void TableCell::layoutSubviews(bool force) { } void TableCell::drawRect(KDContext * ctx, KDRect rect) const { - KDColor backgroundColor = isHighlighted() ? Palette::Select : KDColorWhite; - drawInnerRect(ctx, bounds(), backgroundColor); + KDColor backColor = isHighlighted() ? Palette::Select : backgroundColor(); + drawInnerRect(ctx, bounds(), backColor); drawBorderOfRect(ctx, bounds(), Palette::GreyBright); } From d5e1e620fd6db00b32e221a2adf53b21da9c9501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Apr 2020 17:49:08 +0200 Subject: [PATCH 205/453] [apps/code] Display source and description in var box --- apps/code/script_node.h | 12 ++++--- apps/code/script_node_cell.cpp | 48 +++++++++++++++++++++------ apps/code/script_node_cell.h | 9 ++--- apps/code/variable_box_controller.cpp | 31 ++++++++--------- apps/code/variable_box_controller.h | 9 +++-- 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 01864091d..8cb214d11 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -8,25 +8,27 @@ namespace Code { class ScriptNode { public: - constexpr static uint16_t CurrentScriptIndex = -1; enum class Type : bool { Function, Variable }; - ScriptNode(Type type = Type::Variable, const char * name = nullptr, int nameLength = 0, uint16_t scriptIndex = 0) : + ScriptNode(Type type = Type::Variable, const char * name = nullptr, int nameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr) : m_type(type), m_name(name), - m_scriptIndex(-1), + m_nodeSourceName(nodeSourceName), + m_description(description), m_nameLength(nameLength) {} Type type() const { return m_type; } const char * name() const { return m_name; } int nameLength() const { return m_nameLength; } - uint16_t scriptIndex() const { return m_scriptIndex; } + const char * nodeSourceName() const { return m_nodeSourceName; } + const char * description() const { return m_description; } private: Type m_type; const char * m_name; - uint16_t m_scriptIndex; // TODO LEA smaller type ? + const char * m_nodeSourceName; + const char * m_description; int m_nameLength; // TODO LEA smaller type ? }; diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index a56e69966..838ea9b6a 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -7,22 +7,38 @@ namespace Code { constexpr char ScriptNodeCell::k_parentheses[]; constexpr char ScriptNodeCell::k_parenthesesWithEmpty[]; +// TODO LEA remove static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } + void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { const KDColor backgroundColor = isHighlighted()? Palette::Select : KDColorWhite; + /* If it exists, draw the description name. If it did not fit, we would have + * put nullptr at the node creation. */ + const char * descriptionName = m_scriptNode->description(); + bool drawDescription = descriptionName != nullptr; + KDCoordinate rectHeightPerLine = rect.height(); + if (drawDescription) { + rectHeightPerLine = rect.height() / 2; + ctx->drawString(descriptionName, KDPoint(0, rectHeightPerLine + k_verticalMargin / 2), k_font, Palette::GreyDark, backgroundColor); + } + // Draw the node name const char * nodeName = m_scriptNode->name(); const int nodeNameLength = m_scriptNode->nameLength(); - const KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength); - const KDCoordinate nodeNameY = (rect.height() - nameSize.height()) / 2; + KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength); + const KDCoordinate nodeNameY = rectHeightPerLine - k_verticalMargin / 2 - nameSize.height() ; ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength); - // If it is a function, draw the parentheses if (m_scriptNode->type() == ScriptNode::Type::Function) { ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor); } - if (m_scriptNode->scriptIndex() != ScriptNode::CurrentScriptIndex) { - ctx->drawString(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(), KDPoint(0, Metric::TableCellVerticalMargin + nameSize.height() + k_verticalMargin), k_font, Palette::GreyDark, backgroundColor); + + /* If it exists, draw the source name. If it did not fit, we would have put + * nullptr at the node creation. */ + const char * sourceName = m_scriptNode->nodeSourceName(); + if (sourceName != nullptr) { + KDSize sourceNameSize = k_font->stringSize(sourceName); + ctx->drawString(sourceName, KDPoint(rect.width() - sourceNameSize.width(), nodeNameY), k_font, Palette::GreyDark, backgroundColor); } } @@ -30,13 +46,25 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { if (m_scriptNode->name() == nullptr) { return KDSizeZero; } - KDSize size1 = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); - KDSize size2 = m_scriptNode->scriptIndex() == ScriptNode::CurrentScriptIndex ? KDSizeZero : k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName()); - KDSize size3 = KDSizeZero; + return KDSize(300 /*TODO LEA*/, 2*k_topBottomMargin + m_scriptNode->description() == nullptr ? k_font->glyphSize().height() : k_font->glyphSize().height() * 2 + k_verticalMargin); +#if 0 + KDSize nameLineSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); if (m_scriptNode->type() == ScriptNode::Type::Function) { - size3 = k_font->stringSize(ScriptNodeCell::k_parentheses); + nameLineSize = KDSize(nameLineSize.width() + k_font->stringSize(k_parentheses).width(), nameLineSize.height()); } - return KDSize(size1.width() + size3.width() > size2.width() ? size1.width() + size3.width() : size2.width(), Metric::TableCellVerticalMargin + size1.width() + k_verticalMargin + size2.width()); + const char * sourceName = m_scriptNode->nodeSourceName(); + if (sourceName != nullptr) { + KDSize sourceNameSize = k_font->stringSize(sourceName, nodeNameLength); + nameLineSize = KDSize(nameLineSize.width() + sourceNameSize.width() + k_font->glyphSize().width(), nameLineSize.height()); + } + + const char * descriptionName = m_scriptNode->description(); + if (descriptionName == nullptr) { + return nameLineSize; + } + const KDSize descriptionNameSize = k_font->stringSize(descriptionName); + return KDSize(maxCoordinate(nameLineSize.width(), descriptionNameSize.width()),2*Metric::TableCellVerticalMargin + nameLineSize.width() + k_verticalMargin + descriptionNameSize.height()); +#endif } void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) { diff --git a/apps/code/script_node_cell.h b/apps/code/script_node_cell.h index df14f9b06..55068588b 100644 --- a/apps/code/script_node_cell.h +++ b/apps/code/script_node_cell.h @@ -15,7 +15,6 @@ public: m_scriptNodeView() {} void setScriptNode(ScriptNode * node); - void setScriptStore(ScriptStore * scriptStore) { m_scriptNodeView.setScriptStore(scriptStore); } /* TableCell */ View * labelView() const override { return const_cast(static_cast(&m_scriptNodeView)); } @@ -34,21 +33,19 @@ protected: public: ScriptNodeView() : HighlightCell(), - m_scriptNode(nullptr), - m_scriptStore(nullptr) + m_scriptNode(nullptr) {} void setScriptNode(ScriptNode * node) { m_scriptNode = node; } - void setScriptStore(ScriptStore * scriptStore) { m_scriptStore = scriptStore; } void drawRect(KDContext * ctx, KDRect rect) const override; virtual KDSize minimalSizeForOptimalDisplay() const override; const char * text() const override { - return m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(); + return m_scriptNode->description(); } private: constexpr static const KDFont * k_font = KDFont::SmallFont; + constexpr static KDCoordinate k_topBottomMargin = Metric::TableCellVerticalMargin; constexpr static KDCoordinate k_verticalMargin = 7; ScriptNode * m_scriptNode; - ScriptStore * m_scriptStore; }; ScriptNodeView m_scriptNodeView; }; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8f07eafcb..1e20cf5a7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -53,9 +53,6 @@ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : m_builtinNodesCount(0), m_importedNodesCount(0) { - for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { - m_itemCells[i].setScriptStore(scriptStore); - } for (int i = 0; i < k_scriptOriginsCount; i++) { m_subtitleCells[i].setBackgroundColor(Palette::WallScreen); m_subtitleCells[i].setTextColor(Palette::BlueishGrey); @@ -447,7 +444,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); for (int i = 0; i < k_totalBuiltinNodesCount; i++) { - ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name, -1, 0); + ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name); int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); if (startsWith == 0) { m_builtinNodes[m_builtinNodesCount++] = node; @@ -548,7 +545,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength, ScriptNode::CurrentScriptIndex); + addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength); } } @@ -569,7 +566,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } -void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -582,7 +579,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con uint structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(pns); if (structKind == PN_funcdef || structKind == PN_expr_stmt) { // The script is only a single function or variable definition - addImportStruct(pns, structKind, textToAutocomplete, textToAutocompleteLength); + addImportStruct(pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { // The script is is only an import, handled in addNodesFromImportMaybe } else if (structKind == PN_file_input_2) { @@ -597,7 +594,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); if (structKind == PN_funcdef || structKind == PN_expr_stmt) { - addImportStruct(child_pns, structKind, textToAutocomplete, textToAutocompleteLength); + addImportStruct(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); } else { addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); } @@ -634,7 +631,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { // Parsing something like "import math" const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, 1/*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, "math", "desc" /*TODO LEA*/); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { // Parsing something like "from math import sin" addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); @@ -695,7 +692,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par assert(numberOfChildren > numberOfNodesToSkip); for (int i = 3; i < numberOfChildren; i++) { const char * name = I18n::translate((moduleChildren + i)->label()); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); } } else { // Try fetching the nodes from a script @@ -703,7 +700,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par if (!importedScript.isNull()) { const char * scriptContent = importedScript.scriptContent(); assert(scriptContent != nullptr); - loadGlobalAndImportedVariablesInScriptAsImported(scriptContent, textToAutocomplete, textToAutocompleteLength); + loadGlobalAndImportedVariablesInScriptAsImported(importationSourceName, scriptContent, textToAutocomplete, textToAutocompleteLength); } } } @@ -726,23 +723,23 @@ const char * structName(mp_parse_node_struct_t * structNode) { return nullptr; } -void VariableBoxController::addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength) { assert(structKind == PN_funcdef || structKind == PN_expr_stmt); // Find the id child node, which stores the struct's name const char * name = structName(pns); if (name == nullptr) { return; } - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, 1/*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, scriptName); } -void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, int scriptIndex) { +void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, const char * nodeSourceName, const char * description) { if (nodeNameLength < 0) { nodeNameLength = strlen(nodeName); } if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { // Add the node in alphabetical order - addNode(type, origin, nodeName, nodeNameLength, scriptIndex); + addNode(type, origin, nodeName, nodeNameLength, nodeSourceName, description); } } @@ -796,7 +793,7 @@ bool VariableBoxController::contains(const char * name, int nameLength) { return alreadyInVarBox; } -void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex) { +void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName, const char * description) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); int * currentNodeCount = nodesCountPointerForOrigin(origin); if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { @@ -822,7 +819,7 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co nodes[i+1] = nodes[i]; } // Add the node - nodes[insertionIndex] = ScriptNode(type, name, nameLength, scriptIndex); + nodes[insertionIndex] = ScriptNode(type, name, nameLength, nodeSourceName, description); // Increase the node count *currentNodeCount = *currentNodeCount + 1; } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 2ecce3dc8..e43649c9e 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -85,17 +85,16 @@ private: void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); - void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); + void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); // Returns true if this was an import structure bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); - void addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * textToAutocomplete, int textToAutocompleteLength); + void addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength); /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ - void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); + void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); bool contains(const char * name, int nameLength); - void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, int scriptIndex = 0); - + void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; From 1d416b329930ceef01a04009298ebc9b588e94a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 10 Apr 2020 17:01:36 +0200 Subject: [PATCH 206/453] [apps/code] Fix varbox row height --- apps/code/variable_box_controller.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 1e20cf5a7..3a1563a34 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -75,9 +75,15 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp } KDCoordinate VariableBoxController::rowHeight(int j) { - int cellType = typeAndOriginAtLocation(j); + NodeOrigin cellOrigin = NodeOrigin::CurrentScript; + int cumulatedOriginsCount = 0; + int cellType = typeAndOriginAtLocation(j, &cellOrigin, &cumulatedOriginsCount); if (cellType == k_itemCellType) { - return k_simpleItemRowHeight; // TODO LEA + //TODO LEA if cellOrigin == Imported? + if (scriptNodeAtIndex(j - cumulatedOriginsCount)->description() != nullptr) { + return k_complexItemRowHeight; + } + return k_simpleItemRowHeight; } assert(cellType == k_subtitleCellType); return k_subtitleRowHeight; From 38854d2435a9cc04d6eb962bba61701adc3dc96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 10 Apr 2020 17:11:29 +0200 Subject: [PATCH 207/453] [apps/code] Fix cell type --- apps/code/variable_box_controller.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index e43649c9e..4a6cd9570 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -36,8 +36,8 @@ private: constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 98; constexpr static uint8_t k_scriptOriginsCount = 3; - constexpr static uint8_t k_subtitleCellType = 0; - constexpr static uint8_t k_itemCellType = 1; + constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable + constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf constexpr static KDCoordinate k_subtitleRowHeight = 23; constexpr static KDCoordinate k_simpleItemRowHeight = 27; constexpr static KDCoordinate k_complexItemRowHeight = 44; From 03471bb7b4e51391536b80da472938ec30972c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 10 Apr 2020 17:16:12 +0200 Subject: [PATCH 208/453] [apps/code] Insert right text form var box The text was iffset due to the subtitle rows --- apps/code/variable_box_controller.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3a1563a34..196a4f7e9 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -316,7 +316,12 @@ int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOri bool VariableBoxController::selectLeaf(int rowIndex) { assert(rowIndex >= 0 && rowIndex < numberOfRows()); m_selectableTableView.deselectTable(); - ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex); + + int cumulatedOriginsCount = 0; + int cellType = typeAndOriginAtLocation(rowIndex, nullptr, &cumulatedOriginsCount); + assert(cellType == k_itemCellType); + (void)cellType; // Silence warnings + ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); if (selectedScriptNode->type() == ScriptNode::Type::Function) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); From b41d1e393e94c4beede08d73284fe4448d958487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 10 Apr 2020 17:35:39 +0200 Subject: [PATCH 209/453] [apps/code] Autocomplete when cursor at the end of the word Not just after adding or deleting text --- apps/code/python_text_area.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 46988f079..73ec016d1 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -236,7 +236,8 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { } } bool result = TextArea::handleEvent(event); - if (event == Ion::Events::Backspace) { + if (!m_contentView.isAutocompleting() && selectionIsEmpty()) { + // Add autocompletion after each event handled, if nothing is selected addAutocompletion(); } return result; From b3d87c0e18bb57e3b86cb5a5af4f956d6e122ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 14 Apr 2020 17:41:54 +0200 Subject: [PATCH 210/453] [escher/stack_view_controller] Inline some methods --- escher/include/escher/stack_view_controller.h | 4 ++-- escher/src/stack_view_controller.cpp | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/escher/include/escher/stack_view_controller.h b/escher/include/escher/stack_view_controller.h index 02d6318fc..48bf9a114 100644 --- a/escher/include/escher/stack_view_controller.h +++ b/escher/include/escher/stack_view_controller.h @@ -16,8 +16,8 @@ public: void push(ViewController * vc, KDColor textColor = Palette::SubTab, KDColor backgroundColor = KDColorWhite, KDColor separatorColor = Palette::GreyBright); void pop(); - int depth(); - View * view() override; + int depth() const { return m_numberOfChildren; } + View * view() override { return &m_view; } ViewController * topViewController(); const char * title() override; bool handleEvent(Ion::Events::Event event) override; diff --git a/escher/src/stack_view_controller.cpp b/escher/src/stack_view_controller.cpp index 2b88c2288..1b32e0879 100644 --- a/escher/src/stack_view_controller.cpp +++ b/escher/src/stack_view_controller.cpp @@ -129,10 +129,6 @@ void StackViewController::pop() { vc->viewDidDisappear(); } -int StackViewController::depth() { - return m_numberOfChildren; -} - void StackViewController::pushModel(Frame frame) { m_childrenFrame[m_numberOfChildren++] = frame; } @@ -160,10 +156,6 @@ bool StackViewController::handleEvent(Ion::Events::Event event) { return false; } -View * StackViewController::view() { - return &m_view; -} - void StackViewController::initView() { m_childrenFrame[0].viewController()->initView(); } From 3d64b8dc479222d89cc24288761596b942ae14d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 14 Apr 2020 18:00:17 +0200 Subject: [PATCH 211/453] [apps] AlternateEmptyNestedMenuController handles empty lists --- apps/Makefile | 1 + ...alternate_empty_nested_menu_controller.cpp | 18 +++++++++++ apps/alternate_empty_nested_menu_controller.h | 19 ++++++++++++ apps/variable_box_controller.cpp | 30 +++++++------------ apps/variable_box_controller.h | 8 ++--- 5 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 apps/alternate_empty_nested_menu_controller.cpp create mode 100644 apps/alternate_empty_nested_menu_controller.h diff --git a/apps/Makefile b/apps/Makefile index f7392f395..d6f4adef4 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -12,6 +12,7 @@ apps = $(foreach i,${EPSILON_APPS},$(eval include apps/$(i)/Makefile)) apps_src += $(addprefix apps/,\ + alternate_empty_nested_menu_controller.cpp \ apps_container.cpp \ apps_container_launch_default.cpp:-onboarding \ apps_container_launch_on_boarding.cpp:+onboarding \ diff --git a/apps/alternate_empty_nested_menu_controller.cpp b/apps/alternate_empty_nested_menu_controller.cpp new file mode 100644 index 000000000..b09acca75 --- /dev/null +++ b/apps/alternate_empty_nested_menu_controller.cpp @@ -0,0 +1,18 @@ +#include "alternate_empty_nested_menu_controller.h" + +void AlternateEmptyNestedMenuController::viewDidDisappear() { + if (isDisplayingEmptyController()) { + pop(); + } + NestedMenuController::viewDidDisappear(); +} + +bool AlternateEmptyNestedMenuController::displayEmptyController() { + assert(!isDisplayingEmptyController()); + // If the content is empty, we push an empty controller. + if (numberOfRows() == 0) { + push(emptyViewController()); + return true; + } + return false; +} diff --git a/apps/alternate_empty_nested_menu_controller.h b/apps/alternate_empty_nested_menu_controller.h new file mode 100644 index 000000000..0427a2bf8 --- /dev/null +++ b/apps/alternate_empty_nested_menu_controller.h @@ -0,0 +1,19 @@ +#ifndef APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H +#define APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H + +#include + +class AlternateEmptyNestedMenuController : public NestedMenuController { +public: + AlternateEmptyNestedMenuController(I18n::Message title) : + NestedMenuController(nullptr, title) + {} + // View Controller + void viewDidDisappear() override; +protected: + virtual ViewController * emptyViewController() = 0; + virtual bool isDisplayingEmptyController() = 0; + bool displayEmptyController(); +}; + +#endif diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 5b5f41dce..4637220b3 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -15,7 +15,7 @@ using namespace Shared; using namespace Ion; VariableBoxController::VariableBoxController() : - NestedMenuController(nullptr, I18n::Message::Variables), + AlternateEmptyNestedMenuController(I18n::Message::Variables), m_currentPage(Page::RootMenu), m_lockPageDelete(Page::RootMenu), m_firstMemoizedLayoutIndex(0) @@ -27,15 +27,11 @@ VariableBoxController::VariableBoxController() : void VariableBoxController::viewWillAppear() { assert(m_currentPage == Page::RootMenu); - NestedMenuController::viewWillAppear(); + AlternateEmptyNestedMenuController::viewWillAppear(); } void VariableBoxController::viewDidDisappear() { - if (isDisplayingEmptyController()) { - pop(); - } - - NestedMenuController::viewDidDisappear(); + AlternateEmptyNestedMenuController::viewDidDisappear(); /* NestedMenuController::viewDidDisappear might need cell heights, which would * use the VariableBoxController cell heights memoization. We thus reset the @@ -69,7 +65,7 @@ bool VariableBoxController::handleEvent(Ion::Events::Event event) { displayEmptyController(); return true; } - return NestedMenuController::handleEvent(event); + return AlternateEmptyNestedMenuController::handleEvent(event); } int VariableBoxController::numberOfRows() const { @@ -130,7 +126,7 @@ KDCoordinate VariableBoxController::rowHeight(int index) { return std::max(layoutR.layoutSize().height()+k_leafMargin, Metric::ToolboxRowHeight); } } - return NestedMenuController::rowHeight(index); + return AlternateEmptyNestedMenuController::rowHeight(index); } int VariableBoxController::typeAtLocation(int i, int j) { @@ -163,7 +159,7 @@ void VariableBoxController::setPage(Page page) { bool VariableBoxController::selectSubMenu(int selectedRow) { m_selectableTableView.deselectTable(); setPage(pageAtIndex(selectedRow)); - bool selectSubMenu = NestedMenuController::selectSubMenu(selectedRow); + bool selectSubMenu = AlternateEmptyNestedMenuController::selectSubMenu(selectedRow); if (displayEmptyController()) { return true; } @@ -177,7 +173,7 @@ bool VariableBoxController::returnToPreviousMenu() { m_selectableTableView.deselectTable(); } setPage(Page::RootMenu); - return NestedMenuController::returnToPreviousMenu(); + return AlternateEmptyNestedMenuController::returnToPreviousMenu(); } bool VariableBoxController::selectLeaf(int selectedRow) { @@ -261,15 +257,9 @@ Storage::Record VariableBoxController::recordAtIndex(int rowIndex) { return Storage::sharedStorage()->recordWithExtensionAtIndex(extension(), rowIndex); } -bool VariableBoxController::displayEmptyController() { - assert(!isDisplayingEmptyController()); - // If the content is empty, we push above an empty controller. - if (numberOfRows() == 0) { - m_emptyViewController.setType((VariableBoxEmptyController::Type)m_currentPage); - push(&m_emptyViewController); - return true; - } - return false; +ViewController * VariableBoxController::emptyViewController() { + m_emptyViewController.setType((VariableBoxEmptyController::Type)m_currentPage); + return &m_emptyViewController; } void VariableBoxController::resetMemoization() { diff --git a/apps/variable_box_controller.h b/apps/variable_box_controller.h index 95824e29d..affb031fd 100644 --- a/apps/variable_box_controller.h +++ b/apps/variable_box_controller.h @@ -3,11 +3,11 @@ #define MATRIX_VARIABLES 1 -#include +#include "alternate_empty_nested_menu_controller.h" #include "variable_box_empty_controller.h" #include -class VariableBoxController : public NestedMenuController { +class VariableBoxController : public AlternateEmptyNestedMenuController { public: VariableBoxController(); @@ -47,8 +47,8 @@ private: Poincare::Layout expressionLayoutForRecord(Ion::Storage::Record record, int index); const char * extension() const; Ion::Storage::Record recordAtIndex(int rowIndex); - bool displayEmptyController(); - bool isDisplayingEmptyController() { return StackViewController::depth() == 2; } + ViewController * emptyViewController() override; + bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } void resetMemoization(); void destroyRecordAtRowIndex(int rowIndex); Page m_currentPage; From 74b786f875eb68e609a8e0c8c217f6d77b636b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 15 Apr 2020 15:22:55 +0200 Subject: [PATCH 212/453] [apps/code] Add list methods to the variable box --- apps/code/variable_box_controller.cpp | 9 +++++++++ apps/code/variable_box_controller.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 196a4f7e9..6df01771b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -351,6 +351,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, {"and", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_any), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_append), ScriptNode::Type::Function}, {"as", ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::Function}, {"assert", ScriptNode::Type::Variable}, @@ -364,10 +365,12 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, {"class", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_clear), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_cmath), ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, {"continue", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_count), ScriptNode::Type::Function}, {"def", ScriptNode::Type::Variable}, {"del", ScriptNode::Type::Variable}, //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, @@ -398,7 +401,9 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {"if", ScriptNode::Type::Variable}, {"import", ScriptNode::Type::Variable}, {"in", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_index), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_insert), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_ion), ScriptNode::Type::Variable}, {"is", ScriptNode::Type::Variable}, @@ -425,18 +430,22 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_ord), ScriptNode::Type::Function}, {"pass", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_pow), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_pop), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, {"raise", ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_random), ScriptNode::Type::Variable}, {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_remove), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, {"return", ScriptNode::Type::Variable}, + {qstr_str(MP_QSTR_reverse), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_reversed), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, //{qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, + {qstr_str(MP_QSTR_sort), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 4a6cd9570..c4c2040b6 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -34,7 +34,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA constexpr static int k_maxScriptNodesCount = 32; //TODO LEA - constexpr static int k_totalBuiltinNodesCount = 98; + constexpr static int k_totalBuiltinNodesCount = 107; constexpr static uint8_t k_scriptOriginsCount = 3; constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf From bbeb17c3a9012c28d824eaa66f144e5d3dfb8043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 15 Apr 2020 15:30:12 +0200 Subject: [PATCH 213/453] [apps/code] Rename ScriptNode::Types to With/WithoutParentheses Because some functions already have the parentheses in their name, so their type would have been Variable but it is clearer to give it the type WithoutParentheses. this is the case for nodes created from toolbox nodes. --- apps/code/script_node.h | 6 +- apps/code/script_node_cell.cpp | 4 +- apps/code/variable_box_controller.cpp | 246 +++++++++++++------------- 3 files changed, 128 insertions(+), 128 deletions(-) diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 8cb214d11..695d7ae9b 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -9,10 +9,10 @@ namespace Code { class ScriptNode { public: enum class Type : bool { - Function, - Variable + WithoutParentheses, + WithParentheses }; - ScriptNode(Type type = Type::Variable, const char * name = nullptr, int nameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr) : + ScriptNode(Type type = Type::WithoutParentheses, const char * name = nullptr, int nameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr) : m_type(type), m_name(name), m_nodeSourceName(nodeSourceName), diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index 838ea9b6a..97b86a88a 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -29,7 +29,7 @@ void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) cons const KDCoordinate nodeNameY = rectHeightPerLine - k_verticalMargin / 2 - nameSize.height() ; ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength); // If it is a function, draw the parentheses - if (m_scriptNode->type() == ScriptNode::Type::Function) { + if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) { ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor); } @@ -49,7 +49,7 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { return KDSize(300 /*TODO LEA*/, 2*k_topBottomMargin + m_scriptNode->description() == nullptr ? k_font->glyphSize().height() : k_font->glyphSize().height() * 2 + k_verticalMargin); #if 0 KDSize nameLineSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); - if (m_scriptNode->type() == ScriptNode::Type::Function) { + if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) { nameLineSize = KDSize(nameLineSize.width() + k_font->stringSize(k_parentheses).width(), nameLineSize.height()); } const char * sourceName = m_scriptNode->nodeSourceName(); diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 6df01771b..07d0e1a61 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -323,7 +323,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { (void)cellType; // Silence warnings ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); - if (selectedScriptNode->type() == ScriptNode::Type::Function) { + if (selectedScriptNode->type() == ScriptNode::Type::WithParentheses) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } Container::activeApp()->dismissModalViewController(); @@ -343,124 +343,124 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) //TODO LEA add matplotlib.pyplot static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { - {"False", ScriptNode::Type::Variable}, - {"None", ScriptNode::Type::Variable}, - {"True", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR___import__), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_abs), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_all), ScriptNode::Type::Function}, - {"and", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_any), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_append), ScriptNode::Type::Function}, - {"as", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::Function}, - {"assert", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_bin), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bool), ScriptNode::Type::Function}, - {"break", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_bytearray), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_bytes), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_callable), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_chr), ScriptNode::Type::Function}, - {"class", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_clear), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_cmath), ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_compile), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_complex), ScriptNode::Type::Function}, - {"continue", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_count), ScriptNode::Type::Function}, - {"def", ScriptNode::Type::Variable}, - {"del", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_dict), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_dir), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_divmod), ScriptNode::Type::Function}, - {"elif", ScriptNode::Type::Variable}, - {"else", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_enumerate), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_eval), ScriptNode::Type::Function}, - {"except", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_exec), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_filter), ScriptNode::Type::Function}, - {"finally", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_float), ScriptNode::Type::Function}, - {"for", ScriptNode::Type::Variable}, - //{qstr_str(MP_QSTR_format), ScriptNode::Type::Function}, - {"from", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_getattr), ScriptNode::Type::Function}, - {"global", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_globals), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hasattr), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hash), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_help), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_hex), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_id), ScriptNode::Type::Function}, - {"if", ScriptNode::Type::Variable}, - {"import", ScriptNode::Type::Variable}, - {"in", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_index), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_input), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_insert), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_int), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_ion), ScriptNode::Type::Variable}, - {"is", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_iter), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_kandinsky), ScriptNode::Type::Variable}, - {"lambda", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_len), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_list), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_locals), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_map), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_math), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_max), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_min), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_next), ScriptNode::Type::Function}, - {"nonlocal", ScriptNode::Type::Variable}, - {"not", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_object), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_oct), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_open), ScriptNode::Type::Function}, - {"or", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_ord), ScriptNode::Type::Function}, - {"pass", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_pow), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_pop), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_print), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_property), ScriptNode::Type::Function}, - {"raise", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_random), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_range), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_remove), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_repr), ScriptNode::Type::Function}, - {"return", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_reverse), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_reversed), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_round), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_set), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_setattr), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_slice), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_sort), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_sorted), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_str), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_sum), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_super), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_time), ScriptNode::Type::Variable}, - {"try", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_tuple), ScriptNode::Type::Function}, - {qstr_str(MP_QSTR_turtle), ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_type), ScriptNode::Type::Function}, - //{qstr_str(MP_QSTR_vars), ScriptNode::Type::Function}, - {"while", ScriptNode::Type::Variable}, - {"with", ScriptNode::Type::Variable}, - {"yield", ScriptNode::Type::Variable}, - {qstr_str(MP_QSTR_zip), ScriptNode::Type::Function} + {"False", ScriptNode::Type::WithoutParentheses}, + {"None", ScriptNode::Type::WithoutParentheses}, + {"True", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR___import__), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_abs), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_all), ScriptNode::Type::WithParentheses}, + {"and", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_any), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_append), ScriptNode::Type::WithParentheses}, + {"as", ScriptNode::Type::WithoutParentheses}, + //{qstr_str(MP_QSTR_ascii), ScriptNode::Type::WithParentheses}, + {"assert", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_bin), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_bool), ScriptNode::Type::WithParentheses}, + {"break", ScriptNode::Type::WithoutParentheses}, + //{qstr_str(MP_QSTR_breakpoint), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_bytearray), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_bytes), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_callable), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_chr), ScriptNode::Type::WithParentheses}, + {"class", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_classmethod), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_clear), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_cmath), ScriptNode::Type::WithoutParentheses}, + //{qstr_str(MP_QSTR_compile), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_complex), ScriptNode::Type::WithParentheses}, + {"continue", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_count), ScriptNode::Type::WithParentheses}, + {"def", ScriptNode::Type::WithoutParentheses}, + {"del", ScriptNode::Type::WithoutParentheses}, + //{qstr_str(MP_QSTR_delattr), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_dict), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_dir), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_divmod), ScriptNode::Type::WithParentheses}, + {"elif", ScriptNode::Type::WithoutParentheses}, + {"else", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_enumerate), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_eval), ScriptNode::Type::WithParentheses}, + {"except", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_exec), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_filter), ScriptNode::Type::WithParentheses}, + {"finally", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_float), ScriptNode::Type::WithParentheses}, + {"for", ScriptNode::Type::WithoutParentheses}, + //{qstr_str(MP_QSTR_format), ScriptNode::Type::WithParentheses}, + {"from", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_frozenset), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_getattr), ScriptNode::Type::WithParentheses}, + {"global", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_globals), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_hasattr), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_hash), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_help), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_hex), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_id), ScriptNode::Type::WithParentheses}, + {"if", ScriptNode::Type::WithoutParentheses}, + {"import", ScriptNode::Type::WithoutParentheses}, + {"in", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_index), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_input), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_insert), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_int), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_ion), ScriptNode::Type::WithoutParentheses}, + {"is", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_isinstance), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_issubclass), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_iter), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_kandinsky), ScriptNode::Type::WithoutParentheses}, + {"lambda", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_len), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_list), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_locals), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_map), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_math), ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_max), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_min), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_next), ScriptNode::Type::WithParentheses}, + {"nonlocal", ScriptNode::Type::WithoutParentheses}, + {"not", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_object), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_oct), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_open), ScriptNode::Type::WithParentheses}, + {"or", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_ord), ScriptNode::Type::WithParentheses}, + {"pass", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_pow), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_pop), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_print), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_property), ScriptNode::Type::WithParentheses}, + {"raise", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_random), ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_range), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_remove), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_repr), ScriptNode::Type::WithParentheses}, + {"return", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_reverse), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_reversed), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_round), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_set), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_setattr), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_slice), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_sort), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_sorted), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_staticmethod), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_str), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_sum), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_super), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_time), ScriptNode::Type::WithoutParentheses}, + {"try", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_tuple), ScriptNode::Type::WithParentheses}, + {qstr_str(MP_QSTR_turtle), ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_type), ScriptNode::Type::WithParentheses}, + //{qstr_str(MP_QSTR_vars), ScriptNode::Type::WithParentheses}, + {"while", ScriptNode::Type::WithoutParentheses}, + {"with", ScriptNode::Type::WithoutParentheses}, + {"yield", ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_zip), ScriptNode::Type::WithParentheses} }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); for (int i = 0; i < k_totalBuiltinNodesCount; i++) { @@ -565,7 +565,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::CurrentScript, tokenInText, nameLength); + addNode(defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses, NodeOrigin::CurrentScript, tokenInText, nameLength); } } @@ -651,7 +651,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { // Parsing something like "import math" const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, id, -1, "math", "desc" /*TODO LEA*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, "math", "desc" /*TODO LEA*/); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { // Parsing something like "from math import sin" addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); @@ -712,7 +712,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par assert(numberOfChildren > numberOfNodesToSkip); for (int i = 3; i < numberOfChildren; i++) { const char * name = I18n::translate((moduleChildren + i)->label()); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); } } else { // Try fetching the nodes from a script @@ -750,7 +750,7 @@ void VariableBoxController::addImportStruct(mp_parse_node_struct_t * pns, uint s if (name == nullptr) { return; } - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::Function : ScriptNode::Type::Variable, NodeOrigin::Importation, name, -1, scriptName); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, scriptName); } void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, const char * nodeSourceName, const char * description) { From 0d6016116dc84161b72b8804fd7d9d6886c67c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 15 Apr 2020 16:03:39 +0200 Subject: [PATCH 214/453] [apps/code] Cosmetic fixes on the variable box --- apps/code/script_node_cell.cpp | 42 +++++++-------------------- apps/code/script_node_cell.h | 7 +++-- apps/code/variable_box_controller.cpp | 4 +-- apps/code/variable_box_controller.h | 3 +- escher/include/escher/table_cell.h | 4 +-- escher/src/table_cell.cpp | 8 ++--- 6 files changed, 23 insertions(+), 45 deletions(-) diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index 97b86a88a..e76c46274 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -7,38 +7,32 @@ namespace Code { constexpr char ScriptNodeCell::k_parentheses[]; constexpr char ScriptNodeCell::k_parenthesesWithEmpty[]; -// TODO LEA remove static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } - void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { const KDColor backgroundColor = isHighlighted()? Palette::Select : KDColorWhite; - /* If it exists, draw the description name. If it did not fit, we would have - * put nullptr at the node creation. */ + // If it exists, draw the description name. const char * descriptionName = m_scriptNode->description(); - bool drawDescription = descriptionName != nullptr; - KDCoordinate rectHeightPerLine = rect.height(); - if (drawDescription) { - rectHeightPerLine = rect.height() / 2; - ctx->drawString(descriptionName, KDPoint(0, rectHeightPerLine + k_verticalMargin / 2), k_font, Palette::GreyDark, backgroundColor); + if (descriptionName != nullptr) { + ctx->drawString(descriptionName, KDPoint(0, m_frame.height() - k_bottomMargin - k_font->glyphSize().height()), k_font, Palette::GreyDark, backgroundColor); } // Draw the node name const char * nodeName = m_scriptNode->name(); const int nodeNameLength = m_scriptNode->nameLength(); KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength); - const KDCoordinate nodeNameY = rectHeightPerLine - k_verticalMargin / 2 - nameSize.height() ; + const KDCoordinate nodeNameY = k_topMargin; ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength); - // If it is a function, draw the parentheses + // If it is needed, draw the parentheses if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) { ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor); } /* If it exists, draw the source name. If it did not fit, we would have put - * nullptr at the node creation. */ + * nullptr at the node creation. TODO LEA */ const char * sourceName = m_scriptNode->nodeSourceName(); if (sourceName != nullptr) { KDSize sourceNameSize = k_font->stringSize(sourceName); - ctx->drawString(sourceName, KDPoint(rect.width() - sourceNameSize.width(), nodeNameY), k_font, Palette::GreyDark, backgroundColor); + ctx->drawString(sourceName, KDPoint(m_frame.width() - sourceNameSize.width(), nodeNameY), k_font, Palette::GreyDark, backgroundColor); } } @@ -46,25 +40,9 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { if (m_scriptNode->name() == nullptr) { return KDSizeZero; } - return KDSize(300 /*TODO LEA*/, 2*k_topBottomMargin + m_scriptNode->description() == nullptr ? k_font->glyphSize().height() : k_font->glyphSize().height() * 2 + k_verticalMargin); -#if 0 - KDSize nameLineSize = k_font->stringSize(m_scriptNode->name(), m_scriptNode->nameLength()); - if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) { - nameLineSize = KDSize(nameLineSize.width() + k_font->stringSize(k_parentheses).width(), nameLineSize.height()); - } - const char * sourceName = m_scriptNode->nodeSourceName(); - if (sourceName != nullptr) { - KDSize sourceNameSize = k_font->stringSize(sourceName, nodeNameLength); - nameLineSize = KDSize(nameLineSize.width() + sourceNameSize.width() + k_font->glyphSize().width(), nameLineSize.height()); - } - - const char * descriptionName = m_scriptNode->description(); - if (descriptionName == nullptr) { - return nameLineSize; - } - const KDSize descriptionNameSize = k_font->stringSize(descriptionName); - return KDSize(maxCoordinate(nameLineSize.width(), descriptionNameSize.width()),2*Metric::TableCellVerticalMargin + nameLineSize.width() + k_verticalMargin + descriptionNameSize.height()); -#endif + return KDSize( + Ion::Display::Width - Metric::PopUpLeftMargin - Metric::PopUpRightMargin, + m_scriptNode->description() == nullptr ? k_simpleItemHeight : k_complexItemHeight); } void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) { diff --git a/apps/code/script_node_cell.h b/apps/code/script_node_cell.h index 55068588b..12c1b7a7b 100644 --- a/apps/code/script_node_cell.h +++ b/apps/code/script_node_cell.h @@ -27,7 +27,8 @@ public: static_assert('\x11' == UCodePointEmpty, "Unicode error"); constexpr static char k_parentheses[] = "()"; constexpr static char k_parenthesesWithEmpty[] = "(\x11)"; - + constexpr static KDCoordinate k_simpleItemHeight = 27; + constexpr static KDCoordinate k_complexItemHeight = 42; protected: class ScriptNodeView : public HighlightCell { public: @@ -43,8 +44,8 @@ protected: } private: constexpr static const KDFont * k_font = KDFont::SmallFont; - constexpr static KDCoordinate k_topBottomMargin = Metric::TableCellVerticalMargin; - constexpr static KDCoordinate k_verticalMargin = 7; + constexpr static KDCoordinate k_bottomMargin = 5; + constexpr static KDCoordinate k_topMargin = k_bottomMargin + k_separatorThickness; ScriptNode * m_scriptNode; }; ScriptNodeView m_scriptNodeView; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 07d0e1a61..14908fb71 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -81,9 +81,9 @@ KDCoordinate VariableBoxController::rowHeight(int j) { if (cellType == k_itemCellType) { //TODO LEA if cellOrigin == Imported? if (scriptNodeAtIndex(j - cumulatedOriginsCount)->description() != nullptr) { - return k_complexItemRowHeight; + return ScriptNodeCell::k_complexItemHeight; } - return k_simpleItemRowHeight; + return ScriptNodeCell::k_simpleItemHeight; } assert(cellType == k_subtitleCellType); return k_subtitleRowHeight; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index c4c2040b6..bc55ab290 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -39,8 +39,7 @@ private: constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf constexpr static KDCoordinate k_subtitleRowHeight = 23; - constexpr static KDCoordinate k_simpleItemRowHeight = 27; - constexpr static KDCoordinate k_complexItemRowHeight = 44; + enum class NodeOrigin : uint8_t { CurrentScript = 0, Builtins = 1, diff --git a/escher/include/escher/table_cell.h b/escher/include/escher/table_cell.h index 4cee2b6aa..d2d2b086c 100644 --- a/escher/include/escher/table_cell.h +++ b/escher/include/escher/table_cell.h @@ -24,8 +24,8 @@ public: void drawRect(KDContext * ctx, KDRect rect) const override; protected: virtual KDColor backgroundColor() const { return KDColorWhite; } - virtual KDCoordinate labelMargin() const { return Metric::TableCellHorizontalMargin; } - virtual KDCoordinate accessoryMargin() const { return Metric::TableCellHorizontalMargin; } + virtual KDCoordinate labelMargin() const { return k_horizontalMargin; } + virtual KDCoordinate accessoryMargin() const { return k_horizontalMargin; } int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; diff --git a/escher/src/table_cell.cpp b/escher/src/table_cell.cpp index dc4845ee2..0740a5630 100644 --- a/escher/src/table_cell.cpp +++ b/escher/src/table_cell.cpp @@ -98,16 +98,16 @@ void TableCell::layoutSubviews(bool force) { y += labelHeight + k_verticalMargin; } horizontalMargin = k_separatorThickness + k_horizontalMargin; - y = std::max(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin) - withMargin(subAccessorySize.height(), 0)); + y = std::max(y, height - k_separatorThickness - withMargin(accessorySize.height(), k_verticalMargin) - withMargin(subAccessorySize.height(), 0)); if (subAccessory) { - KDCoordinate subAccessoryHeight = std::min(subAccessorySize.height(), height - y - k_separatorThickness - Metric::TableCellVerticalMargin); + KDCoordinate subAccessoryHeight = std::min(subAccessorySize.height(), height - y - k_separatorThickness - k_verticalMargin); accessory->setFrame(KDRect(horizontalMargin, y, width - 2*horizontalMargin, subAccessoryHeight), force); y += subAccessoryHeight; } horizontalMargin = k_separatorThickness + accessoryMargin(); - y = std::max(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin)); + y = std::max(y, height - k_separatorThickness - withMargin(accessorySize.height(), k_verticalMargin)); if (accessory) { - KDCoordinate accessoryHeight = std::min(accessorySize.height(), height - y - k_separatorThickness - Metric::TableCellVerticalMargin); + KDCoordinate accessoryHeight = std::min(accessorySize.height(), height - y - k_separatorThickness - k_verticalMargin); accessory->setFrame(KDRect(horizontalMargin, y, width - 2*horizontalMargin, accessoryHeight), force); } } else { From 33d8d10286345d5ea89910f34e22f1a486259cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 15 Apr 2020 17:48:59 +0200 Subject: [PATCH 215/453] [apps/code] Do not select subtitles in the variable box --- apps/code/variable_box_controller.cpp | 14 ++++++++++++++ apps/code/variable_box_controller.h | 2 ++ escher/include/escher/nested_menu_controller.h | 2 +- escher/src/nested_menu_controller.cpp | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 14908fb71..03103d8f2 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -136,6 +136,20 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin]); } +void VariableBoxController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { + if (withinTemporarySelection) { + return; + } + const int currentSelectedRow = selectedRow(); + if (typeAtLocation(0, currentSelectedRow) == k_subtitleCellType) { + if (currentSelectedRow == 0) { + t->selectCellAtLocation(0, 1); + } else { + t->selectCellAtLocation(0, selectedRow() + (previousSelectedCellY < currentSelectedRow ? 1 : -1)); + } + } +} + int VariableBoxController::typeAtLocation(int i, int j) { assert(i == 0); return typeAndOriginAtLocation(j); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index bc55ab290..3cfb63bf8 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -24,6 +24,8 @@ public: int typeAtLocation(int i, int j) override; /* ListViewDataSource */ void willDisplayCellForIndex(HighlightCell * cell, int index) override; + /* SelectableTableViewDelegate */ + void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); diff --git a/escher/include/escher/nested_menu_controller.h b/escher/include/escher/nested_menu_controller.h index 0037d9c90..1cc2ab1ad 100644 --- a/escher/include/escher/nested_menu_controller.h +++ b/escher/include/escher/nested_menu_controller.h @@ -7,7 +7,7 @@ #include #include -class NestedMenuController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource { +class NestedMenuController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate { public: NestedMenuController(Responder * parentResponder, I18n::Message title = (I18n::Message)0); void setSender(InputEventHandler * sender) { m_sender = sender; } diff --git a/escher/src/nested_menu_controller.cpp b/escher/src/nested_menu_controller.cpp index 44b80456a..12d0263ae 100644 --- a/escher/src/nested_menu_controller.cpp +++ b/escher/src/nested_menu_controller.cpp @@ -90,7 +90,7 @@ void NestedMenuController::ListController::setFirstSelectedRow(int firstSelected NestedMenuController::NestedMenuController(Responder * parentResponder, I18n::Message title) : StackViewController(parentResponder, &m_listController, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), - m_selectableTableView(&m_listController, this, this), + m_selectableTableView(&m_listController, this, this, this), m_listController(this, &m_selectableTableView, title), m_sender(nullptr) { From f37112670890c2b84e2160f7eda56ae225999a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 17 Apr 2020 15:05:31 +0200 Subject: [PATCH 216/453] [apps/code] Fix assertion --- apps/code/python_text_area.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 73ec016d1..3e335a12d 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -259,8 +259,10 @@ void PythonTextArea::removeAutocompletion() { assert(m_contentView.isAutocompleting()); const char * autocompleteStart = m_contentView.cursorLocation(); const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); - assert(autocompleteEnd > autocompleteStart); - m_contentView.removeText(autocompleteStart, autocompleteEnd); + assert(autocompleteEnd >= autocompleteStart); + if (autocompleteEnd > autocompleteStart) { + m_contentView.removeText(autocompleteStart, autocompleteEnd); + } m_contentView.setAutocompleting(false); } From f98c171d2acb5b9d50638c76ea97791f81e5beb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 17 Apr 2020 16:21:41 +0200 Subject: [PATCH 217/453] [apps/variable_box] Prepare for Code::VariableBox factorization --- apps/Makefile | 3 +- apps/apps_container.cpp | 2 +- apps/apps_container.h | 6 +- apps/graph/app.cpp | 4 +- ...r.cpp => math_variable_box_controller.cpp} | 56 ++++---- ...oller.h => math_variable_box_controller.h} | 15 +-- apps/math_variable_box_empty_controller.cpp | 53 ++++++++ apps/math_variable_box_empty_controller.h | 41 ++++++ .../input_event_handler_delegate_app.cpp | 4 +- apps/variable_box_empty_controller.cpp | 123 +++++++----------- apps/variable_box_empty_controller.h | 31 ++--- 11 files changed, 198 insertions(+), 140 deletions(-) rename apps/{variable_box_controller.cpp => math_variable_box_controller.cpp} (82%) rename apps/{variable_box_controller.h => math_variable_box_controller.h} (88%) create mode 100644 apps/math_variable_box_empty_controller.cpp create mode 100644 apps/math_variable_box_empty_controller.h diff --git a/apps/Makefile b/apps/Makefile index d6f4adef4..3d73f627b 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -34,10 +34,11 @@ apps_src += $(addprefix apps/,\ lock_view.cpp \ main.cpp \ math_toolbox.cpp \ + math_variable_box_controller.cpp \ + math_variable_box_empty_controller.cpp \ shift_alpha_lock_view.cpp \ suspend_timer.cpp \ title_bar_view.cpp \ - variable_box_controller.cpp \ variable_box_empty_controller.cpp \ ) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 894920888..cd5f56f5a 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -85,7 +85,7 @@ MathToolbox * AppsContainer::mathToolbox() { return &m_mathToolbox; } -VariableBoxController * AppsContainer::variableBoxController() { +MathVariableBoxController * AppsContainer::variableBoxController() { return &m_variableBoxController; } diff --git a/apps/apps_container.h b/apps/apps_container.h index 18d755512..482999103 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -8,7 +8,7 @@ #include "apps_window.h" #include "empty_battery_window.h" #include "math_toolbox.h" -#include "variable_box_controller.h" +#include "math_variable_box_controller.h" #include "exam_pop_up_controller.h" #include "exam_pop_up_controller_delegate.h" #include "battery_timer.h" @@ -34,7 +34,7 @@ public: void reset(); Poincare::Context * globalContext(); MathToolbox * mathToolbox(); - VariableBoxController * variableBoxController(); + MathVariableBoxController * variableBoxController(); void suspend(bool checkIfOnOffKeyReleased = false); bool dispatchEvent(Ion::Events::Event event) override; bool switchTo(App::Snapshot * snapshot) override; @@ -70,7 +70,7 @@ private: EmptyBatteryWindow m_emptyBatteryWindow; Shared::GlobalContext m_globalContext; MathToolbox m_mathToolbox; - VariableBoxController m_variableBoxController; + MathVariableBoxController m_variableBoxController; ExamPopUpController m_examPopUpController; OnBoarding::PopUpController m_promptController; BatteryTimer m_batteryTimer; diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index 227aa1c0e..464966cba 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -77,9 +77,9 @@ CodePoint App::XNT() { } NestedMenuController * App::variableBoxForInputEventHandler(InputEventHandler * textInput) { - VariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController(); + MathVariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController(); varBox->setSender(textInput); - varBox->lockDeleteEvent(VariableBoxController::Page::Function); + varBox->lockDeleteEvent(MathVariableBoxController::Page::Function); return varBox; } diff --git a/apps/variable_box_controller.cpp b/apps/math_variable_box_controller.cpp similarity index 82% rename from apps/variable_box_controller.cpp rename to apps/math_variable_box_controller.cpp index 4637220b3..7eb72b39e 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/math_variable_box_controller.cpp @@ -1,4 +1,4 @@ -#include "variable_box_controller.h" +#include "math_variable_box_controller.h" #include "shared/global_context.h" #include "shared/continuous_function.h" #include @@ -14,7 +14,7 @@ using namespace Poincare; using namespace Shared; using namespace Ion; -VariableBoxController::VariableBoxController() : +MathVariableBoxController::MathVariableBoxController() : AlternateEmptyNestedMenuController(I18n::Message::Variables), m_currentPage(Page::RootMenu), m_lockPageDelete(Page::RootMenu), @@ -25,20 +25,20 @@ VariableBoxController::VariableBoxController() : } } -void VariableBoxController::viewWillAppear() { +void MathVariableBoxController::viewWillAppear() { assert(m_currentPage == Page::RootMenu); AlternateEmptyNestedMenuController::viewWillAppear(); } -void VariableBoxController::viewDidDisappear() { +void MathVariableBoxController::viewDidDisappear() { AlternateEmptyNestedMenuController::viewDidDisappear(); /* NestedMenuController::viewDidDisappear might need cell heights, which would - * use the VariableBoxController cell heights memoization. We thus reset the - * VariableBoxController layouts only after calling the parent's + * use the MathVariableBoxController cell heights memoization. We thus reset the + * MathVariableBoxController layouts only after calling the parent's * viewDidDisappear. */ - // Tidy the layouts displayed in the VariableBoxController to clean TreePool + // Tidy the layouts displayed in the MathVariableBoxController to clean TreePool for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { m_leafCells[i].setLayout(Layout()); m_leafCells[i].setAccessoryLayout(Layout()); @@ -49,7 +49,7 @@ void VariableBoxController::viewDidDisappear() { setPage(Page::RootMenu); } -bool VariableBoxController::handleEvent(Ion::Events::Event event) { +bool MathVariableBoxController::handleEvent(Ion::Events::Event event) { /* We do not want to handle backspace event if: * - On the root menu page * The deletion on the current page is locked @@ -68,7 +68,7 @@ bool VariableBoxController::handleEvent(Ion::Events::Event event) { return AlternateEmptyNestedMenuController::handleEvent(event); } -int VariableBoxController::numberOfRows() const { +int MathVariableBoxController::numberOfRows() const { switch (m_currentPage) { case Page::RootMenu: return k_numberOfMenuRows; @@ -81,7 +81,7 @@ int VariableBoxController::numberOfRows() const { } } -int VariableBoxController::reusableCellCount(int type) { +int MathVariableBoxController::reusableCellCount(int type) { assert(type < 2); if (type == 0) { return k_maxNumberOfDisplayedRows; @@ -89,7 +89,7 @@ int VariableBoxController::reusableCellCount(int type) { return k_numberOfMenuRows; } -void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { +void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { if (m_currentPage == Page::RootMenu) { I18n::Message label = nodeLabelAtIndex(index); MessageTableCell * myCell = (MessageTableCell *)cell; @@ -119,7 +119,7 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in myCell->reloadCell(); } -KDCoordinate VariableBoxController::rowHeight(int index) { +KDCoordinate MathVariableBoxController::rowHeight(int index) { if (m_currentPage != Page::RootMenu) { Layout layoutR = expressionLayoutForRecord(recordAtIndex(index), index); if (!layoutR.isUninitialized()) { @@ -129,34 +129,34 @@ KDCoordinate VariableBoxController::rowHeight(int index) { return AlternateEmptyNestedMenuController::rowHeight(index); } -int VariableBoxController::typeAtLocation(int i, int j) { +int MathVariableBoxController::typeAtLocation(int i, int j) { if (m_currentPage == Page::RootMenu) { return 1; } return 0; } -ExpressionTableCellWithExpression * VariableBoxController::leafCellAtIndex(int index) { +ExpressionTableCellWithExpression * MathVariableBoxController::leafCellAtIndex(int index) { assert(index >= 0 && index < k_maxNumberOfDisplayedRows); return &m_leafCells[index]; } -MessageTableCellWithChevron * VariableBoxController::nodeCellAtIndex(int index) { +MessageTableCellWithChevron * MathVariableBoxController::nodeCellAtIndex(int index) { assert(index >= 0 && index < k_numberOfMenuRows); return &m_nodeCells[index]; } -VariableBoxController::Page VariableBoxController::pageAtIndex(int index) { +MathVariableBoxController::Page MathVariableBoxController::pageAtIndex(int index) { Page pages[2] = {Page::Expression, Page::Function}; return pages[index]; } -void VariableBoxController::setPage(Page page) { +void MathVariableBoxController::setPage(Page page) { m_currentPage = page; resetMemoization(); } -bool VariableBoxController::selectSubMenu(int selectedRow) { +bool MathVariableBoxController::selectSubMenu(int selectedRow) { m_selectableTableView.deselectTable(); setPage(pageAtIndex(selectedRow)); bool selectSubMenu = AlternateEmptyNestedMenuController::selectSubMenu(selectedRow); @@ -166,7 +166,7 @@ bool VariableBoxController::selectSubMenu(int selectedRow) { return selectSubMenu; } -bool VariableBoxController::returnToPreviousMenu() { +bool MathVariableBoxController::returnToPreviousMenu() { if (isDisplayingEmptyController()) { pop(); } else { @@ -176,7 +176,7 @@ bool VariableBoxController::returnToPreviousMenu() { return AlternateEmptyNestedMenuController::returnToPreviousMenu(); } -bool VariableBoxController::selectLeaf(int selectedRow) { +bool MathVariableBoxController::selectLeaf(int selectedRow) { if (isDisplayingEmptyController()) { /* We do not want to handle OK/EXE events in that case. */ return false; @@ -210,13 +210,13 @@ bool VariableBoxController::selectLeaf(int selectedRow) { return true; } -I18n::Message VariableBoxController::nodeLabelAtIndex(int index) { +I18n::Message MathVariableBoxController::nodeLabelAtIndex(int index) { assert(m_currentPage == Page::RootMenu); I18n::Message labels[2] = {I18n::Message::Expressions, I18n::Message::Functions}; return labels[index]; } -Layout VariableBoxController::expressionLayoutForRecord(Storage::Record record, int index) { +Layout MathVariableBoxController::expressionLayoutForRecord(Storage::Record record, int index) { assert(m_currentPage != Page::RootMenu); assert(index >= 0); if (index >= m_firstMemoizedLayoutIndex+k_maxNumberOfDisplayedRows || index < m_firstMemoizedLayoutIndex) { @@ -246,30 +246,30 @@ Layout VariableBoxController::expressionLayoutForRecord(Storage::Record record, return m_layouts[index-m_firstMemoizedLayoutIndex]; } -const char * VariableBoxController::extension() const { +const char * MathVariableBoxController::extension() const { assert(m_currentPage != Page::RootMenu); return m_currentPage == Page::Function ? Ion::Storage::funcExtension : Ion::Storage::expExtension; } -Storage::Record VariableBoxController::recordAtIndex(int rowIndex) { +Storage::Record MathVariableBoxController::recordAtIndex(int rowIndex) { assert(m_currentPage != Page::RootMenu); assert(!Storage::sharedStorage()->recordWithExtensionAtIndex(extension(), rowIndex).isNull()); return Storage::sharedStorage()->recordWithExtensionAtIndex(extension(), rowIndex); } -ViewController * VariableBoxController::emptyViewController() { - m_emptyViewController.setType((VariableBoxEmptyController::Type)m_currentPage); +ViewController * MathVariableBoxController::emptyViewController() { + m_emptyViewController.setType((MathVariableBoxEmptyController::Type)m_currentPage); return &m_emptyViewController; } -void VariableBoxController::resetMemoization() { +void MathVariableBoxController::resetMemoization() { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { m_layouts[i] = Layout(); } m_firstMemoizedLayoutIndex = 0; } -void VariableBoxController::destroyRecordAtRowIndex(int rowIndex) { +void MathVariableBoxController::destroyRecordAtRowIndex(int rowIndex) { // Destroy the record recordAtIndex(rowIndex).destroy(); // Shift the memoization if needed diff --git a/apps/variable_box_controller.h b/apps/math_variable_box_controller.h similarity index 88% rename from apps/variable_box_controller.h rename to apps/math_variable_box_controller.h index affb031fd..25bb29703 100644 --- a/apps/variable_box_controller.h +++ b/apps/math_variable_box_controller.h @@ -1,15 +1,13 @@ -#ifndef APPS_VARIABLE_BOX_CONTROLLER_H -#define APPS_VARIABLE_BOX_CONTROLLER_H - -#define MATRIX_VARIABLES 1 +#ifndef APPS_MATH_VARIABLE_BOX_CONTROLLER_H +#define APPS_MATH_VARIABLE_BOX_CONTROLLER_H #include "alternate_empty_nested_menu_controller.h" -#include "variable_box_empty_controller.h" +#include "math_variable_box_empty_controller.h" #include -class VariableBoxController : public AlternateEmptyNestedMenuController { +class MathVariableBoxController : public AlternateEmptyNestedMenuController { public: - VariableBoxController(); + MathVariableBoxController(); // View Controller void viewWillAppear() override; @@ -32,6 +30,7 @@ public: Function = 2 }; void lockDeleteEvent(Page page) { m_lockPageDelete = page; } + private: constexpr static int k_maxNumberOfDisplayedRows = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin - Metric::StackTitleHeight) / Metric::ToolboxRowHeight + 2; // (240 - 18 - 50 - 20) / 40 = 3.8; the 0.8 cell can be above and below so we add +2 to get 5 constexpr static int k_numberOfMenuRows = 2; @@ -55,7 +54,7 @@ private: Page m_lockPageDelete; ExpressionTableCellWithExpression m_leafCells[k_maxNumberOfDisplayedRows]; MessageTableCellWithChevron m_nodeCells[k_numberOfMenuRows]; - VariableBoxEmptyController m_emptyViewController; + MathVariableBoxEmptyController m_emptyViewController; // Layout memoization // TODO: make a helper doing the RingMemoizationOfConsecutiveObjets to factorize this code and ExpressionModelStore code int m_firstMemoizedLayoutIndex; diff --git a/apps/math_variable_box_empty_controller.cpp b/apps/math_variable_box_empty_controller.cpp new file mode 100644 index 000000000..f36380d99 --- /dev/null +++ b/apps/math_variable_box_empty_controller.cpp @@ -0,0 +1,53 @@ +#include "math_variable_box_empty_controller.h" +#include +#include +#include + +MathVariableBoxEmptyController::MathVariableBoxEmptyView::MathVariableBoxEmptyView() : + VariableBoxEmptyView(), + m_layoutExample(0.5f, 0.5f, KDColorBlack, Palette::WallScreen) +{ + initMessageViews(); +} + +void MathVariableBoxEmptyController::MathVariableBoxEmptyView::setLayout(Poincare::Layout layout) { + m_layoutExample.setLayout(layout); +} + +void MathVariableBoxEmptyController::viewDidDisappear() { + m_view.setLayout(Poincare::Layout()); +} + +void MathVariableBoxEmptyController::setType(Type type) { + I18n::Message messages[MathVariableBoxEmptyView::k_numberOfMessages] = { + I18n::Message::Default, + I18n::Message::Default, + I18n::Message::Default, + I18n::Message::EnableCharacters + }; + Poincare::Layout layout; + switch (type) { + case Type::Expressions: + { + messages[0] = I18n::Message::EmptyExpressionBox0; + messages[1] = I18n::Message::EmptyExpressionBox1; + messages[2] = I18n::Message::EmptyExpressionBox2; + const char * storeExpression = "3→A"; + layout = Poincare::LayoutHelper::String(storeExpression, strlen(storeExpression), MathVariableBoxEmptyView::k_font); + break; + } + case Type::Functions: + { + messages[0] = I18n::Message::EmptyFunctionBox0; + messages[1] = I18n::Message::EmptyFunctionBox1; + messages[2] = I18n::Message::EmptyFunctionBox2; + const char * storeFunction = "3+x→f(x)"; + layout = Poincare::LayoutHelper::String(storeFunction, strlen(storeFunction), MathVariableBoxEmptyView::k_font); + break; + } + default: + assert(false); + } + m_view.setMessages(messages); + m_view.setLayout(layout); +} diff --git a/apps/math_variable_box_empty_controller.h b/apps/math_variable_box_empty_controller.h new file mode 100644 index 000000000..9083b3bca --- /dev/null +++ b/apps/math_variable_box_empty_controller.h @@ -0,0 +1,41 @@ +#ifndef APPS_MATH_VARIABLE_BOX_EMPTY_CONTROLLER_H +#define APPS_MATH_VARIABLE_BOX_EMPTY_CONTROLLER_H + +#include +#include "variable_box_empty_controller.h" + +class MathVariableBoxEmptyController : public VariableBoxEmptyController { +public: + MathVariableBoxEmptyController() : + VariableBoxEmptyController(), + m_view() + {} + enum class Type { + None = 0, + Expressions = 1, + Functions = 2 + }; + void setType(Type type); + // View Controller + View * view() override { return &m_view; } + void viewDidDisappear() override; +private: + class MathVariableBoxEmptyView : public VariableBoxEmptyView { + public: + constexpr static int k_numberOfMessages = 4; + MathVariableBoxEmptyView(); + void setLayout(Poincare::Layout layout); + private: + int numberOfMessageTextViews() const override { return k_numberOfMessages; } + MessageTextView * messageTextViewAtIndex(int index) override { + assert(index >= 0 && index < k_numberOfMessages); + return &m_messages[index]; + } + ExpressionView * expressionView() override { return &m_layoutExample; } + MessageTextView m_messages[k_numberOfMessages]; + ExpressionView m_layoutExample; + }; + MathVariableBoxEmptyView m_view; +}; + +#endif diff --git a/apps/shared/input_event_handler_delegate_app.cpp b/apps/shared/input_event_handler_delegate_app.cpp index cc9b5d525..53c49047c 100644 --- a/apps/shared/input_event_handler_delegate_app.cpp +++ b/apps/shared/input_event_handler_delegate_app.cpp @@ -20,9 +20,9 @@ Toolbox * InputEventHandlerDelegateApp::toolboxForInputEventHandler(InputEventHa } NestedMenuController * InputEventHandlerDelegateApp::variableBoxForInputEventHandler(InputEventHandler * textInput) { - VariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController(); + MathVariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController(); varBox->setSender(textInput); - varBox->lockDeleteEvent(VariableBoxController::Page::RootMenu); + varBox->lockDeleteEvent(MathVariableBoxController::Page::RootMenu); return varBox; } diff --git a/apps/variable_box_empty_controller.cpp b/apps/variable_box_empty_controller.cpp index 9f96fd021..a07a8d23d 100644 --- a/apps/variable_box_empty_controller.cpp +++ b/apps/variable_box_empty_controller.cpp @@ -3,29 +3,28 @@ #include #include -using namespace Poincare; -using namespace Ion; - -VariableBoxEmptyController::VariableBoxEmptyView::VariableBoxEmptyView() : - m_layoutExample(0.5f, 0.5f, KDColorBlack, Palette::WallScreen) -{ - for (int i = 0; i < k_numberOfMessages; i++) { - m_messages[i].setFont(k_font); - m_messages[i].setAlignment(0.5f, 0.5f); - m_messages[i].setBackgroundColor(Palette::WallScreen); - } - m_messages[0].setAlignment(0.5f,1.0f); - m_messages[k_numberOfMessages-1].setAlignment(0.5f,0.0f); -} - -void VariableBoxEmptyController::VariableBoxEmptyView::setMessages(I18n::Message * message) { - for (int i = 0; i < k_numberOfMessages; i++) { - m_messages[i].setMessage(message[i]); +// VariableBoxEmptyController::VariableBoxEmptyView +void VariableBoxEmptyController::VariableBoxEmptyView::initMessageViews() { + const int numberOfMessageViews = numberOfMessageTextViews(); + for (int i = 0; i < numberOfMessageViews; i++) { + MessageTextView * message = messageTextViewAtIndex(i); + message->setFont(k_font); + message->setBackgroundColor(Palette::WallScreen); + float verticalAlignment = 0.5f; + if (i == 0) { + verticalAlignment = 1.0f; + } else if (i == numberOfMessageViews - 1) { + verticalAlignment = 0.0f; + } + message->setAlignment(0.5f, verticalAlignment); } } -void VariableBoxEmptyController::VariableBoxEmptyView::setLayout(Poincare::Layout layout) { - m_layoutExample.setLayout(layout); +void VariableBoxEmptyController::VariableBoxEmptyView::setMessages(I18n::Message * message) { + const int numberOfMessageViews = numberOfMessageTextViews(); + for (int i = 0; i < numberOfMessageViews; i++) { + messageTextViewAtIndex(i)->setMessage(message[i]); + } } void VariableBoxEmptyController::VariableBoxEmptyView::drawRect(KDContext * ctx, KDRect rect) const { @@ -33,76 +32,48 @@ void VariableBoxEmptyController::VariableBoxEmptyView::drawRect(KDContext * ctx, } int VariableBoxEmptyController::VariableBoxEmptyView::numberOfSubviews() const { - return k_numberOfMessages+1; + return numberOfMessageTextViews() + hasExpressionView(); } View * VariableBoxEmptyController::VariableBoxEmptyView::subviewAtIndex(int index) { - if (index == k_layoutRowIndex) { - return &m_layoutExample; + if (hasExpressionView()) { + if (index == k_expressionViewRowIndex) { + return expressionView(); + } + return messageTextViewAtIndex(index + (index < k_expressionViewRowIndex ? 0 : -1)); } - if (index < k_layoutRowIndex) { - return &m_messages[index]; - } - return &m_messages[index-1]; + return messageTextViewAtIndex(index); } void VariableBoxEmptyController::VariableBoxEmptyView::layoutSubviews(bool force) { - KDCoordinate width = bounds().width() - 2*k_separatorThickness; - KDCoordinate height = bounds().height() - 2*k_separatorThickness; + const int numberOfMessageViews = numberOfMessageTextViews(); + const bool hasExpression = hasExpressionView(); + KDCoordinate width = bounds().width() - 2 * k_separatorThickness; + KDCoordinate height = bounds().height() - 2 * k_separatorThickness; KDCoordinate textHeight = k_font->glyphSize().height(); - KDCoordinate layoutHeight = m_layoutExample.minimalSizeForOptimalDisplay().height(); - KDCoordinate margin = (height - k_numberOfMessages*textHeight-layoutHeight)/2; - m_layoutExample.setFrame(KDRect(k_separatorThickness, k_separatorThickness+margin+k_layoutRowIndex*textHeight, width, layoutHeight), force); + KDCoordinate layoutHeight = hasExpression ? expressionView()->minimalSizeForOptimalDisplay().height() : 0; + KDCoordinate margin = (height - numberOfMessageViews * textHeight - layoutHeight) / 2; + if (hasExpression) { + expressionView()->setFrame(KDRect( + k_separatorThickness, + k_separatorThickness + margin + k_expressionViewRowIndex * textHeight, + width, + layoutHeight), + force); + } KDCoordinate currentHeight = k_separatorThickness; - for (uint8_t i = 0; i < k_numberOfMessages; i++) { - if (i == k_layoutRowIndex) { + for (uint8_t i = 0; i < numberOfMessageViews; i++) { + if (hasExpression && i == k_expressionViewRowIndex) { currentHeight += layoutHeight; } - KDCoordinate h = i == 0 || i == k_numberOfMessages - 1 ? textHeight+margin : textHeight; - m_messages[i].setFrame(KDRect(k_separatorThickness, currentHeight, width, h), force); + KDCoordinate h = (i == 0 || i == numberOfMessageViews - 1) ? textHeight + margin : textHeight; + messageTextViewAtIndex(i)->setFrame(KDRect(k_separatorThickness, currentHeight, width, h), force); currentHeight += h; } } -VariableBoxEmptyController::VariableBoxEmptyController() : - ViewController(nullptr), - m_view() -{ -} +// VariableBoxEmptyController -View * VariableBoxEmptyController::view() { - return &m_view; -} - -void VariableBoxEmptyController::viewDidDisappear() { - m_view.setLayout(Layout()); -} - -void VariableBoxEmptyController::setType(Type type) { - I18n::Message messages[VariableBoxEmptyView::k_numberOfMessages] = {I18n::Message::Default, I18n::Message::Default, I18n::Message::Default, I18n::Message::EnableCharacters}; - Layout layout; - switch (type) { - case Type::Expressions: - { - messages[0] = I18n::Message::EmptyExpressionBox0; - messages[1] = I18n::Message::EmptyExpressionBox1; - messages[2] = I18n::Message::EmptyExpressionBox2; - const char * storeExpression = "3→A"; - layout = LayoutHelper::String(storeExpression, strlen(storeExpression), VariableBoxEmptyView::k_font); - break; - } - case Type::Functions: - { - messages[0] = I18n::Message::EmptyFunctionBox0; - messages[1] = I18n::Message::EmptyFunctionBox1; - messages[2] = I18n::Message::EmptyFunctionBox2; - const char * storeFunction = "3+x→f(x)"; - layout = LayoutHelper::String(storeFunction, strlen(storeFunction), VariableBoxEmptyView::k_font); - break; - } - default: - assert(false); - } - m_view.setMessages(messages); - m_view.setLayout(layout); +void VariableBoxEmptyController::setMessages(I18n::Message * messages) { + static_cast(view())->setMessages(messages); } diff --git a/apps/variable_box_empty_controller.h b/apps/variable_box_empty_controller.h index 683c63a9b..4218801fb 100644 --- a/apps/variable_box_empty_controller.h +++ b/apps/variable_box_empty_controller.h @@ -9,36 +9,29 @@ class VariableBoxEmptyController : public ViewController { public: - VariableBoxEmptyController(); - enum class Type { - None = 0, - Expressions = 1, - Functions = 2 - }; + VariableBoxEmptyController() : ViewController(nullptr) {} + void setMessages(I18n::Message * messages); // View Controller - View * view() override; DisplayParameter displayParameter() override { return DisplayParameter::DoNotShowOwnTitle; } - void viewDidDisappear() override; - - void setType(Type type); -private: +protected: class VariableBoxEmptyView : public View, public Bordered { public: - static constexpr const KDFont * k_font = KDFont::SmallFont; - VariableBoxEmptyView(); + constexpr static const KDFont * k_font = KDFont::SmallFont; + void initMessageViews(); void setMessages(I18n::Message * message); - void setLayout(Poincare::Layout layout); void drawRect(KDContext * ctx, KDRect rect) const override; - constexpr static int k_numberOfMessages = 4; private: + constexpr static int k_expressionViewRowIndex = 2; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; - constexpr static int k_layoutRowIndex = 2; - MessageTextView m_messages[k_numberOfMessages]; - ExpressionView m_layoutExample; + virtual int numberOfMessageTextViews() const = 0; + virtual MessageTextView * messageTextViewAtIndex(int index) = 0; + bool hasExpressionView() const { + return const_cast(this)->expressionView() != nullptr; + } + virtual ExpressionView * expressionView() { return nullptr; } }; - VariableBoxEmptyView m_view; }; #endif From 398de8bda3f86eb4064c1b30bfe967b928451767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 17 Apr 2020 18:01:16 +0200 Subject: [PATCH 218/453] [apps/code] Empty controller in the var box --- apps/code/Makefile | 1 + apps/code/variable_box_controller.cpp | 4 +-- apps/code/variable_box_controller.h | 11 +++++-- apps/code/variable_box_empty_controller.cpp | 14 +++++++++ apps/code/variable_box_empty_controller.h | 34 +++++++++++++++++++++ 5 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 apps/code/variable_box_empty_controller.cpp create mode 100644 apps/code/variable_box_empty_controller.h diff --git a/apps/code/Makefile b/apps/code/Makefile index d91713eed..7a4772d2c 100644 --- a/apps/code/Makefile +++ b/apps/code/Makefile @@ -24,6 +24,7 @@ app_code_src = $(addprefix apps/code/,\ script_parameter_controller.cpp \ script_store.cpp \ variable_box_controller.cpp \ + variable_box_empty_controller.cpp \ ) app_code_src += $(app_code_test_src) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 03103d8f2..e6b74f781 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -47,7 +47,7 @@ static bool shouldAddObject(const char * name, int maxLength) { } VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : - NestedMenuController(nullptr, I18n::Message::FunctionsAndVariables), + AlternateEmptyNestedMenuController(I18n::Message::FunctionsAndVariables), m_scriptStore(scriptStore), m_currentScriptNodesCount(0), m_builtinNodesCount(0), @@ -141,7 +141,7 @@ void VariableBoxController::tableViewDidChangeSelection(SelectableTableView * t, return; } const int currentSelectedRow = selectedRow(); - if (typeAtLocation(0, currentSelectedRow) == k_subtitleCellType) { + if (currentSelectedRow >= 0 && typeAtLocation(0, currentSelectedRow) == k_subtitleCellType) { if (currentSelectedRow == 0) { t->selectCellAtLocation(0, 1); } else { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 3cfb63bf8..462e9db1a 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -1,14 +1,16 @@ #ifndef CODE_VARIABLE_BOX_CONTROLLER_H #define CODE_VARIABLE_BOX_CONTROLLER_H -#include +#include +#include #include "script_node.h" #include "script_node_cell.h" #include "script_store.h" +#include "variable_box_empty_controller.h" namespace Code { -class VariableBoxController : public NestedMenuController { +class VariableBoxController : public AlternateEmptyNestedMenuController { public: VariableBoxController(ScriptStore * scriptStore); @@ -27,6 +29,10 @@ public: /* SelectableTableViewDelegate */ void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; + //AlternateEmptyNestedMenuController + ViewController * emptyViewController() override { return &m_variableBoxEmptyController; } + bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } + /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int * textToInsertLength); @@ -96,6 +102,7 @@ private: bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); bool contains(const char * name, int nameLength); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); + VariableBoxEmptyController m_variableBoxEmptyController; ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; diff --git a/apps/code/variable_box_empty_controller.cpp b/apps/code/variable_box_empty_controller.cpp new file mode 100644 index 000000000..ce4ea5ffe --- /dev/null +++ b/apps/code/variable_box_empty_controller.cpp @@ -0,0 +1,14 @@ +#include "variable_box_empty_controller.h" +#include + +namespace Code { + +VariableBoxEmptyController::VariableBoxEmptyView::VariableBoxEmptyView() : + ::VariableBoxEmptyController::VariableBoxEmptyView() +{ + initMessageViews(); + m_messages[0].setMessage(I18n::Message::Degrees); //TODO LEA + m_messages[1].setMessage(I18n::Message::Degrees); +} + +} diff --git a/apps/code/variable_box_empty_controller.h b/apps/code/variable_box_empty_controller.h new file mode 100644 index 000000000..f30f06825 --- /dev/null +++ b/apps/code/variable_box_empty_controller.h @@ -0,0 +1,34 @@ +#ifndef APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H +#define APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H + +#include + +namespace Code { + +class VariableBoxEmptyController : public ::VariableBoxEmptyController { +public: + VariableBoxEmptyController() : + ::VariableBoxEmptyController(), + m_view() + {} + // View Controller + View * view() override { return &m_view; } +private: + class VariableBoxEmptyView : public ::VariableBoxEmptyController::VariableBoxEmptyView { + public: + constexpr static int k_numberOfMessages = 2; + VariableBoxEmptyView(); + private: + int numberOfMessageTextViews() const override { return k_numberOfMessages; } + MessageTextView * messageTextViewAtIndex(int index) override { + assert(index >= 0 && index < k_numberOfMessages); + return &m_messages[index]; + } + MessageTextView m_messages[k_numberOfMessages]; + }; + VariableBoxEmptyView m_view; +}; + +} + +#endif From 003317647ea6a6116d6b49975dc07edc0770cdb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 20 Apr 2020 13:59:07 +0200 Subject: [PATCH 219/453] [apps/code] Display empty message in var box --- apps/code/editor_controller.cpp | 6 ++++-- apps/code/editor_view.h | 1 + apps/code/python_text_area.cpp | 11 +++++++---- apps/code/python_text_area.h | 1 + apps/code/variable_box_controller.cpp | 1 + apps/code/variable_box_controller.h | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index dd4eadba1..1325f21eb 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -124,8 +124,10 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events: VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - // If the editor is autocompleting, the variable box has already been loaded - if (!m_editorView.isAutocompleting()) { + /* If the editor should be autocompleting, the variable box has already been + * loaded. We check shouldAutocomplete and not isAutocompleting, because the + * autocompletion result might be empty. */ + if (!m_editorView.shouldAutocomplete()) { varBox->loadFunctionsAndVariables(m_scriptIndex, nullptr, 0); } return varBox; diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index b7f5ca969..991aaf062 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -9,6 +9,7 @@ namespace Code { class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); + bool shouldAutocomplete() const { return m_textArea.shouldAutocomplete(); } bool isAutocompleting() const; void resetSelection(); void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 3e335a12d..180e5aa0d 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -53,6 +53,12 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { } return lex->column - lex->tok_column; } +bool PythonTextArea::shouldAutocomplete(const char * autocompletionLocation) const { + const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation(); + CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), location); + return !UTF8Helper::CodePointIsEndOfWord(prevCodePoint) + && UTF8Helper::CodePointIsEndOfWord(UTF8Helper::CodePointAtLocation(location)); +} const char * PythonTextArea::ContentView::textToAutocomplete() const { return UTF8Helper::BeginningOfWord(editedText(), cursorLocation()); @@ -272,10 +278,7 @@ void PythonTextArea::addAutocompletion() { const char * autocompletionLocation = const_cast(cursorLocation()); const char * textToInsert = nullptr; int textToInsertLength = 0; - CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), autocompletionLocation); - if (!UTF8Helper::CodePointIsEndOfWord(prevCodePoint) - && UTF8Helper::CodePointIsEndOfWord(UTF8Helper::CodePointAtLocation(autocompletionLocation))) - { + if (shouldAutocomplete(autocompletionLocation)) { /* The previous code point is neither the beginning of the text, nor a * space, nor a \n, and the next code point is the end of the word. * Compute the text to insert: diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index a641ded21..755f791c1 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -18,6 +18,7 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; + bool shouldAutocomplete(const char * autocompletionLocation = nullptr) const; bool isAutocompleting() const { return m_contentView.isAutocompleting(); } protected: class ContentView : public TextArea::ContentView { diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index e6b74f781..32091d200 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -72,6 +72,7 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp * when leaving the VariableBoxController, so we do not lose the environment * that was loaded when entering the VariableBoxController. */ assert(App::app()->pythonIsInited()); + displayEmptyController(); } KDCoordinate VariableBoxController::rowHeight(int j) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 462e9db1a..6efe0228d 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -31,7 +31,7 @@ public: //AlternateEmptyNestedMenuController ViewController * emptyViewController() override { return &m_variableBoxEmptyController; } - bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } + bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } //TODO LEA factorize with math toolbox /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); From a165c6d85b8d74b424f75b151b359b58b00a7097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 20 Apr 2020 14:40:33 +0200 Subject: [PATCH 220/453] [escher] Clean InputEventHandler --- escher/src/input_event_handler.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/escher/src/input_event_handler.cpp b/escher/src/input_event_handler.cpp index ee18a4025..f8da2b112 100644 --- a/escher/src/input_event_handler.cpp +++ b/escher/src/input_event_handler.cpp @@ -5,10 +5,14 @@ #include bool InputEventHandler::handleBoxEvent(Ion::Events::Event event) { + if (m_inputEventHandlerDelegate == nullptr) { + return false; + } NestedMenuController * box = nullptr; - if (m_inputEventHandlerDelegate) { - box = event == Ion::Events::Toolbox ? m_inputEventHandlerDelegate->toolboxForInputEventHandler(this) : box; - box = event == Ion::Events::Var ? m_inputEventHandlerDelegate->variableBoxForInputEventHandler(this) : box; + if (event == Ion::Events::Toolbox) { + box = m_inputEventHandlerDelegate->toolboxForInputEventHandler(this); + } else if (event == Ion::Events::Var) { + box = m_inputEventHandlerDelegate->variableBoxForInputEventHandler(this); } if (box) { box->setSender(this); From 5393ec7273edccb9c8c6a817f4887b01a35094de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 14:42:56 +0200 Subject: [PATCH 221/453] [apps/code] Add matplotlib.pyplot in the var box --- apps/code/variable_box_controller.cpp | 2 +- apps/code/variable_box_controller.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 32091d200..e50b83b62 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -356,7 +356,6 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) - //TODO LEA add matplotlib.pyplot static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { {"False", ScriptNode::Type::WithoutParentheses}, {"None", ScriptNode::Type::WithoutParentheses}, @@ -432,6 +431,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_locals), ScriptNode::Type::WithParentheses}, {qstr_str(MP_QSTR_map), ScriptNode::Type::WithParentheses}, {qstr_str(MP_QSTR_math), ScriptNode::Type::WithoutParentheses}, + {qstr_str(MP_QSTR_matplotlib_dot_pyplot), ScriptNode::Type::WithoutParentheses}, {qstr_str(MP_QSTR_max), ScriptNode::Type::WithParentheses}, //{qstr_str(MP_QSTR_memoryview), ScriptNode::Type::WithParentheses}, {qstr_str(MP_QSTR_min), ScriptNode::Type::WithParentheses}, diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 6efe0228d..ca59edcfc 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -42,7 +42,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA constexpr static int k_maxScriptNodesCount = 32; //TODO LEA - constexpr static int k_totalBuiltinNodesCount = 107; + constexpr static int k_totalBuiltinNodesCount = 108; constexpr static uint8_t k_scriptOriginsCount = 3; constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf From 0f2ac5b110bd8bd971b91c3a92eaba5660431f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 14:57:39 +0200 Subject: [PATCH 222/453] [escher/text_field] Fix std::min use --- apps/code/python_text_area.cpp | 2 +- escher/src/text_field.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 180e5aa0d..e1fe0a923 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -188,7 +188,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char line, UTF8Helper::GlyphOffsetAtCodePoint(text, autocompleteStart), autocompleteStart, - minPointer(text + byteLength, autocompleteEnd) - autocompleteStart, + std::min(text + byteLength, autocompleteEnd) - autocompleteStart, AutocompleteColor, BackgroundColor, nullptr, diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index aa1d128b7..da9109d55 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -122,7 +122,7 @@ void TextField::ContentView::reinitDraftTextBuffer() { bool TextField::ContentView::insertTextAtLocation(const char * text, char * location, int textLen) { assert(m_isEditing); - int textLength = textLen < 0 ? strlen(text) : textLen; + size_t textLength = textLen < 0 ? strlen(text) : (size_t)textLen; if (m_currentDraftTextLength + textLength >= m_draftTextBufferSize || textLength == 0) { return false; } @@ -130,7 +130,7 @@ bool TextField::ContentView::insertTextAtLocation(const char * text, char * loca memmove(location + textLength, location, (s_draftTextBuffer + m_currentDraftTextLength + 1) - location); // Caution! One byte will be overridden by the null-terminating char of strlcpy - size_t copySize = std::min(textLength + 1, (s_draftTextBuffer + m_draftTextBufferSize) - location); + size_t copySize = std::min(textLength + 1, static_cast((s_draftTextBuffer + m_draftTextBufferSize) - location)); char * overridenByteLocation = location + copySize - 1; char overridenByte = *overridenByteLocation; strlcpy(location, text, copySize); From dd6c2a4f54c4481e4ddf63ac7d49b6949bae2b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 15:31:24 +0200 Subject: [PATCH 223/453] [apps/code] Translate the variable box --- apps/code/base.de.i18n | 8 +++++--- apps/code/base.en.i18n | 6 ++++-- apps/code/base.es.i18n | 8 +++++--- apps/code/base.fr.i18n | 6 ++++-- apps/code/base.it.i18n | 5 +++++ apps/code/base.nl.i18n | 5 +++++ apps/code/base.pt.i18n | 8 +++++--- apps/code/variable_box_controller.cpp | 4 ++-- apps/code/variable_box_empty_controller.cpp | 3 +-- apps/code/variable_box_empty_controller.h | 6 +++--- 10 files changed, 39 insertions(+), 20 deletions(-) diff --git a/apps/code/base.de.i18n b/apps/code/base.de.i18n index 1d9f39cc5..a94f7e3e9 100644 --- a/apps/code/base.de.i18n +++ b/apps/code/base.de.i18n @@ -6,6 +6,8 @@ AutoImportScript = "Automatischer Import in Konsole" DeleteScript = "Skript löschen" FunctionsAndVariables = "Funktionen und Variablen" AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _" -CurrentScript = "Current script" -BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" -ImportedModulesAndScripts = "Imported modules and scripts" +Autocomplete = "Autovervollständigung" +ScriptInProgress = "Aktuelle Skript" +BuiltinsAndKeywords = "Native Funktionen und Schlüsselwörter" +ImportedModulesAndScripts = "Importierte Module und Skripte" +NoWordAvailableHere = "Kein Wort ist hier verfübar." diff --git a/apps/code/base.en.i18n b/apps/code/base.en.i18n index 266221a70..ac53cd42f 100644 --- a/apps/code/base.en.i18n +++ b/apps/code/base.en.i18n @@ -6,6 +6,8 @@ AutoImportScript = "Auto import in shell" DeleteScript = "Delete script" FunctionsAndVariables = "Functions and variables" AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" -CurrentScript = "Current script" -BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" +Autocomplete = "Autocomplete" +ScriptInProgress = "Script in progress" +BuiltinsAndKeywords = "Builtins and keywords" ImportedModulesAndScripts = "Imported modules and scripts" +NoWordAvailableHere = "No word available here." diff --git a/apps/code/base.es.i18n b/apps/code/base.es.i18n index cbd4b8859..3ac3694ab 100644 --- a/apps/code/base.es.i18n +++ b/apps/code/base.es.i18n @@ -6,6 +6,8 @@ AutoImportScript = "Importación auto en intérprete" DeleteScript = "Eliminar el archivo" FunctionsAndVariables = "Funciones y variables" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" -CurrentScript = "Current script" -BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" -ImportedModulesAndScripts = "Imported modules and scripts" +Autocomplete = "Autocompleción" +ScriptInProgress = "Archivo en curso" +BuiltinsAndKeywords = "Funciones nativas y palabras clave" +ImportedModulesAndScripts = "Módulos y archivos importados" +NoWordAvailableHere = "No hay ninguna palabra disponible aquí." diff --git a/apps/code/base.fr.i18n b/apps/code/base.fr.i18n index 2dd179d22..b133eba46 100644 --- a/apps/code/base.fr.i18n +++ b/apps/code/base.fr.i18n @@ -6,6 +6,8 @@ AutoImportScript = "Importation auto dans la console" DeleteScript = "Supprimer le script" FunctionsAndVariables = "Fonctions et variables" AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" -CurrentScript = "Script en cours" -BuiltinFunctionsAndKeyWords = "Fonctions natives et mots-clés" +Autocomplete = "Auto-complétion" +ScriptInProgress = "Script en cours" +BuiltinsAndKeywords = "Fonctions natives et mots-clés" ImportedModulesAndScripts = "Modules et scripts importés" +NoWordAvailableHere = "Aucun mot disponible à cet endroit." diff --git a/apps/code/base.it.i18n b/apps/code/base.it.i18n index aafac90a4..ea2a614e8 100644 --- a/apps/code/base.it.i18n +++ b/apps/code/base.it.i18n @@ -6,3 +6,8 @@ AutoImportScript = "Importazione automatica dello script" DeleteScript = "Eliminare lo script" FunctionsAndVariables = "Funzioni e variabili" AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _" +Autocomplete = "Autocompletamento" +ScriptInProgress = "Script in corso" +BuiltinsAndKeywords = "Funzioni native e parole chiave" +ImportedModulesAndScripts = "Moduli e scripts importati" +NoWordAvailableHere = "Nessuna parola disponibile qui." diff --git a/apps/code/base.nl.i18n b/apps/code/base.nl.i18n index a898aa833..b9916b3d2 100644 --- a/apps/code/base.nl.i18n +++ b/apps/code/base.nl.i18n @@ -6,3 +6,8 @@ AutoImportScript = "Automatisch importeren in shell" DeleteScript = "Script verwijderen" FunctionsAndVariables = "Functies en variabelen" AllowedCharactersaz09 = "Toegestane tekens: a-z, 0-9, _" +Autocomplete = "Autocomplete" +ScriptInProgress = "Script in progress" +BuiltinsAndKeywords = "Builtins and keywords" +ImportedModulesAndScripts = "Imported modules and scripts" +NoWordAvailableHere = "No word available here." diff --git a/apps/code/base.pt.i18n b/apps/code/base.pt.i18n index 4dd8066d3..6c872142e 100644 --- a/apps/code/base.pt.i18n +++ b/apps/code/base.pt.i18n @@ -6,6 +6,8 @@ AutoImportScript = "Importação auto no interpretador" DeleteScript = "Eliminar o script" FunctionsAndVariables = "Funções e variáveis" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" -CurrentScript = "Current script" -BuiltinFunctionsAndKeyWords = "Builtin functions and keywords" -ImportedModulesAndScripts = "Imported modules and scripts" +Autocomplete = "Preenchimento automático" +ScriptInProgress = "Script em curso" +BuiltinsAndKeywords = "Funções nativas e palavras-chave" +ImportedModulesAndScripts = "Módulos e scripts importados" +NoWordAvailableHere = "Nenhuma palavra disponível aqui." diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index e50b83b62..f1cce74ea 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -130,8 +130,8 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in } assert(cellType == k_subtitleCellType); I18n::Message subtitleMessages[k_scriptOriginsCount] = { - I18n::Message::CurrentScript, - I18n::Message::BuiltinFunctionsAndKeyWords, + I18n::Message::ScriptInProgress, + I18n::Message::BuiltinsAndKeywords, I18n::Message::ImportedModulesAndScripts }; static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin]); diff --git a/apps/code/variable_box_empty_controller.cpp b/apps/code/variable_box_empty_controller.cpp index ce4ea5ffe..28afc0fd5 100644 --- a/apps/code/variable_box_empty_controller.cpp +++ b/apps/code/variable_box_empty_controller.cpp @@ -7,8 +7,7 @@ VariableBoxEmptyController::VariableBoxEmptyView::VariableBoxEmptyView() : ::VariableBoxEmptyController::VariableBoxEmptyView() { initMessageViews(); - m_messages[0].setMessage(I18n::Message::Degrees); //TODO LEA - m_messages[1].setMessage(I18n::Message::Degrees); + m_message.setMessage(I18n::Message::NoWordAvailableHere); } } diff --git a/apps/code/variable_box_empty_controller.h b/apps/code/variable_box_empty_controller.h index f30f06825..f29d3a928 100644 --- a/apps/code/variable_box_empty_controller.h +++ b/apps/code/variable_box_empty_controller.h @@ -16,15 +16,15 @@ public: private: class VariableBoxEmptyView : public ::VariableBoxEmptyController::VariableBoxEmptyView { public: - constexpr static int k_numberOfMessages = 2; + constexpr static int k_numberOfMessages = 1; VariableBoxEmptyView(); private: int numberOfMessageTextViews() const override { return k_numberOfMessages; } MessageTextView * messageTextViewAtIndex(int index) override { assert(index >= 0 && index < k_numberOfMessages); - return &m_messages[index]; + return &m_message; } - MessageTextView m_messages[k_numberOfMessages]; + MessageTextView m_message; }; VariableBoxEmptyView m_view; }; From e73ae9bcdf3853c119db51ea27aacfc27f33eed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 15:51:34 +0200 Subject: [PATCH 224/453] [apps/code] Fix varbox that should autocomplete the current word --- apps/code/python_text_area.cpp | 3 +++ apps/code/python_text_area.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index e1fe0a923..f0ed0ff99 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -54,6 +54,9 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { return lex->column - lex->tok_column; } bool PythonTextArea::shouldAutocomplete(const char * autocompletionLocation) const { + if (isAutocompleting()) { + return true; + } const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation(); CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), location); return !UTF8Helper::CodePointIsEndOfWord(prevCodePoint) diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 755f791c1..1bbcd2531 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -18,6 +18,9 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; + /* shouldAutocomplete returns true if there is currently autocompletion, or if + * there should be autocompletion but there is not because there is no word to + * autocomplete. */ bool shouldAutocomplete(const char * autocompletionLocation = nullptr) const; bool isAutocompleting() const { return m_contentView.isAutocompleting(); } protected: From e630b0e9e595fbd1cfecda9ecaeeeb2ee6a2e653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 16:17:30 +0200 Subject: [PATCH 225/453] [apps/code] Remove __import__ from builtins --- apps/code/variable_box_controller.cpp | 1 - apps/code/variable_box_controller.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index f1cce74ea..42a1ae606 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -360,7 +360,6 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {"False", ScriptNode::Type::WithoutParentheses}, {"None", ScriptNode::Type::WithoutParentheses}, {"True", ScriptNode::Type::WithoutParentheses}, - {qstr_str(MP_QSTR___import__), ScriptNode::Type::WithParentheses}, {qstr_str(MP_QSTR_abs), ScriptNode::Type::WithParentheses}, {qstr_str(MP_QSTR_all), ScriptNode::Type::WithParentheses}, {"and", ScriptNode::Type::WithoutParentheses}, diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index ca59edcfc..6efe0228d 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -42,7 +42,7 @@ private: constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA constexpr static int k_maxScriptNodesCount = 32; //TODO LEA - constexpr static int k_totalBuiltinNodesCount = 108; + constexpr static int k_totalBuiltinNodesCount = 107; constexpr static uint8_t k_scriptOriginsCount = 3; constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf From 7636c001e110c1554173a076d29d809c015b7ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 16:18:23 +0200 Subject: [PATCH 226/453] [apps/code] Fix varbox parentheses bug Scenario: write i, open the varbox and select "in" -> parentheses are added, but there shouldn't be any --- apps/code/variable_box_controller.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 42a1ae606..652687968 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -337,10 +337,19 @@ bool VariableBoxController::selectLeaf(int rowIndex) { assert(cellType == k_itemCellType); (void)cellType; // Silence warnings ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index + + /* We need to check now if we need to add parentheses: insertTextInCaller + * calls handleEventWithText, which will reload the autocompletion for the + * added text, which will probably chande the script nodes and + * selectedScriptNode will become invalid. */ + const bool shouldAddParentheses = selectedScriptNode->type() == ScriptNode::Type::WithParentheses; insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); - if (selectedScriptNode->type() == ScriptNode::Type::WithParentheses) { + // WARNING: selectedScriptNode is now invalid + + if (shouldAddParentheses) { insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); } + Container::activeApp()->dismissModalViewController(); return true; } From 4502ae4fbd0e6ef189ec9dee8aee39f336733e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 17:11:32 +0200 Subject: [PATCH 227/453] [apps/code] Change autocomplete color --- apps/code/python_text_area.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index f0ed0ff99..ef92ce613 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -19,7 +19,7 @@ constexpr KDColor KeywordColor = KDColor::RGB24(0xFF000C); // constexpr KDColor BuiltinColor = KDColor::RGB24(0x0086B3); constexpr KDColor OperatorColor = KDColor::RGB24(0xd73a49); constexpr KDColor StringColor = KDColor::RGB24(0x032f62); -constexpr KDColor AutocompleteColor = KDColorRed; +constexpr KDColor AutocompleteColor = KDColor::RGB24(0xC6C6C6); constexpr KDColor BackgroundColor = KDColorWhite; constexpr KDColor HighlightColor = Palette::Select; constexpr KDColor DefaultColor = KDColorBlack; From 9bf361d5a581912f924d396f1d04556e5429efff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 22 Apr 2020 17:21:29 +0200 Subject: [PATCH 228/453] [apps/code] Autocomplete only after edition Reverts 39c3d66cd --- apps/code/python_text_area.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index ef92ce613..b4be26104 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -245,8 +245,11 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { } } bool result = TextArea::handleEvent(event); - if (!m_contentView.isAutocompleting() && selectionIsEmpty()) { - // Add autocompletion after each event handled, if nothing is selected + if (event == Ion::Events::Backspace && !m_contentView.isAutocompleting() && selectionIsEmpty()) { + /* We want to add autocompletion when we are editing a word (after adding or + * deleting text). So if nothing is selected, we add the autocompletion if + * the event is backspace, as autocompletion has already been added if the + * event added text, in handleEventWithText. */ addAutocompletion(); } return result; From da2730dd640c82cf83bc358100f130f41af307d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 10:59:18 +0200 Subject: [PATCH 229/453] [apps/code] Autocomplete at the end of tokens Not at the end of "words" separated by spaces. --- apps/code/editor_controller.cpp | 18 +++++-- apps/code/editor_view.h | 5 +- apps/code/python_text_area.cpp | 74 ++++++++++++++++++++++----- apps/code/python_text_area.h | 17 ++++-- apps/code/variable_box_controller.cpp | 23 +++++---- apps/code/variable_box_controller.h | 3 +- 6 files changed, 107 insertions(+), 33 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 1325f21eb..49a9fee8b 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -124,11 +124,21 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events: VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - /* If the editor should be autocompleting, the variable box has already been - * loaded. We check shouldAutocomplete and not isAutocompleting, because the - * autocompletion result might be empty. */ - if (!m_editorView.shouldAutocomplete()) { + /* If the editor should be autocompleting an identifier, the variable box has + * already been loaded. We check shouldAutocomplete and not isAutocompleting, + * because the autocompletion result might be empty. */ + const char * beginningOfAutocompletion = nullptr; + const char * cursor = nullptr; + PythonTextArea::AutocompletionType autocompType = m_editorView.autocompletionType(&beginningOfAutocompletion, &cursor); + if (autocompType == PythonTextArea::AutocompletionType::NoIdentifier) { varBox->loadFunctionsAndVariables(m_scriptIndex, nullptr, 0); + } else if (autocompType == PythonTextArea::AutocompletionType::MiddleOfIdentifier) { + varBox->empty(); + } else { + assert(autocompType == PythonTextArea::AutocompletionType::EndOfIdentifier); + assert(beginningOfAutocompletion != nullptr && cursor != nullptr); + assert(cursor > beginningOfAutocompletion); + varBox->loadFunctionsAndVariables(m_scriptIndex, beginningOfAutocompletion, cursor - beginningOfAutocompletion); } return varBox; } diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h index 991aaf062..ab3038c94 100644 --- a/apps/code/editor_view.h +++ b/apps/code/editor_view.h @@ -9,7 +9,7 @@ namespace Code { class EditorView : public Responder, public View, public ScrollViewDelegate { public: EditorView(Responder * parentResponder, App * pythonDelegate); - bool shouldAutocomplete() const { return m_textArea.shouldAutocomplete(); } + PythonTextArea::AutocompletionType autocompletionType(const char ** autocompletionBeginning, const char ** autocompletionEnd) const { return m_textArea.autocompletionType(nullptr, autocompletionBeginning, autocompletionEnd); } bool isAutocompleting() const; void resetSelection(); void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { @@ -19,6 +19,9 @@ public: void setText(char * textBuffer, size_t textBufferSize) { m_textArea.setText(textBuffer, textBufferSize); } + const char * cursorLocation() { + return m_textArea.cursorLocation(); + } bool setCursorLocation(const char * location) { return m_textArea.setCursorLocation(location); } diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index b4be26104..103f66f9e 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -53,14 +53,64 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) { } return lex->column - lex->tok_column; } -bool PythonTextArea::shouldAutocomplete(const char * autocompletionLocation) const { - if (isAutocompleting()) { - return true; - } + +PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char * autocompletionLocation, const char ** autocompletionLocationBeginning, const char ** autocompletionLocationEnd) const { const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation(); - CodePoint prevCodePoint = UTF8Helper::PreviousCodePoint(m_contentView.editedText(), location); - return !UTF8Helper::CodePointIsEndOfWord(prevCodePoint) - && UTF8Helper::CodePointIsEndOfWord(UTF8Helper::CodePointAtLocation(location)); + const char * beginningOfToken = nullptr; + + // We want to autocomplete only at the end of an identifier or a keyword + AutocompletionType autocompleteType = AutocompletionType::NoIdentifier; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + const char * firstNonSpace = UTF8Helper::BeginningOfWord(m_contentView.editedText(), location); + mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, UTF8Helper::EndOfWord(location) - firstNonSpace, 0); + + const char * tokenStart; + const char * tokenEnd; + _mp_token_kind_t currentTokenKind = lex->tok_kind; + + while (currentTokenKind != MP_TOKEN_NEWLINE && currentTokenKind != MP_TOKEN_END) { + tokenStart = firstNonSpace + lex->tok_column - 1; + tokenEnd = tokenStart + TokenLength(lex, tokenStart); + + if (location < tokenStart) { + // The location for autocompletion is not in an identifier + break; + } + if (currentTokenKind == MP_TOKEN_NAME + || (currentTokenKind >= MP_TOKEN_KW_FALSE + && currentTokenKind <= MP_TOKEN_KW_YIELD)) + { + if (location < tokenEnd) { + // The location for autocompletion is in the middle of an identifier + autocompleteType = AutocompletionType::MiddleOfIdentifier; + break; + } + if (location == tokenEnd) { + // The location for autocompletion is at the end of an identifier + beginningOfToken = tokenStart; + autocompleteType = AutocompletionType::EndOfIdentifier; + break; + } + } + if (location < tokenStart) { + // The location for autocompletion is not in an identifier + break; + } + mp_lexer_to_next(lex); + currentTokenKind = lex->tok_kind; + } + mp_lexer_free(lex); + nlr_pop(); + } + if (autocompletionLocationBeginning != nullptr) { + *autocompletionLocationBeginning = beginningOfToken; + } + if (autocompletionLocationEnd != nullptr) { + *autocompletionLocationEnd = location; + } + assert(!isAutocompleting() || autocompleteType == AutocompletionType::EndOfIdentifier); + return autocompleteType; } const char * PythonTextArea::ContentView::textToAutocomplete() const { @@ -281,18 +331,18 @@ void PythonTextArea::removeAutocompletion() { void PythonTextArea::addAutocompletion() { assert(!m_contentView.isAutocompleting()); + const char * autocompletionTokenBeginning = nullptr; const char * autocompletionLocation = const_cast(cursorLocation()); const char * textToInsert = nullptr; int textToInsertLength = 0; - if (shouldAutocomplete(autocompletionLocation)) { - /* The previous code point is neither the beginning of the text, nor a - * space, nor a \n, and the next code point is the end of the word. + if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) == AutocompletionType::EndOfIdentifier) { + /* The cursor is at the end of an identifier. * Compute the text to insert: * Look first in the current script variables and functions, then in the * builtins, then in the imported modules/scripts. */ VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); - const char * beginningOfWord = m_contentView.textToAutocomplete(); - textToInsert = varBox->autocompletionForText(m_contentView.pythonDelegate()->menuController()->editedScriptIndex(), beginningOfWord, &textToInsertLength); + const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex(); + textToInsert = varBox->autocompletionForText(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength); } // Try to insert the text (this might fail if the buffer is full) diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 1bbcd2531..28a69a5e0 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -9,6 +9,11 @@ class App; class PythonTextArea : public TextArea { public: + enum class AutocompletionType : uint8_t { + EndOfIdentifier, + MiddleOfIdentifier, + NoIdentifier + }; PythonTextArea(Responder * parentResponder, App * pythonDelegate, const KDFont * font) : TextArea(parentResponder, &m_contentView, font), m_contentView(pythonDelegate, font) @@ -18,10 +23,14 @@ public: void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; - /* shouldAutocomplete returns true if there is currently autocompletion, or if - * there should be autocompletion but there is not because there is no word to - * autocomplete. */ - bool shouldAutocomplete(const char * autocompletionLocation = nullptr) const; + /* autocompletionType returns: + * - EndOfIdentifier if there is currently autocompletion, or if the wursor is + * at the end of an identifier, + * - MiddleOfIdentifier is the cursor is in the middle of an identifier, + * - No identifier otherwise. + * The autocompletionLocation can be provided with autocompletionLocation, or + * retreived with autocompletionLocationBeginning and autocompletionLocationEnd. */ + AutocompletionType autocompletionType(const char * autocompletionLocation = nullptr, const char ** autocompletionLocationBeginning = nullptr, const char ** autocompletionLocationEnd = nullptr) const; bool isAutocompleting() const { return m_contentView.isAutocompleting(); } protected: class ContentView : public TextArea::ContentView { diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 652687968..faea142d1 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -190,16 +190,11 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } } -const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int * textToInsertLength) { - /* The text to autocomplete will most probably not be null-terminated. We thus - * say that the end of the text to autocomplete is the end if the current word, - * determined by the next space char or the next null char.*/ - const char * endOfText = UTF8Helper::EndOfWord(textToAutocomplete); - const int textLength = endOfText - textToAutocomplete; - assert(textLength >= 1); +const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength) { + assert(textToAutocompleteLength >= 1); // First load variables and functions that complete the textToAutocomplete - loadFunctionsAndVariables(scriptIndex, textToAutocomplete, textLength); + loadFunctionsAndVariables(scriptIndex, textToAutocomplete, textToAutocompleteLength); if (numberOfRows() == 0) { return nullptr; } @@ -212,10 +207,16 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const currentNameLength = strlen(currentName); } // Assert the text we return does indeed autocomplete the text to autocomplete - assert(currentNameLength != textLength && strncmp(textToAutocomplete, currentName, textLength) == 0); + assert(currentNameLength != textToAutocompleteLength && strncmp(textToAutocomplete, currentName, textToAutocompleteLength) == 0); // Return the text without the beginning that matches the text to autocomplete - *textToInsertLength = currentNameLength - textLength; - return currentName + textLength; + *textToInsertLength = currentNameLength - textToAutocompleteLength; + return currentName + textToAutocompleteLength; +} + +void VariableBoxController::empty() { + m_builtinNodesCount = 0; + m_currentScriptNodesCount = 0; + m_importedNodesCount = 0; } // PRIVATE METHODS diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 6efe0228d..4b69510af 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -35,7 +35,8 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); - const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int * textToInsertLength); + const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength); + void empty(); private: //TODO LEA use size_t From 2ed0c85ebfee8e7769962051698b5370e4ebba7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 11:19:41 +0200 Subject: [PATCH 230/453] [apps/code] Autocompletion end is end of token, not next ' ' --- apps/code/python_text_area.cpp | 21 ++++++++++++--------- apps/code/python_text_area.h | 6 +++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 103f66f9e..37fa5d790 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -235,13 +235,13 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char // Redraw the autocompleted word in the right color if (m_autocomplete && autocompleteStart >= text && autocompleteStart < text + byteLength) { - const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); + assert(m_autocompletionEnd != nullptr && m_autocompletionEnd > autocompleteStart); drawStringAt( ctx, line, UTF8Helper::GlyphOffsetAtCodePoint(text, autocompleteStart), autocompleteStart, - std::min(text + byteLength, autocompleteEnd) - autocompleteStart, + std::min(text + byteLength, m_autocompletionEnd) - autocompleteStart, AutocompleteColor, BackgroundColor, nullptr, @@ -319,12 +319,13 @@ bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bo void PythonTextArea::removeAutocompletion() { assert(m_contentView.isAutocompleting()); + assert(m_contentView.autocompletionEnd() != nullptr); const char * autocompleteStart = m_contentView.cursorLocation(); - const char * autocompleteEnd = UTF8Helper::EndOfWord(autocompleteStart); - assert(autocompleteEnd >= autocompleteStart); - if (autocompleteEnd > autocompleteStart) { - m_contentView.removeText(autocompleteStart, autocompleteEnd); - } + const char * autocompleteEnd = m_contentView.autocompletionEnd(); + assert(autocompleteEnd != nullptr && autocompleteEnd > autocompleteStart); + //TODO LEA if (autocompleteEnd > autocompleteStart) { + m_contentView.removeText(autocompleteStart, autocompleteEnd); + //TODO LEA } m_contentView.setAutocompleting(false); } @@ -348,15 +349,17 @@ void PythonTextArea::addAutocompletion() { // Try to insert the text (this might fail if the buffer is full) if (textToInsert && textToInsertLength > 0 && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) { m_contentView.setAutocompleting(true); + m_contentView.setAutocompletionEnd(autocompletionLocation + textToInsertLength); } } void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) { assert(m_contentView.isAutocompleting()); + const char * autocompEnd = m_contentView.autocompletionEnd(); m_contentView.setAutocompleting(false); + m_contentView.setAutocompletionEnd(nullptr); if (moveCursorToEndOfAutocompletion) { - const char * autocompleteEnd = UTF8Helper::EndOfWord(m_contentView.cursorLocation()); - setCursorLocation(autocompleteEnd); + setCursorLocation(autocompEnd); addAutocompletion(); } } diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 28a69a5e0..037069446 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -38,12 +38,15 @@ protected: ContentView(App * pythonDelegate, const KDFont * font) : TextArea::ContentView(font), m_pythonDelegate(pythonDelegate), - m_autocomplete(false) + m_autocomplete(false), + m_autocompletionEnd(nullptr) { } App * pythonDelegate() { return m_pythonDelegate; } void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; } bool isAutocompleting() const { return m_autocomplete; } + const char * autocompletionEnd() const { assert(m_autocomplete); return m_autocompletionEnd; } + void setAutocompletionEnd(const char * end) { m_autocompletionEnd = end; } const char * textToAutocomplete() const; void loadSyntaxHighlighter(); void unloadSyntaxHighlighter(); @@ -53,6 +56,7 @@ protected: private: App * m_pythonDelegate; bool m_autocomplete; + const char * m_autocompletionEnd; }; private: void removeAutocompletion(); From 5d2910188d2338e05154b1acafe5795651393f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 11:34:04 +0200 Subject: [PATCH 231/453] [apps/code] Add the parentheses in the autocompletion --- apps/code/python_text_area.cpp | 38 ++++++++++++++++++--------- apps/code/variable_box_controller.cpp | 4 ++- apps/code/variable_box_controller.h | 2 +- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 37fa5d790..8b10201ed 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -331,25 +331,37 @@ void PythonTextArea::removeAutocompletion() { void PythonTextArea::addAutocompletion() { assert(!m_contentView.isAutocompleting()); - const char * autocompletionTokenBeginning = nullptr; const char * autocompletionLocation = const_cast(cursorLocation()); - const char * textToInsert = nullptr; - int textToInsertLength = 0; - if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) == AutocompletionType::EndOfIdentifier) { - /* The cursor is at the end of an identifier. - * Compute the text to insert: - * Look first in the current script variables and functions, then in the - * builtins, then in the imported modules/scripts. */ - VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); - const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex(); - textToInsert = varBox->autocompletionForText(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength); + if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) != AutocompletionType::EndOfIdentifier) { + // The cursor is not at the end of an identifier. + return; } + /* Compute the text to insert: + * Look first in the current script variables and functions, then in the + * builtins, then in the imported modules/scripts. */ + VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); + const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex(); + int textToInsertLength = 0; + bool addParentheses = false; + + const char * textToInsert = varBox->autocompletionForText(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses); // Try to insert the text (this might fail if the buffer is full) - if (textToInsert && textToInsertLength > 0 && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) { + if (textToInsert != nullptr + && textToInsertLength > 0 + && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) + { m_contentView.setAutocompleting(true); - m_contentView.setAutocompletionEnd(autocompletionLocation + textToInsertLength); + autocompletionLocation += textToInsertLength; + m_contentView.setAutocompletionEnd(autocompletionLocation); + } + // Try to insert the parentheses if needed text + const char * parentheses = ScriptNodeCell::k_parentheses; + constexpr int parenthesesLength = 2; + assert(strlen(parentheses) == parenthesesLength); + if (addParentheses && m_contentView.insertTextAtLocation(ScriptNodeCell::k_parentheses, const_cast(autocompletionLocation), parenthesesLength)) { + m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); } } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index faea142d1..e459b3331 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -190,8 +190,9 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha } } -const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength) { +const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses) { assert(textToAutocompleteLength >= 1); + assert(addParentheses != nullptr); // First load variables and functions that complete the textToAutocomplete loadFunctionsAndVariables(scriptIndex, textToAutocomplete, textToAutocompleteLength); @@ -206,6 +207,7 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const if (currentNameLength < 0) { currentNameLength = strlen(currentName); } + *addParentheses = node->type() == ScriptNode::Type::WithParentheses; // Assert the text we return does indeed autocomplete the text to autocomplete assert(currentNameLength != textToAutocompleteLength && strncmp(textToAutocomplete, currentName, textToAutocompleteLength) == 0); // Return the text without the beginning that matches the text to autocomplete diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 4b69510af..414665475 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -35,7 +35,7 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); - const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength); + const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses); void empty(); private: From 94e9a10f168e585e0d29a55b0be3dc63546f1e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 14:00:01 +0200 Subject: [PATCH 232/453] [apps/code] Autocomplete only with parentheses if needed For instance, type "abs", there is "()" autocompletion --- apps/code/python_text_area.cpp | 1 + apps/code/variable_box_controller.cpp | 48 +++++++++++++++------------ apps/code/variable_box_controller.h | 8 +---- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 8b10201ed..b638bdc12 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -361,6 +361,7 @@ void PythonTextArea::addAutocompletion() { constexpr int parenthesesLength = 2; assert(strlen(parentheses) == parenthesesLength); if (addParentheses && m_contentView.insertTextAtLocation(ScriptNodeCell::k_parentheses, const_cast(autocompletionLocation), parenthesesLength)) { + m_contentView.setAutocompleting(true); m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); } } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index e459b3331..0a7fe58d3 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -209,7 +209,9 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const } *addParentheses = node->type() == ScriptNode::Type::WithParentheses; // Assert the text we return does indeed autocomplete the text to autocomplete - assert(currentNameLength != textToAutocompleteLength && strncmp(textToAutocomplete, currentName, textToAutocompleteLength) == 0); + assert((*addParentheses + || currentNameLength != textToAutocompleteLength) + && strncmp(textToAutocomplete, currentName, textToAutocompleteLength) == 0); // Return the text without the beginning that matches the text to autocomplete *textToInsertLength = currentNameLength - textToAutocompleteLength; return currentName + textToAutocompleteLength; @@ -244,15 +246,6 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, return nodeNameLengthStartsWithName ? 1 : -1; } -int VariableBoxController::NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength) { - bool strictlyStartsWith = false; - int result = NodeNameCompare(node, name, nameLength, &strictlyStartsWith); - if (strictlyStartsWith) { - return 0; - } - return result <= 0 ? -1 : 1; -} - int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { if (origin == NodeOrigin::Builtins) { return m_builtinNodesCount; @@ -489,13 +482,25 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_zip), ScriptNode::Type::WithParentheses} }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); + /* We can leverage on the fact that buitin nodes are stored in alphabetical + * order, so we do not use shouldAddNode. */ for (int i = 0; i < k_totalBuiltinNodesCount; i++) { ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name); - int startsWith = textToAutocomplete == nullptr ? 0 : NodeNameStartsWith(&node, textToAutocomplete, textToAutocompleteLength); + + int startsWith = 0; + if (textToAutocomplete != nullptr) { + bool strictlyStartsWith = false; + startsWith = NodeNameCompare(&node, textToAutocomplete, textToAutocompleteLength, &strictlyStartsWith); + if (startsWith == 0) { // The node name and name are equal + startsWith = builtinNames[i].type == ScriptNode::Type::WithParentheses ? 0 : -1; // We accept the node only if it has parentheses + } else if (strictlyStartsWith) { + startsWith = 0; + } else if (startsWith > 0) { + return; + } + } if (startsWith == 0) { m_builtinNodes[m_builtinNodesCount++] = node; - } else if (startsWith > 0) { - break; } } } @@ -577,7 +582,8 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont /* If the token autocompletes the text and it is not already in the * variable box, add it. */ - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength)) { + ScriptNode::Type nodeType = defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType)) { /* This is a trick to get the token position in the text, as name and * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. @@ -591,7 +597,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses, NodeOrigin::CurrentScript, tokenInText, nameLength); + addNode(nodeType, NodeOrigin::CurrentScript, tokenInText, nameLength); } } @@ -783,13 +789,14 @@ void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int if (nodeNameLength < 0) { nodeNameLength = strlen(nodeName); } - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength)) { + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength, type)) { // Add the node in alphabetical order addNode(type, origin, nodeName, nodeNameLength, nodeSourceName, description); } } -bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength) { +bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength, ScriptNode::Type type) { + assert(nodeNameLength > 0); if (textToAutocomplete != nullptr) { /* Check that nodeName autocompletes the text to autocomplete * - The start of nodeName must be equal to the text to autocomplete */ @@ -797,10 +804,9 @@ bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int t return false; } /* - nodeName should be longer than the text to autocomplete. Beware of the - * case where nodeName is textToAutocompleteLength(parameters), which we do - * not want to accept. */ - char firstCharAfterAutocompletion = *(nodeName + textToAutocompleteLength); - if (firstCharAfterAutocompletion == 0 || firstCharAfterAutocompletion == '(') { + * case where nodeName is textToAutocompleteLength(), where we want to add + * the node to autocomplete with parentheses. */ + if (nodeNameLength == textToAutocompleteLength && type != ScriptNode::Type::WithParentheses) { return false; } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 414665475..591d8d326 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -63,12 +63,6 @@ private: * strictlyStartsWith is set to True if the node name starts with name but * they are not equal.*/ static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith = nullptr); - /* Returns: - * - a negative int if the node name is before name in alphabetical - * order or equal to name - * - 0 if node name strictly starts with name - * - a positive int if node name is after name in alphabetical order. */ - static int NodeNameStartsWith(ScriptNode * node, const char * name, int nameLength); // Nodes and nodes count static int MaxNodesCountForOrigin(NodeOrigin origin) { @@ -100,7 +94,7 @@ private: /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); - bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength); + bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength, ScriptNode::Type type); bool contains(const char * name, int nameLength); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); VariableBoxEmptyController m_variableBoxEmptyController; From e7bfb3b5f32e87d3a6b11c9d7093b3e1b8d97957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 17:00:16 +0200 Subject: [PATCH 233/453] [apps/code] Use variable --- apps/code/python_text_area.cpp | 2 +- apps/code/variable_box_controller.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index b638bdc12..4169e359e 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -360,7 +360,7 @@ void PythonTextArea::addAutocompletion() { const char * parentheses = ScriptNodeCell::k_parentheses; constexpr int parenthesesLength = 2; assert(strlen(parentheses) == parenthesesLength); - if (addParentheses && m_contentView.insertTextAtLocation(ScriptNodeCell::k_parentheses, const_cast(autocompletionLocation), parenthesesLength)) { + if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) { m_contentView.setAutocompleting(true); m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 0a7fe58d3..3297b6df6 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -742,7 +742,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par * and "....function". */ constexpr int numberOfNodesToSkip = 3; assert(numberOfChildren > numberOfNodesToSkip); - for (int i = 3; i < numberOfChildren; i++) { + for (int i = numberOfNodesToSkip; i < numberOfChildren; i++) { const char * name = I18n::translate((moduleChildren + i)->label()); checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); } From afdf34bbb9137911543a834159d0cca2a5f66604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 17:07:18 +0200 Subject: [PATCH 234/453] [apps/code] Signed/unsigned comparison --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3297b6df6..c2a365e08 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -678,7 +678,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par bool loadAllContent = structKindIsImportWithoutFrom; size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); - for (int i = 0; i < childNodesCount; i++) { + for (size_t i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { // Parsing something like "import math" From 2a823419ff66d9a517c7febd801f86b520bc0825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 24 Apr 2020 17:53:13 +0200 Subject: [PATCH 235/453] [apps/code] Cycle through possible autocompletions with up/down --- apps/code/python_text_area.cpp | 62 ++++++++++++++++++++------- apps/code/python_text_area.h | 7 ++- apps/code/variable_box_controller.cpp | 30 ++++++++++--- apps/code/variable_box_controller.h | 1 + 4 files changed, 77 insertions(+), 23 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 4169e359e..c9563090f 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -285,6 +285,12 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { || event == Ion::Events::Alpha || event == Ion::Events::OnOff) { + } else if(event == Ion::Events::Up + || event == Ion::Events::Down) + { + //TODO LEA handle only one suggestion in var box. + cycleAutocompletion(event == Ion::Events::Down); + return true; } else { removeAutocompletion(); m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); @@ -318,6 +324,12 @@ bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bo } void PythonTextArea::removeAutocompletion() { + assert(m_contentView.isAutocompleting()); + removeAutocompletionText(); + m_contentView.setAutocompleting(false); +} + +void PythonTextArea::removeAutocompletionText() { assert(m_contentView.isAutocompleting()); assert(m_contentView.autocompletionEnd() != nullptr); const char * autocompleteStart = m_contentView.cursorLocation(); @@ -326,7 +338,6 @@ void PythonTextArea::removeAutocompletion() { //TODO LEA if (autocompleteEnd > autocompleteStart) { m_contentView.removeText(autocompleteStart, autocompleteEnd); //TODO LEA } - m_contentView.setAutocompleting(false); } void PythonTextArea::addAutocompletion() { @@ -337,33 +348,52 @@ void PythonTextArea::addAutocompletion() { // The cursor is not at the end of an identifier. return; } - /* Compute the text to insert: - * Look first in the current script variables and functions, then in the - * builtins, then in the imported modules/scripts. */ - VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); + + // First load variables and functions that complete the textToAutocomplete const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex(); + m_contentView.pythonDelegate()->variableBoxController()->loadFunctionsAndVariables(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning); + + if (addAutocompletionTextAtIndex(0)) { + m_contentView.setAutocompleting(true); + } +} + +bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate) { + // The variable box should be loaded at this point + const char * autocompletionTokenBeginning = nullptr; + const char * autocompletionLocation = const_cast(cursorLocation()); + AutocompletionType type = autocompletionType(autocompletionLocation, &autocompletionTokenBeginning); // Done to get autocompletionTokenBeginning + assert(type == AutocompletionType::EndOfIdentifier); + (void)type; // Silence warnings + VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController(); int textToInsertLength = 0; bool addParentheses = false; - - const char * textToInsert = varBox->autocompletionForText(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses); + const char * textToInsert = varBox->autocompletionAlternativeAtIndex(autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses, nextIndex, currentIndexToUpdate); // Try to insert the text (this might fail if the buffer is full) if (textToInsert != nullptr && textToInsertLength > 0 && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) { - m_contentView.setAutocompleting(true); autocompletionLocation += textToInsertLength; m_contentView.setAutocompletionEnd(autocompletionLocation); + // Try to insert the parentheses if needed text + const char * parentheses = ScriptNodeCell::k_parentheses; + constexpr int parenthesesLength = 2; + assert(strlen(parentheses) == parenthesesLength); + if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) { + m_contentView.setAutocompleting(true); + m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); + } + return true; } - // Try to insert the parentheses if needed text - const char * parentheses = ScriptNodeCell::k_parentheses; - constexpr int parenthesesLength = 2; - assert(strlen(parentheses) == parenthesesLength); - if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) { - m_contentView.setAutocompleting(true); - m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); - } + return false; +} + +void PythonTextArea::cycleAutocompletion(bool downwards) { + assert(m_contentView.isAutocompleting()); + removeAutocompletionText(); + addAutocompletionTextAtIndex(m_autocompletionResultIndex + (downwards ? 1 : -1), &m_autocompletionResultIndex); } void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) { diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 037069446..5ede682b8 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -16,7 +16,8 @@ public: }; PythonTextArea(Responder * parentResponder, App * pythonDelegate, const KDFont * font) : TextArea(parentResponder, &m_contentView, font), - m_contentView(pythonDelegate, font) + m_contentView(pythonDelegate, font), + m_autocompletionResultIndex(0) { } void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); } @@ -60,10 +61,14 @@ protected: }; private: void removeAutocompletion(); + void removeAutocompletionText(); // Just removes the suggested text, not the autocompletion mode void addAutocompletion(); + bool addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate = nullptr); // Assumes the var box is already loaded + void cycleAutocompletion(bool downwards); void acceptAutocompletion(bool moveCursorToEndOfAutocompletion); const ContentView * nonEditableContentView() const override { return &m_contentView; } ContentView m_contentView; + int m_autocompletionResultIndex; }; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c2a365e08..c6d89e7f7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -200,18 +200,36 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const return nullptr; } - // Return the first node - ScriptNode * node = scriptNodeAtIndex(0); + return autocompletionAlternativeAtIndex(textToAutocompleteLength, textToInsertLength, addParentheses, 0); +} + +const char * VariableBoxController::autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate) { + assert(numberOfRows() != 0); + + int nodesCount = 0; // We cannot use numberOfRows as it contains the banners + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + nodesCount += nodesCountForOrigin(origin); + } + if (index < 0) { + assert(index == -1); + index = nodesCount - 1; + } else if (index >= nodesCount) { + assert(index == nodesCount); + index = 0; + } + + if (indexToUpdate != nullptr) { + *indexToUpdate = index; + } + + ScriptNode * node = scriptNodeAtIndex(index); const char * currentName = node->name(); int currentNameLength = node->nameLength(); if (currentNameLength < 0) { currentNameLength = strlen(currentName); } *addParentheses = node->type() == ScriptNode::Type::WithParentheses; - // Assert the text we return does indeed autocomplete the text to autocomplete - assert((*addParentheses - || currentNameLength != textToAutocompleteLength) - && strncmp(textToAutocomplete, currentName, textToAutocompleteLength) == 0); // Return the text without the beginning that matches the text to autocomplete *textToInsertLength = currentNameLength - textToAutocompleteLength; return currentName + textToAutocompleteLength; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 591d8d326..22ea76937 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -36,6 +36,7 @@ public: /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses); + const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr); void empty(); private: From f9bbc94eeaeadd7a8d31859edf09e45dcf0867ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 27 Apr 2020 10:52:03 +0200 Subject: [PATCH 236/453] [apps/code] Handle autocompletionAlternativeAtIndex with no nodes --- apps/code/variable_box_controller.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c6d89e7f7..823c5f29e 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -204,7 +204,9 @@ const char * VariableBoxController::autocompletionForText(int scriptIndex, const } const char * VariableBoxController::autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate) { - assert(numberOfRows() != 0); + if (numberOfRows() == 0) { + return nullptr; + } int nodesCount = 0; // We cannot use numberOfRows as it contains the banners NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; From a7773576f8cc3b26a1be53a314b4b9ed3ac41256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 27 Apr 2020 11:05:45 +0200 Subject: [PATCH 237/453] [apps/code] Fix PythonTextArea::autocompletionType --- apps/code/python_text_area.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index c9563090f..5934d0e50 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -58,8 +58,13 @@ PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation(); const char * beginningOfToken = nullptr; - // We want to autocomplete only at the end of an identifier or a keyword - AutocompletionType autocompleteType = AutocompletionType::NoIdentifier; + /* If there is already autocompleting, the cursor must be at the end of an + * identifier. Trying to compute autocompletionType will fail: because of the + * autocompletion text, the cursor seems to be in the middle of an identifier. */ + AutocompletionType autocompleteType = isAutocompleting() ? AutocompletionType::EndOfIdentifier : AutocompletionType::NoIdentifier; + if (autocompletionLocationBeginning == nullptr && autocompletionLocationEnd == nullptr) { + return autocompleteType; + } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { const char * firstNonSpace = UTF8Helper::BeginningOfWord(m_contentView.editedText(), location); @@ -82,8 +87,10 @@ PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char && currentTokenKind <= MP_TOKEN_KW_YIELD)) { if (location < tokenEnd) { - // The location for autocompletion is in the middle of an identifier - autocompleteType = AutocompletionType::MiddleOfIdentifier; + if (autocompleteType != AutocompletionType::EndOfIdentifier) { + // The location for autocompletion is in the middle of an identifier + autocompleteType = AutocompletionType::MiddleOfIdentifier; + } break; } if (location == tokenEnd) { From 3fe6af281fa54c768f764e8aeb29b9805d92b79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 27 Apr 2020 14:13:16 +0200 Subject: [PATCH 238/453] [apps/code] Fix variable box that crashed --- apps/code/python_text_area.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 5934d0e50..6c39de566 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -80,28 +80,25 @@ PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char if (location < tokenStart) { // The location for autocompletion is not in an identifier + assert(autocompleteType == AutocompletionType::NoIdentifier); break; } - if (currentTokenKind == MP_TOKEN_NAME - || (currentTokenKind >= MP_TOKEN_KW_FALSE - && currentTokenKind <= MP_TOKEN_KW_YIELD)) - { - if (location < tokenEnd) { - if (autocompleteType != AutocompletionType::EndOfIdentifier) { - // The location for autocompletion is in the middle of an identifier - autocompleteType = AutocompletionType::MiddleOfIdentifier; - } - break; - } - if (location == tokenEnd) { - // The location for autocompletion is at the end of an identifier + if (location <= tokenEnd) { + if (currentTokenKind == MP_TOKEN_NAME + || (currentTokenKind >= MP_TOKEN_KW_FALSE + && currentTokenKind <= MP_TOKEN_KW_YIELD)) + { + /* The location for autocompletion is in the middle or at the end of + * an identifier. */ beginningOfToken = tokenStart; - autocompleteType = AutocompletionType::EndOfIdentifier; - break; + /* If autocompleteType is already EndOfIdentifier, we are + * autocompleting, so we do not need to update autocompleteType. If we + * recomputed autocompleteType now, we might wrongly think that it is + * MiddleOfIdentifier because of the autocompetion text. */ + if (autocompleteType != AutocompletionType::EndOfIdentifier) { + autocompleteType = location < tokenEnd ? AutocompletionType::MiddleOfIdentifier : AutocompletionType::EndOfIdentifier; + } } - } - if (location < tokenStart) { - // The location for autocompletion is not in an identifier break; } mp_lexer_to_next(lex); From 2eed894599f61d3c7b1556acd6ab83ef520aef36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 27 Apr 2020 15:59:58 +0200 Subject: [PATCH 239/453] [apps/variable_box_empty_controller] Draw the background This was not necessary when it was only used for the expressions variable box, because the background was already of the right color thanks to the previous displayed menu. We need to draw it for the python variable box. --- apps/variable_box_empty_controller.cpp | 5 ++++- apps/variable_box_empty_controller.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/variable_box_empty_controller.cpp b/apps/variable_box_empty_controller.cpp index a07a8d23d..a31799c50 100644 --- a/apps/variable_box_empty_controller.cpp +++ b/apps/variable_box_empty_controller.cpp @@ -3,13 +3,15 @@ #include #include +const KDColor VariableBoxEmptyController::VariableBoxEmptyView::k_backgroundColor; + // VariableBoxEmptyController::VariableBoxEmptyView void VariableBoxEmptyController::VariableBoxEmptyView::initMessageViews() { const int numberOfMessageViews = numberOfMessageTextViews(); for (int i = 0; i < numberOfMessageViews; i++) { MessageTextView * message = messageTextViewAtIndex(i); message->setFont(k_font); - message->setBackgroundColor(Palette::WallScreen); + message->setBackgroundColor(k_backgroundColor); float verticalAlignment = 0.5f; if (i == 0) { verticalAlignment = 1.0f; @@ -28,6 +30,7 @@ void VariableBoxEmptyController::VariableBoxEmptyView::setMessages(I18n::Message } void VariableBoxEmptyController::VariableBoxEmptyView::drawRect(KDContext * ctx, KDRect rect) const { + ctx->fillRect(bounds(), k_backgroundColor); drawBorderOfRect(ctx, bounds(), Palette::GreyBright); } diff --git a/apps/variable_box_empty_controller.h b/apps/variable_box_empty_controller.h index 4218801fb..fbedcf9af 100644 --- a/apps/variable_box_empty_controller.h +++ b/apps/variable_box_empty_controller.h @@ -22,6 +22,7 @@ protected: void drawRect(KDContext * ctx, KDRect rect) const override; private: constexpr static int k_expressionViewRowIndex = 2; + constexpr static KDColor k_backgroundColor = Palette::WallScreen; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; From f49bf76b1912c189020a4221d61714aa59bfa753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 28 Apr 2020 09:46:08 +0200 Subject: [PATCH 240/453] [apps/code] More complete comment --- apps/code/python_text_area.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 6c39de566..a5c92b017 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -94,7 +94,10 @@ PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char /* If autocompleteType is already EndOfIdentifier, we are * autocompleting, so we do not need to update autocompleteType. If we * recomputed autocompleteType now, we might wrongly think that it is - * MiddleOfIdentifier because of the autocompetion text. */ + * MiddleOfIdentifier because of the autocompetion text. + * Example : fin|ally -> the lexer is at the end of "fin", but because + * we are autocompleting with "ally", the lexer thinks the cursor is + * in the middle of an identifier. */ if (autocompleteType != AutocompletionType::EndOfIdentifier) { autocompleteType = location < tokenEnd ? AutocompletionType::MiddleOfIdentifier : AutocompletionType::EndOfIdentifier; } From 4fb0a7e46707b3c5051ae68f1872bdbf1fae30eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 28 Apr 2020 17:04:42 +0200 Subject: [PATCH 241/453] [apps/code] properly display the importation source - It sould be nameOfScript.py, not just nameOfScript, when the source is a script - Fix the source for script name variables. For instance, "from script1 import *" should display the node "script1" with the source "script1.py" - If a script has the same name as a module, the module will be imported and not the script, so do not load its variables (even if the module is not in the toolbox). --- apps/code/python_toolbox.cpp | 8 +- apps/code/script.h | 2 +- apps/code/variable_box_controller.cpp | 154 +++++++++++++++++--------- apps/code/variable_box_controller.h | 6 +- 4 files changed, 111 insertions(+), 59 deletions(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 1313a7932..efc1241db 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -438,11 +438,13 @@ PythonToolbox::PythonToolbox() : } const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const { - assert(numberOfNodes != nullptr); for (ToolboxMessageTree t : modulesChildren) { if (strcmp(I18n::translate(t.label()), name) == 0) { - *numberOfNodes = t.numberOfChildren(); - assert(*numberOfNodes > 0); + const int childrenCount = t.numberOfChildren(); + if (numberOfNodes != nullptr) { + *numberOfNodes = childrenCount; + } + assert(childrenCount > 0); return static_cast(t.children(0)); } } diff --git a/apps/code/script.h b/apps/code/script.h index fc10352f3..37a204bd6 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -23,7 +23,7 @@ public: static bool DefaultName(char buffer[], size_t bufferSize); static bool nameCompliant(const char * name); - Script(Ion::Storage::Record r) : Record(r) {} + Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {} bool importationStatus() const; void toggleImportationStatus(); const char * scriptContent() const; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 823c5f29e..a69fa535a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -13,6 +13,7 @@ extern "C" { #include "py/lexer.h" #include "py/nlr.h" +#include "py/objmodule.h" } namespace Code { @@ -651,7 +652,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con uint structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(pns); if (structKind == PN_funcdef || structKind == PN_expr_stmt) { // The script is only a single function or variable definition - addImportStruct(pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); + addImportStructFromScript(pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { // The script is is only an import, handled in addNodesFromImportMaybe } else if (structKind == PN_file_input_2) { @@ -666,7 +667,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); if (structKind == PN_funcdef || structKind == PN_expr_stmt) { - addImportStruct(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); + addImportStructFromScript(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); } else { addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); } @@ -701,9 +702,25 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par for (size_t i = 0; i < childNodesCount; i++) { mp_parse_node_t child = parseNode->nodes[i]; if (MP_PARSE_NODE_IS_LEAF(child) && MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID) { - // Parsing something like "import math" + // Parsing something like "import xyz" const char * id = qstr_str(MP_PARSE_NODE_LEAF_ARG(child)); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, "math", "desc" /*TODO LEA*/); + + /* xyz might be: + * - a module name -> in which case we want no importation source on the + * node. The node will not be added if it is already in the builtins. + * - a script name -> we want to have xyz.py as the importation source + * - a non-existing identifier -> we want no source */ + const char * sourceId = nullptr; + if (!importationSourceIsModule(id)) { + /* If a module and a script have the same name, the micropython + * importation algorithm first looks for a module then for a script. We + * should thus check that the id is not a module name before retreiving + * a script name to put it as source. + * TODO Should importationSourceIsModule be called in + * importationSourceIsScript?*/ + importationSourceIsScript(id, &sourceId); + } + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, sourceId); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { // Parsing something like "from math import sin" addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); @@ -717,68 +734,97 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par // Fetch a script / module content if needed if (loadAllContent) { assert(childNodesCount > 0); - mp_parse_node_t importationSource = parseNode->nodes[0]; - const char * importationSourceName = nullptr; - if (MP_PARSE_NODE_IS_LEAF(importationSource) - && MP_PARSE_NODE_LEAF_KIND(importationSource) == MP_PARSE_NODE_ID) - { - // The importation source is "simple", for instance: from math import * - importationSourceName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSource)); - } else if (MP_PARSE_NODE_IS_STRUCT(importationSource)) { - mp_parse_node_struct_t * importationSourcePNS = (mp_parse_node_struct_t *)importationSource; - uint importationSourceStructKind = MP_PARSE_NODE_STRUCT_KIND(importationSourcePNS); - if (importationSourceStructKind == PN_dotted_name) { - /* The importation source is "complex", for instance: - * from matplotlib.pyplot import * - * FIXME The solution would be to build a single qstr for this name, - * such as in python/src/compile.c, function do_import_name, from line - * 1117 (found by searching PN_dotted_name). - * We might do this later, for now the only dotted name we might want to - * find is matplolib.pyplot, so we do a very specific search. */ - int numberOfSplitNames = MP_PARSE_NODE_STRUCT_NUM_NODES(importationSourcePNS); - if (numberOfSplitNames != 2) { - return true; + const char * importationSourceName = importationSourceNameFromNode(parseNode->nodes[0]); + int numberOfModuleChildren = 0; + const ToolboxMessageTree * moduleChildren = nullptr; + if (importationSourceIsModule(importationSourceName, &moduleChildren, &numberOfModuleChildren)) { + if (moduleChildren != nullptr) { + /* The importation source is a module that we display in the toolbox: + * get the nodes from the toolbox + * We skip the 3 first nodes, which are "import ...", "from ... import *" + * and "....function". */ + constexpr int numberOfNodesToSkip = 3; + assert(numberOfModuleChildren > numberOfNodesToSkip); + for (int i = numberOfNodesToSkip; i < numberOfModuleChildren; i++) { + const char * name = I18n::translate((moduleChildren + i)->label()); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); } - const char * importationSourceSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSourcePNS->nodes[0])); - if (strcmp(importationSourceSubName, "matplotlib") != 0) { //TODO LEA once rebased - - return true; - } - importationSourceSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(importationSourcePNS->nodes[1])); - if (strcmp(importationSourceSubName, "pyplot") != 0) { //TODO LEA once rebased - - return true; - } - importationSourceName = "matplotlib.pyplot"; //TODO LEA once rebased } else { - assert(false); //TODO LEA can we indeed assert? - } - } - int numberOfChildren = 0; - const ToolboxMessageTree * moduleChildren = static_cast(App::app()->toolboxForInputEventHandler(nullptr))->moduleChildren(importationSourceName, &numberOfChildren); - if (moduleChildren != nullptr) { - /* If the importation source is a module, get the nodes from the toolbox - * We skip the 3 first nodes, which are "import ...", "from ... import *" - * and "....function". */ - constexpr int numberOfNodesToSkip = 3; - assert(numberOfChildren > numberOfNodesToSkip); - for (int i = numberOfNodesToSkip; i < numberOfChildren; i++) { - const char * name = I18n::translate((moduleChildren + i)->label()); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); + //TODO LEA get module variables } } else { // Try fetching the nodes from a script - Script importedScript = ScriptStore::ScriptBaseNamed(importationSourceName); - if (!importedScript.isNull()) { + Script importedScript; + const char * scriptFullName; + if (importationSourceIsScript(importationSourceName, &scriptFullName, &importedScript)) { const char * scriptContent = importedScript.scriptContent(); assert(scriptContent != nullptr); - loadGlobalAndImportedVariablesInScriptAsImported(importationSourceName, scriptContent, textToAutocomplete, textToAutocompleteLength); + loadGlobalAndImportedVariablesInScriptAsImported(scriptFullName, scriptContent, textToAutocomplete, textToAutocompleteLength); } } } return true; } +const char * VariableBoxController::importationSourceNameFromNode(mp_parse_node_t & node) { + if (MP_PARSE_NODE_IS_LEAF(node) && MP_PARSE_NODE_LEAF_KIND(node) == MP_PARSE_NODE_ID) { + // The importation source is "simple", for instance: from math import * + return qstr_str(MP_PARSE_NODE_LEAF_ARG(node)); + } + if (MP_PARSE_NODE_IS_STRUCT(node)) { + mp_parse_node_struct_t * nodePNS = (mp_parse_node_struct_t *)node; + uint nodeStructKind = MP_PARSE_NODE_STRUCT_KIND(nodePNS); + if (nodeStructKind != PN_dotted_name) { + return nullptr; + } + /* The importation source is "complex", for instance: + * from matplotlib.pyplot import * + * TODO LEA + * FIXME The solution would be to build a single qstr for this name, + * such as in python/src/compile.c, function do_import_name, from line + * 1117 (found by searching PN_dotted_name). + * We might do this later, for now the only dotted name we might want to + * find is matplolib.pyplot, so we do a very specific search. */ + int numberOfSplitNames = MP_PARSE_NODE_STRUCT_NUM_NODES(nodePNS); + if (numberOfSplitNames != 2) { + return nullptr; + } + const char * nodeSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(nodePNS->nodes[0])); + if (strcmp(nodeSubName, qstr_str(MP_QSTR_matplotlib)) == 0) { + nodeSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(nodePNS->nodes[1])); + if (strcmp(nodeSubName, qstr_str(MP_QSTR_pyplot)) == 0) { + qstr_str(MP_QSTR_matplotlib_dot_pyplot); + } + } + } + return nullptr; +} + +bool VariableBoxController::importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren, int * numberOfModuleChildren) { + const ToolboxMessageTree * children = static_cast(App::app()->toolboxForInputEventHandler(nullptr))->moduleChildren(sourceName, numberOfModuleChildren); + if (moduleChildren != nullptr) { + *moduleChildren = children; + } + if (children != nullptr) { + return true; + } + // The sourceName might be a module that is not in the toolbox + return mp_module_get(qstr_from_str(sourceName)) != MP_OBJ_NULL; +} + +bool VariableBoxController::importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript) { + // Try fetching the nodes from a script + Script importedScript = ScriptStore::ScriptBaseNamed(sourceName); + if (importedScript.isNull()) { + return false; + } + *scriptFullName = importedScript.fullName(); + if (retreivedScript != nullptr) { + *retreivedScript = importedScript; + } + return true; +} + const char * structName(mp_parse_node_struct_t * structNode) { // Find the id child node, which stores the struct's name size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode); @@ -795,7 +841,7 @@ const char * structName(mp_parse_node_struct_t * structNode) { return nullptr; } -void VariableBoxController::addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength) { assert(structKind == PN_funcdef || structKind == PN_expr_stmt); // Find the id child node, which stores the struct's name const char * name = structName(pns); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 22ea76937..7e21eff8d 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -3,6 +3,7 @@ #include #include +#include #include "script_node.h" #include "script_node_cell.h" #include "script_store.h" @@ -91,7 +92,10 @@ private: void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); // Returns true if this was an import structure bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); - void addImportStruct(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength); + const char * importationSourceNameFromNode(mp_parse_node_t & node); + bool importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren = nullptr, int * numberOfModuleChildren = nullptr); + bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript = nullptr); + void addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength); /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); From d8cab18eb32457036cf202ac2aa703d2f39d7693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 29 Apr 2020 10:16:47 +0200 Subject: [PATCH 242/453] [apps/code] Do not display varbox source name if it does not fit --- apps/code/script_node_cell.cpp | 11 ++++++++++- apps/code/script_node_cell.h | 15 +++++++++------ apps/code/variable_box_controller.cpp | 4 ++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index e76c46274..e0b42b68e 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -41,10 +41,19 @@ KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { return KDSizeZero; } return KDSize( - Ion::Display::Width - Metric::PopUpLeftMargin - Metric::PopUpRightMargin, + k_optimalWidth, m_scriptNode->description() == nullptr ? k_simpleItemHeight : k_complexItemHeight); } +bool ScriptNodeCell::CanDisplayNameAndSource(int nameLength, const char * source) { + if (source == nullptr) { + return true; + } + assert(nameLength > 0); + const KDFont * font = ScriptNodeView::k_font; + return font->glyphSize().width()*(nameLength + 1) + font->stringSize(source).width() <= ScriptNodeView::k_optimalWidth; // + 1 for the separating space +} + void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) { m_scriptNodeView.setScriptNode(scriptNode); reloadCell(); diff --git a/apps/code/script_node_cell.h b/apps/code/script_node_cell.h index 12c1b7a7b..672a9fb44 100644 --- a/apps/code/script_node_cell.h +++ b/apps/code/script_node_cell.h @@ -10,11 +10,18 @@ namespace Code { class ScriptNodeCell : public TableCell { public: + static_assert('\x11' == UCodePointEmpty, "Unicode error"); + constexpr static char k_parentheses[] = "()"; + constexpr static char k_parenthesesWithEmpty[] = "(\x11)"; + constexpr static KDCoordinate k_simpleItemHeight = 27; + constexpr static KDCoordinate k_complexItemHeight = 42; + ScriptNodeCell() : TableCell(), m_scriptNodeView() {} void setScriptNode(ScriptNode * node); + static bool CanDisplayNameAndSource(int nameLength, const char * source); /* TableCell */ View * labelView() const override { return const_cast(static_cast(&m_scriptNodeView)); } @@ -24,14 +31,11 @@ public: void reloadCell() override; const char * text() const override { return m_scriptNodeView.text(); } - static_assert('\x11' == UCodePointEmpty, "Unicode error"); - constexpr static char k_parentheses[] = "()"; - constexpr static char k_parenthesesWithEmpty[] = "(\x11)"; - constexpr static KDCoordinate k_simpleItemHeight = 27; - constexpr static KDCoordinate k_complexItemHeight = 42; protected: class ScriptNodeView : public HighlightCell { public: + constexpr static const KDFont * k_font = KDFont::SmallFont; + constexpr static KDCoordinate k_optimalWidth = Ion::Display::Width - Metric::PopUpLeftMargin - Metric::PopUpRightMargin; ScriptNodeView() : HighlightCell(), m_scriptNode(nullptr) @@ -43,7 +47,6 @@ protected: return m_scriptNode->description(); } private: - constexpr static const KDFont * k_font = KDFont::SmallFont; constexpr static KDCoordinate k_bottomMargin = 5; constexpr static KDCoordinate k_topMargin = k_bottomMargin + k_separatorThickness; ScriptNode * m_scriptNode; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index a69fa535a..7d8769bb3 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -936,6 +936,10 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co for (int i = *currentNodeCount - 1; i >= insertionIndex; i--) { nodes[i+1] = nodes[i]; } + // Check if the node source name fits, if not, do not use it + if (!ScriptNodeCell::CanDisplayNameAndSource(nameLength, nodeSourceName)) { + nodeSourceName = nullptr; + } // Add the node nodes[insertionIndex] = ScriptNode(type, name, nameLength, nodeSourceName, description); // Increase the node count From c81420c4b2ee3fa9cd715d792251a4dd3491f4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 29 Apr 2020 10:18:17 +0200 Subject: [PATCH 243/453] [apps/code] EXE event accepts autocompletion --- apps/code/python_text_area.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index a5c92b017..6d9074aa5 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -277,7 +277,8 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { // Handle event with autocompletion if (event == Ion::Events::Right || event == Ion::Events::ShiftRight - || event == Ion::Events::OK) + || event == Ion::Events::OK + || event == Ion::Events::EXE) { m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); acceptAutocompletion(event != Ion::Events::ShiftRight); From 9e973adbabe6c723031952603d232168e582a836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 29 Apr 2020 16:41:13 +0200 Subject: [PATCH 244/453] [apps/code] VarBox from console --- apps/code/script.cpp | 11 ++++- apps/code/script.h | 14 +++--- apps/code/variable_box_controller.cpp | 64 ++++++++++++++++++--------- apps/code/variable_box_controller.h | 5 ++- 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/apps/code/script.cpp b/apps/code/script.cpp index 1b33fd0e7..fb38ad234 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -80,7 +80,16 @@ void Script::toggleImportationStatus() { const char * Script::scriptContent() const { assert(!isNull()); Data d = value(); - return (const char *)d.buffer + k_importationStatusSize; + return (const char *)d.buffer + k_autoimportationStatusSize + k_currentImportationStatusSize; } +bool Script::contentFetchedFromConsole() const { + +} + +void Script::setContentFetchedFromConsole(bool fetch) const { + +} +//TODO TODO LEA + } diff --git a/apps/code/script.h b/apps/code/script.h index 37a204bd6..040f45a7d 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -9,12 +9,9 @@ namespace Code { * Script: | AutoImportationStatus | Content |*/ class Script : public Ion::Storage::Record { -private: - // Default script names are chosen between script1 and script99 - static constexpr int k_maxNumberOfDefaultScriptNames = 99; - static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max public: - static constexpr size_t k_importationStatusSize = 1; + static constexpr size_t k_autoimportationStatusSize = 1; + static constexpr size_t k_currentImportationStatusSize = 1; static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; /* 6 = strlen("script") * k_defaultScriptNameNumberMaxSize = maxLength of integers between 1 and 99 @@ -27,6 +24,13 @@ public: bool importationStatus() const; void toggleImportationStatus(); const char * scriptContent() const; + bool contentFetchedFromConsole() const; + void setContentFetchedFromConsole(bool fetch) const; +private: + // Default script names are chosen between script1 and script99 + static constexpr int k_maxNumberOfDefaultScriptNames = 99; + static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max + }; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 7d8769bb3..835b9c7e3 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -163,6 +163,14 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha m_builtinNodesCount = 0; m_importedNodesCount = 0; + if (scriptIndex < 0) { + /* If not script index is given, the variable box is loaded from console. We + * only want to load imported script variables. */ + assert(textToAutocomplete == nullptr); + loadVariablesImportedFromScripts(); + return; + } + if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { textToAutocompleteLength = strlen(textToAutocomplete); } @@ -178,17 +186,12 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha // Always load the builtin functions and variables loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); - - if (scriptIndex < 0) { - //TODO LEA load imported in console - } else { - Script script = m_scriptStore->scriptAtIndex(scriptIndex); - assert(!script.isNull()); - const char * scriptContent = script.scriptContent(); - assert(scriptContent != nullptr); - loadImportedVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); - loadCurrentVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); - } + Script script = m_scriptStore->scriptAtIndex(scriptIndex); + assert(!script.isNull()); + const char * scriptContent = script.scriptContent(); + assert(scriptContent != nullptr); + loadImportedVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); + loadCurrentVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); } const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses) { @@ -379,6 +382,16 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength sender()->handleEventWithText(commandBuffer); } +void VariableBoxController::loadVariablesImportedFromScripts() { + const int scriptsCount = m_scriptStore->numberOfScripts(); + for (int i = 0; i < scriptsCount; i++) { + Script * script = m_scriptStore->scriptAtIndex(i); + if (script->contentFetchedFromConsole()) { + loadGlobalAndImportedVariablesInScriptAsImported(script->fullName(), script->scriptContent(), nullptr, -1, false); + } + } +} + void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) @@ -639,7 +652,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } -void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { +void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -653,7 +666,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con if (structKind == PN_funcdef || structKind == PN_expr_stmt) { // The script is only a single function or variable definition addImportStructFromScript(pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); - } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength)) { + } else if (addNodesFromImportMaybe(pns, textToAutocomplete, textToAutocompleteLength, importFromModules)) { // The script is is only an import, handled in addNodesFromImportMaybe } else if (structKind == PN_file_input_2) { /* At this point, if the script node is not of type "file_input_2", it @@ -669,7 +682,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con if (structKind == PN_funcdef || structKind == PN_expr_stmt) { addImportStructFromScript(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); } else { - addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength); + addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength, importFromModules); } } } @@ -680,7 +693,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con } } -bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength) { +bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { // Determine if the node is an import structure uint structKind = (uint) MP_PARSE_NODE_STRUCT_KIND(parseNode); bool structKindIsImportWithoutFrom = structKind == PN_import_name; @@ -693,10 +706,10 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par return false; } - /* loadAllModuleContent will be True if the struct imports all the content + /* loadAllSourceContent will be True if the struct imports all the content * from a script / module (for instance, "import math"), instead of single * items (for instance, "from math import sin"). */ - bool loadAllContent = structKindIsImportWithoutFrom; + bool loadAllSourceContent = structKindIsImportWithoutFrom; size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(parseNode); for (size_t i = 0; i < childNodesCount; i++) { @@ -718,26 +731,35 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par * a script name to put it as source. * TODO Should importationSourceIsModule be called in * importationSourceIsScript?*/ - importationSourceIsScript(id, &sourceId); + if (!importationSourceIsScript(id, &sourceId) && !importFromModules) { // Warning : must be done in this order + /* We call importationSourceIsScript to load the script name in + * sourceId. We also use it to make sure, if importFromModules is + * false, that we are not importing variables from something else than + * scripts. */ + return true; + } } checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, sourceId); } else if (MP_PARSE_NODE_IS_STRUCT(child)) { // Parsing something like "from math import sin" - addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength); + addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength, importFromModules); } else if (MP_PARSE_NODE_IS_TOKEN(child) && MP_PARSE_NODE_IS_TOKEN_KIND(child, MP_TOKEN_OP_STAR)) { /* Parsing something like "from math import *" * -> Load all the module content */ - loadAllContent = true; + loadAllSourceContent = true; } } // Fetch a script / module content if needed - if (loadAllContent) { + if (loadAllSourceContent) { assert(childNodesCount > 0); const char * importationSourceName = importationSourceNameFromNode(parseNode->nodes[0]); int numberOfModuleChildren = 0; const ToolboxMessageTree * moduleChildren = nullptr; if (importationSourceIsModule(importationSourceName, &moduleChildren, &numberOfModuleChildren)) { + if (!importFromModules) { + return true; + } if (moduleChildren != nullptr) { /* The importation source is a module that we display in the toolbox: * get the nodes from the toolbox diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 7e21eff8d..0a0b9323c 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -86,12 +86,13 @@ private: void insertTextInCaller(const char * text, int textLength = -1); // Loading + void loadVariablesImportedFromScripts(); void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); - void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); + void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true); // Returns true if this was an import structure - bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength); + bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true); const char * importationSourceNameFromNode(mp_parse_node_t & node); bool importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren = nullptr, int * numberOfModuleChildren = nullptr); bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript = nullptr); From d1c8bbdaf7eeb29598e98aebb809860b32274a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 29 Apr 2020 16:54:28 +0200 Subject: [PATCH 245/453] [apps/code] The console marks imported script for the var box After lauching the console, if we fetch a script we mark it as fetched. When the variable box displays variables from imported scripts, it scans all the variables from the scripts marked as fetched. --- apps/code/app.cpp | 2 +- apps/code/console_controller.cpp | 6 +++++- apps/code/editor_controller.cpp | 4 ++-- apps/code/script.cpp | 22 +++++++++++++--------- apps/code/script.h | 21 +++++++++++---------- apps/code/script_parameter_controller.cpp | 4 ++-- apps/code/script_store.cpp | 15 +++++++++++++-- apps/code/script_store.h | 3 ++- apps/code/script_template.cpp | 12 ++++++------ apps/code/script_template.h | 6 ++++-- apps/code/variable_box_controller.cpp | 6 +++--- python/port/port.cpp | 4 ++-- python/port/port.h | 3 ++- 13 files changed, 66 insertions(+), 42 deletions(-) diff --git a/apps/code/app.cpp b/apps/code/app.cpp index 4c017e220..3a54ba988 100644 --- a/apps/code/app.cpp +++ b/apps/code/app.cpp @@ -61,7 +61,7 @@ void App::Snapshot::setOpt(const char * name, const char * value) { const char * scriptContent = separator; Code::ScriptTemplate script(scriptName, scriptContent); m_scriptStore.addScriptFromTemplate(&script); - ScriptStore::ScriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1 + ScriptStore::ScriptNamed(scriptName).toggleAutoimportationStatus(); // set Importation Status to 1 return; } if (strcmp(name, "lock-on-console") == 0) { diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index b60f069e8..36456a896 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -54,10 +54,13 @@ bool ConsoleController::loadPythonEnvironment() { m_pythonDelegate->initPythonWithUser(this); MicroPython::registerScriptProvider(m_scriptStore); m_importScriptsWhenViewAppears = m_autoImportScripts; +#if 0 + //TODO LEA /* We load functions and variables names in the variable box before running * any other python code to avoid failling to load functions and variables * due to memory exhaustion. */ App::app()->variableBoxController()->loadFunctionsAndVariables(-1, nullptr, -1); +#endif return true; } @@ -65,6 +68,7 @@ void ConsoleController::unloadPythonEnvironment() { if (!m_pythonDelegate->isPythonUser(nullptr)) { m_consoleStore.startNewSession(); m_pythonDelegate->deinitPython(); + m_scriptStore->clearFetchInformation(); } } @@ -474,7 +478,7 @@ void ConsoleController::autoImportScript(Script script, bool force) { * the sandbox. */ hideAnyDisplayedViewController(); - if (script.importationStatus() || force) { + if (script.autoImportationStatus() || force) { // Step 1 - Create the command "from scriptName import *". assert(strlen(k_importCommand1) + strlen(script.fullName()) - strlen(ScriptStore::k_scriptExtension) - 1 + strlen(k_importCommand2) + 1 <= k_maxImportCommandSize); diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 49a9fee8b..2a10bbc50 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -37,7 +37,7 @@ void EditorController::setScript(Script script, int scriptIndex) { * */ size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script); - m_editorView.setText(const_cast(m_script.scriptContent()), newScriptSize - Script::k_importationStatusSize); + m_editorView.setText(const_cast(m_script.scriptContent()), newScriptSize - Script::InformationSize()); } void EditorController::willExitApp() { @@ -154,7 +154,7 @@ void EditorController::cleanStorageEmptySpace() { Ion::Storage::Record::Data scriptValue = m_script.value(); Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( m_script, - scriptValue.size - Script::k_importationStatusSize - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches + scriptValue.size - Script::InformationSize() - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches } diff --git a/apps/code/script.cpp b/apps/code/script.cpp index fb38ad234..15a9419f5 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -65,31 +65,35 @@ bool Script::nameCompliant(const char * name) { return false; } -bool Script::importationStatus() const { +bool Script::autoImportationStatus() const { assert(!isNull()); Data d = value(); return (((char *)d.buffer)[0] == 1); } -void Script::toggleImportationStatus() { +void Script::toggleAutoimportationStatus() { + assert(!isNull()); Data d = value(); ((char *)d.buffer)[0] = (((char *)d.buffer)[0] == 1 ? 0 : 1); setValue(d); } const char * Script::scriptContent() const { - assert(!isNull()); Data d = value(); - return (const char *)d.buffer + k_autoimportationStatusSize + k_currentImportationStatusSize; + return ((const char *)d.buffer) + InformationSize(); } bool Script::contentFetchedFromConsole() const { - + assert(!isNull()); + Data d = value(); + return (((char *)d.buffer)[k_autoImportationStatusSize] == 1); } -void Script::setContentFetchedFromConsole(bool fetch) const { - -} -//TODO TODO LEA +void Script::setContentFetchedFromConsole(bool fetch) { + assert(!isNull()); + Data d = value(); + ((char *)d.buffer)[k_autoImportationStatusSize] = fetch; + setValue(d); +} } diff --git a/apps/code/script.h b/apps/code/script.h index 040f45a7d..36dbe9ea6 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -9,9 +9,14 @@ namespace Code { * Script: | AutoImportationStatus | Content |*/ class Script : public Ion::Storage::Record { -public: - static constexpr size_t k_autoimportationStatusSize = 1; +private: + // Default script names are chosen between script1 and script99 + static constexpr int k_maxNumberOfDefaultScriptNames = 99; + static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max + + static constexpr size_t k_autoImportationStatusSize = 1; //TODO LEA use only 1 byte for both status flags static constexpr size_t k_currentImportationStatusSize = 1; +public: static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; /* 6 = strlen("script") * k_defaultScriptNameNumberMaxSize = maxLength of integers between 1 and 99 @@ -19,18 +24,14 @@ public: static bool DefaultName(char buffer[], size_t bufferSize); static bool nameCompliant(const char * name); + static constexpr size_t InformationSize() { return k_autoImportationStatusSize + k_currentImportationStatusSize; } Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {} - bool importationStatus() const; - void toggleImportationStatus(); + bool autoImportationStatus() const; + void toggleAutoimportationStatus(); const char * scriptContent() const; bool contentFetchedFromConsole() const; - void setContentFetchedFromConsole(bool fetch) const; -private: - // Default script names are chosen between script1 and script99 - static constexpr int k_maxNumberOfDefaultScriptNames = 99; - static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max - + void setContentFetchedFromConsole(bool fetch); }; } diff --git a/apps/code/script_parameter_controller.cpp b/apps/code/script_parameter_controller.cpp index ab31e778d..5332fddc3 100644 --- a/apps/code/script_parameter_controller.cpp +++ b/apps/code/script_parameter_controller.cpp @@ -42,7 +42,7 @@ bool ScriptParameterController::handleEvent(Ion::Events::Event event) { m_menuController->renameSelectedScript(); return true; case 2: - m_script.toggleImportationStatus(); + m_script.toggleAutoimportationStatus(); m_selectableTableView.reloadData(); m_menuController->reloadConsole(); Container::activeApp()->setFirstResponder(&m_selectableTableView); @@ -81,7 +81,7 @@ HighlightCell * ScriptParameterController::reusableCell(int index) { void ScriptParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) { if (cell == &m_autoImportScript) { SwitchView * switchView = (SwitchView *)m_autoImportScript.accessoryView(); - switchView->setState(m_script.importationStatus()); + switchView->setState(m_script.autoImportationStatus()); } } diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index c4062a9b6..37fd45cbf 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -25,16 +25,27 @@ bool ScriptStore::isFull() { return Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit; } -const char * ScriptStore::contentOfScript(const char * name) { +const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) { Script script = ScriptNamed(name); if (script.isNull()) { return nullptr; } + if (markAsFetched) { + script.setContentFetchedFromConsole(true); + } return script.scriptContent(); } +void ScriptStore::clearFetchInformation() { + // TODO optimize fetches + const int scriptsCount = numberOfScripts(); + for (int i = 0; i < scriptsCount; i++) { + scriptAtIndex(i).setContentFetchedFromConsole(false); + } +} + Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) { - size_t valueSize = strlen(scriptTemplate->content())+1+1;// scriptcontent size + 1 char for the importation status + size_t valueSize = Script::InformationSize() + strlen(scriptTemplate->content()) + 1; // (auto importation status + content fetched status) + scriptcontent size + null-terminating char assert(Script::nameCompliant(scriptTemplate->name())); Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithFullName(scriptTemplate->name(), scriptTemplate->value(), valueSize); assert(err != Script::ErrorStatus::NonCompliantName); diff --git a/apps/code/script_store.h b/apps/code/script_store.h index ae5f7dbf6..3b3cf9a9c 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -39,7 +39,8 @@ public: bool isFull(); /* MicroPython::ScriptProvider */ - const char * contentOfScript(const char * name) override; + const char * contentOfScript(const char * name, bool markAsFetched) override; + void clearFetchInformation() override; Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate); private: diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index 488cd362a..df6350040 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -2,15 +2,15 @@ namespace Code { -constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import * +constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01\x00" R"(from math import * )"); -constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( +constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"( #from math import sin as stew, cos as cabbage from math import * )"); -/*constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"( +/*constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"( import math import math as m import math, cmath @@ -31,7 +31,7 @@ from math import sin as stew from math import sin, cos from math import sin as stew, cos as cabbage */ -constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set +constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01\x00" R"(# This script draws a Mandelbrot fractal set # N_iteration: degree of precision import kandinsky def mandelbrot(N_iteration): @@ -51,7 +51,7 @@ def mandelbrot(N_iteration): # Draw a pixel colored in 'col' at position (x,y) kandinsky.set_pixel(x,y,col))"); -constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import * +constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01\x00" R"(from math import * # roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0 def roots(a,b,c): delta = b*b-4*a*c @@ -64,7 +64,7 @@ def roots(a,b,c): else: return None)"); -constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import * +constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01\x00" R"(from matplotlib.pyplot import * from math import * g=9.81 diff --git a/apps/code/script_template.h b/apps/code/script_template.h index d0d048ab1..02a53f87d 100644 --- a/apps/code/script_template.h +++ b/apps/code/script_template.h @@ -1,6 +1,8 @@ #ifndef CODE_SCRIPT_TEMPLATE_H #define CODE_SCRIPT_TEMPLATE_H +#include "script.h" + namespace Code { class ScriptTemplate { @@ -12,11 +14,11 @@ public: static const ScriptTemplate * Polynomial(); static const ScriptTemplate * Parabola(); const char * name() const { return m_name; } - const char * content() const { return m_value+1; } + const char * content() const { return m_value + Script::InformationSize(); } const char * value() const { return m_value; } private: const char * m_name; - const char * m_value; // hold the 'importation status' flag concatenate with the script content + const char * m_value; // holds the 'importation status' and 'current importation status' flags concatenated with the script content }; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 835b9c7e3..87240f40f 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -385,9 +385,9 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength void VariableBoxController::loadVariablesImportedFromScripts() { const int scriptsCount = m_scriptStore->numberOfScripts(); for (int i = 0; i < scriptsCount; i++) { - Script * script = m_scriptStore->scriptAtIndex(i); - if (script->contentFetchedFromConsole()) { - loadGlobalAndImportedVariablesInScriptAsImported(script->fullName(), script->scriptContent(), nullptr, -1, false); + Script script = m_scriptStore->scriptAtIndex(i); + if (script.contentFetchedFromConsole()) { + loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.scriptContent(), nullptr, -1, false); // TODO optimize number of script fetches } } } diff --git a/python/port/port.cpp b/python/port/port.cpp index bac7595ca..6ae0c36c9 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -288,7 +288,7 @@ void nlr_jump_fail(void *val) { mp_lexer_t * mp_lexer_new_from_file(const char * filename) { if (sScriptProvider != nullptr) { - const char * script = sScriptProvider->contentOfScript(filename); + const char * script = sScriptProvider->contentOfScript(filename, true); if (script != nullptr) { return mp_lexer_new_from_str_len(qstr_from_str(filename), script, strlen(script), 0 /* size_t free_len*/); } else { @@ -300,7 +300,7 @@ mp_lexer_t * mp_lexer_new_from_file(const char * filename) { } mp_import_stat_t mp_import_stat(const char *path) { - if (sScriptProvider && sScriptProvider->contentOfScript(path)) { + if (sScriptProvider && sScriptProvider->contentOfScript(path, false)) { return MP_IMPORT_STAT_FILE; } return MP_IMPORT_STAT_NO_EXIST; diff --git a/python/port/port.h b/python/port/port.h index 3ab3a603f..3cef6ec0a 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -12,7 +12,8 @@ namespace MicroPython { class ScriptProvider { public: - virtual const char * contentOfScript(const char * name) = 0; + virtual const char * contentOfScript(const char * name, bool markAsFetched) = 0; + virtual void clearFetchInformation() = 0; }; class ExecutionEnvironment { From ac654f00970b0d4bbb31877436ceee6a95aa4473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 10:37:24 +0200 Subject: [PATCH 246/453] [apps/code] Load varbox before returning it in console --- apps/code/console_controller.cpp | 8 +++++++- apps/code/console_controller.h | 7 ++++++- apps/code/variable_box_controller.cpp | 24 +++++++++++------------- apps/code/variable_box_controller.h | 2 +- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 36456a896..da5603e04 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -30,7 +30,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe m_pythonDelegate(pythonDelegate), m_importScriptsWhenViewAppears(false), m_selectableTableView(this, this, this, this), - m_editCell(this, pythonDelegate, this), + m_editCell(this, this, this), m_scriptStore(scriptStore), m_sandboxController(this), m_inputRunLoopActive(false) @@ -378,6 +378,12 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { return true; } +VariableBoxController * ConsoleController::variableBoxForInputEventHandler(InputEventHandler * textInput) { + VariableBoxController * varBox = App::app()->variableBoxController(); + varBox->loadVariablesImportedFromScripts(); + return varBox; +} + void ConsoleController::resetSandbox() { if (stackViewController()->topViewController() != sandbox()) { return; diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index f198255a6..cd3cae701 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -9,12 +9,14 @@ #include "console_store.h" #include "sandbox_controller.h" #include "script_store.h" +#include "variable_box_controller.h" +#include "../shared/input_event_handler_delegate.h" namespace Code { class App; -class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment { +class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public Shared::InputEventHandlerDelegate, public MicroPython::ExecutionEnvironment { public: ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore #if EPSILON_GETOPT @@ -59,6 +61,9 @@ public: bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidAbortEditing(TextField * textField) override; + // InputEventHandlerDelegate + VariableBoxController * variableBoxForInputEventHandler(InputEventHandler * textInput) override; + // MicroPython::ExecutionEnvironment ViewController * sandbox() override { return &m_sandboxController; } void resetSandbox() override; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 87240f40f..68ef37d0b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -159,9 +159,7 @@ int VariableBoxController::typeAtLocation(int i, int j) { void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { // Reset the node counts - m_currentScriptNodesCount = 0; - m_builtinNodesCount = 0; - m_importedNodesCount = 0; + empty(); if (scriptIndex < 0) { /* If not script index is given, the variable box is loaded from console. We @@ -241,6 +239,16 @@ const char * VariableBoxController::autocompletionAlternativeAtIndex(int textToA return currentName + textToAutocompleteLength; } +void VariableBoxController::loadVariablesImportedFromScripts() { + const int scriptsCount = m_scriptStore->numberOfScripts(); + for (int i = 0; i < scriptsCount; i++) { + Script script = m_scriptStore->scriptAtIndex(i); + if (script.contentFetchedFromConsole()) { + loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.scriptContent(), nullptr, -1, false); // TODO optimize number of script fetches + } + } +} + void VariableBoxController::empty() { m_builtinNodesCount = 0; m_currentScriptNodesCount = 0; @@ -382,16 +390,6 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength sender()->handleEventWithText(commandBuffer); } -void VariableBoxController::loadVariablesImportedFromScripts() { - const int scriptsCount = m_scriptStore->numberOfScripts(); - for (int i = 0; i < scriptsCount; i++) { - Script script = m_scriptStore->scriptAtIndex(i); - if (script.contentFetchedFromConsole()) { - loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.scriptContent(), nullptr, -1, false); // TODO optimize number of script fetches - } - } -} - void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 0a0b9323c..54a341f25 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -38,6 +38,7 @@ public: void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses); const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr); + void loadVariablesImportedFromScripts(); void empty(); private: @@ -86,7 +87,6 @@ private: void insertTextInCaller(const char * text, int textLength = -1); // Loading - void loadVariablesImportedFromScripts(); void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); From 5ffcb77c69caf5c47f491f589837851ba408aa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 10:40:11 +0200 Subject: [PATCH 247/453] [apps/code] Fix missing return --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 68ef37d0b..c24da82d7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -813,7 +813,7 @@ const char * VariableBoxController::importationSourceNameFromNode(mp_parse_node_ if (strcmp(nodeSubName, qstr_str(MP_QSTR_matplotlib)) == 0) { nodeSubName = qstr_str(MP_PARSE_NODE_LEAF_ARG(nodePNS->nodes[1])); if (strcmp(nodeSubName, qstr_str(MP_QSTR_pyplot)) == 0) { - qstr_str(MP_QSTR_matplotlib_dot_pyplot); + return qstr_str(MP_QSTR_matplotlib_dot_pyplot); } } } From 0c82334a963f9d612767f32259f161af919a8660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 11:16:47 +0200 Subject: [PATCH 248/453] [apps/code] Fix preventing module importations in varbox from console --- apps/code/variable_box_controller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c24da82d7..786cd7b55 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -722,7 +722,11 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par * - a script name -> we want to have xyz.py as the importation source * - a non-existing identifier -> we want no source */ const char * sourceId = nullptr; - if (!importationSourceIsModule(id)) { + if (importationSourceIsModule(id)) { + if (!importFromModules) { + return true; + } + } else { /* If a module and a script have the same name, the micropython * importation algorithm first looks for a module then for a script. We * should thus check that the id is not a module name before retreiving From ccca872a0fd14fca77bf4d40dd6a8572b1d701d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 11:20:29 +0200 Subject: [PATCH 249/453] [appx/code] Empty variable box before loading it in the console --- apps/code/variable_box_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 786cd7b55..c16af0a26 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -240,6 +240,7 @@ const char * VariableBoxController::autocompletionAlternativeAtIndex(int textToA } void VariableBoxController::loadVariablesImportedFromScripts() { + empty(); const int scriptsCount = m_scriptStore->numberOfScripts(); for (int i = 0; i < scriptsCount; i++) { Script script = m_scriptStore->scriptAtIndex(i); From 2fbf5d2d9f34ff81277dd45cfa5983cb2ae16d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 11:46:46 +0200 Subject: [PATCH 250/453] [apps/code] No variables starting with underscore in imported variables In the variable box --- apps/code/variable_box_controller.cpp | 29 ++++++++++++--------------- apps/code/variable_box_controller.h | 2 +- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c16af0a26..b2e61fef5 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -35,18 +35,6 @@ constexpr static uint PN_import_as_name = 99; // sin as stew constexpr static uint PN_import_as_names = 102; // ... import sin as stew, cos as cabbage constexpr static uint PN_dotted_name = 104; -//TODO LEA use this -static bool shouldAddObject(const char * name, int maxLength) { - if (strlen(name)+1 > (size_t)maxLength) { - return false; - } - assert(name != nullptr); - if (UTF8Helper::CodePointIs(name, '_')) { - return false; - } - return true; -} - VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : AlternateEmptyNestedMenuController(I18n::Message::FunctionsAndVariables), m_scriptStore(scriptStore), @@ -616,7 +604,8 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont /* If the token autocompletes the text and it is not already in the * variable box, add it. */ ScriptNode::Type nodeType = defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType)) { + const NodeOrigin origin = NodeOrigin::CurrentScript; + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { /* This is a trick to get the token position in the text, as name and * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. @@ -630,7 +619,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(nodeType, NodeOrigin::CurrentScript, tokenInText, nameLength); + addNode(nodeType, origin, tokenInText, nameLength); } } @@ -880,14 +869,22 @@ void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int if (nodeNameLength < 0) { nodeNameLength = strlen(nodeName); } - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength, type)) { + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength, type, origin)) { // Add the node in alphabetical order addNode(type, origin, nodeName, nodeNameLength, nodeSourceName, description); } } -bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength, ScriptNode::Type type) { +bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength, ScriptNode::Type type, NodeOrigin origin) { assert(nodeNameLength > 0); + assert(nodeName != nullptr); + + /* If the node will go to imported, do not add it if it starts with an + * underscore : such identifiers are meant to be private. */ + if (origin == NodeOrigin::Importation && UTF8Helper::CodePointIs(nodeName, '_')) { + return false; + } + if (textToAutocomplete != nullptr) { /* Check that nodeName autocompletes the text to autocomplete * - The start of nodeName must be equal to the text to autocomplete */ diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 54a341f25..0537c7f62 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -100,7 +100,7 @@ private: /* Add a node if it completes the text to autocomplete and if it is not * already contained in the variable box. */ void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); - bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength, ScriptNode::Type type); + bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength, ScriptNode::Type type, NodeOrigin origin); bool contains(const char * name, int nameLength); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); VariableBoxEmptyController m_variableBoxEmptyController; From 5986716031ab3ac2c79f8f8c653d9cd41673a7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 12:08:28 +0200 Subject: [PATCH 251/453] [apps/code] Fix first varbox row that never appeared again After scrolling down --- apps/code/variable_box_controller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index b2e61fef5..61bb7e7f7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -133,6 +133,8 @@ void VariableBoxController::tableViewDidChangeSelection(SelectableTableView * t, const int currentSelectedRow = selectedRow(); if (currentSelectedRow >= 0 && typeAtLocation(0, currentSelectedRow) == k_subtitleCellType) { if (currentSelectedRow == 0) { + // We scroll to the first cell, otherwise it will never appear again + t->scrollToCell(0, 0); t->selectCellAtLocation(0, 1); } else { t->selectCellAtLocation(0, selectedRow() + (previousSelectedCellY < currentSelectedRow ? 1 : -1)); From bba5b237d20ccfc59f03117d17a6c7d7d80a0f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 12:18:58 +0200 Subject: [PATCH 252/453] [apps/code] Display different varbox titles from editor and console --- apps/code/console_controller.cpp | 1 + apps/code/editor_controller.cpp | 1 + escher/include/escher/nested_menu_controller.h | 2 ++ escher/src/nested_menu_controller.cpp | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index da5603e04..04cdc79c4 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -380,6 +380,7 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { VariableBoxController * ConsoleController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); + varBox->setTitle(I18n::Message::FunctionsAndVariables); varBox->loadVariablesImportedFromScripts(); return varBox; } diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 2a10bbc50..704b814f5 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -140,6 +140,7 @@ VariableBoxController * EditorController::variableBoxForInputEventHandler(InputE assert(cursor > beginningOfAutocompletion); varBox->loadFunctionsAndVariables(m_scriptIndex, beginningOfAutocompletion, cursor - beginningOfAutocompletion); } + varBox->setTitle(I18n::Message::Autocomplete); return varBox; } diff --git a/escher/include/escher/nested_menu_controller.h b/escher/include/escher/nested_menu_controller.h index 1cc2ab1ad..6711c5eb1 100644 --- a/escher/include/escher/nested_menu_controller.h +++ b/escher/include/escher/nested_menu_controller.h @@ -11,6 +11,7 @@ class NestedMenuController : public StackViewController, public ListViewDataSour public: NestedMenuController(Responder * parentResponder, I18n::Message title = (I18n::Message)0); void setSender(InputEventHandler * sender) { m_sender = sender; } + void setTitle(I18n::Message title); // StackViewController bool handleEvent(Ion::Events::Event event) override; @@ -48,6 +49,7 @@ protected: public: ListController(Responder * parentResponder, SelectableTableView * tableView, I18n::Message title); const char * title() override; + void setTitle(I18n::Message title) { m_title = title; } View * view() override; void didBecomeFirstResponder() override; void setFirstSelectedRow(int firstSelectedRow); diff --git a/escher/src/nested_menu_controller.cpp b/escher/src/nested_menu_controller.cpp index 12d0263ae..652420e2c 100644 --- a/escher/src/nested_menu_controller.cpp +++ b/escher/src/nested_menu_controller.cpp @@ -98,6 +98,10 @@ NestedMenuController::NestedMenuController(Responder * parentResponder, I18n::Me m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None); } +void NestedMenuController::setTitle(I18n::Message title) { + m_listController.setTitle(title); +} + bool NestedMenuController::handleEvent(Ion::Events::Event event) { return handleEventForRow(event, selectedRow()); } From 6d7b294bca64c7221895daa565e0aa3fb425357c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 14:14:08 +0200 Subject: [PATCH 253/453] [apps/escher] Rename ToolboxMessageTree::children -> childAtIndex --- apps/code/python_toolbox.cpp | 8 ++++---- apps/math_toolbox.cpp | 2 +- apps/settings/main_controller.cpp | 14 +++++++------- apps/settings/sub_menu/generic_sub_controller.cpp | 2 +- apps/settings/sub_menu/preferences_controller.cpp | 2 +- apps/shared/settings_message_tree.h | 2 +- escher/include/escher/message_tree.h | 2 +- escher/include/escher/toolbox_message_tree.h | 2 +- escher/src/toolbox.cpp | 8 ++++---- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index efc1241db..83f0b462e 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -445,7 +445,7 @@ const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int *numberOfNodes = childrenCount; } assert(childrenCount > 0); - return static_cast(t.children(0)); + return static_cast(t.childAtIndex(0)); } } return nullptr; @@ -476,7 +476,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) { * We thus decided to compute the real height only for the ifStatement * children of the toolbox, which is the only menu that has special height * rows. */ - const ToolboxMessageTree * messageTree = static_cast(m_messageTreeModel->children(j)); + const ToolboxMessageTree * messageTree = static_cast(m_messageTreeModel->childAtIndex(j)); return k_font->stringSize(I18n::translate(messageTree->label())).height() + 2*Metric::TableCellVerticalMargin + (messageTree->text() == I18n::Message::Default ? 0 : Toolbox::rowHeight(j)); } return Toolbox::rowHeight(j); @@ -484,7 +484,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) { bool PythonToolbox::selectLeaf(int selectedRow) { m_selectableTableView.deselectTable(); - ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow); + ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow); const char * editedText = I18n::translate(node->insertedText()); // strippedEditedText array needs to be in the same scope as editedText char strippedEditedText[k_maxMessageSize]; @@ -525,7 +525,7 @@ void PythonToolbox::scrollToLetter(char letter) { char lowerLetter = tolower(letter); int index = -1; for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) { - char l = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]); + char l = tolower(I18n::translate(m_messageTreeModel->childAtIndex(i)->label())[0]); if (l == lowerLetter) { index = i; break; diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 53c77e3c3..0a6e18c4b 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -300,7 +300,7 @@ MathToolbox::MathToolbox() : } bool MathToolbox::selectLeaf(int selectedRow) { - ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow); + ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow); m_selectableTableView.deselectTable(); // Translate the message diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 3b5bf9b49..5464241ed 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -44,8 +44,8 @@ void MainController::didBecomeFirstResponder() { bool MainController::handleEvent(Ion::Events::Event event) { GlobalPreferences * globalPreferences = GlobalPreferences::sharedGlobalPreferences(); - if (model()->children(selectedRow())->numberOfChildren() == 0) { - if (model()->children(selectedRow())->label() == promptMessage()) { + if (model()->childAtIndex(selectedRow())->numberOfChildren() == 0) { + if (model()->childAtIndex(selectedRow())->label() == promptMessage()) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { globalPreferences->setShowPopUp(!globalPreferences->showPopUp()); m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()); @@ -53,7 +53,7 @@ bool MainController::handleEvent(Ion::Events::Event event) { } return false; } - if (model()->children(selectedRow())->label() == I18n::Message::Brightness) { + if (model()->childAtIndex(selectedRow())->label() == I18n::Message::Brightness) { if (event == Ion::Events::Right || event == Ion::Events::Left || event == Ion::Events::Plus || event == Ion::Events::Minus) { int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates; int direction = (event == Ion::Events::Right || event == Ion::Events::Plus) ? delta : -delta; @@ -63,7 +63,7 @@ bool MainController::handleEvent(Ion::Events::Event event) { } return false; } - if (model()->children(selectedRow())->label() == I18n::Message::Language) { + if (model()->childAtIndex(selectedRow())->label() == I18n::Message::Language) { if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) { stackController()->push(&m_languageController); return true; @@ -85,7 +85,7 @@ bool MainController::handleEvent(Ion::Events::Event event) { } else { subController = &m_preferencesController; } - subController->setMessageTreeModel(model()->children(selectedRow())); + subController->setMessageTreeModel(model()->childAtIndex(selectedRow())); StackViewController * stack = stackController(); stack->push(subController); return true; @@ -153,7 +153,7 @@ int MainController::typeAtLocation(int i, int j) { void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { GlobalPreferences * globalPreferences = GlobalPreferences::sharedGlobalPreferences(); Preferences * preferences = Preferences::sharedPreferences(); - I18n::Message title = model()->children(index)->label(); + I18n::Message title = model()->childAtIndex(index)->label(); if (index == k_indexOfBrightnessCell) { MessageTableCellWithGaugeWithSeparator * myGaugeCell = (MessageTableCellWithGaugeWithSeparator *)cell; myGaugeCell->setMessage(title); @@ -193,7 +193,7 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { childIndex = GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont ? 0 : 1; break; } - I18n::Message message = childIndex >= 0 ? model()->children(index)->children(childIndex)->label() : I18n::Message::Default; + I18n::Message message = childIndex >= 0 ? model()->childAtIndex(index)->childAtIndex(childIndex)->label() : I18n::Message::Default; myTextCell->setSubtitle(message); } diff --git a/apps/settings/sub_menu/generic_sub_controller.cpp b/apps/settings/sub_menu/generic_sub_controller.cpp index 40f658955..5286743d1 100644 --- a/apps/settings/sub_menu/generic_sub_controller.cpp +++ b/apps/settings/sub_menu/generic_sub_controller.cpp @@ -76,7 +76,7 @@ int GenericSubController::typeAtLocation(int i, int j) { void GenericSubController::willDisplayCellForIndex(HighlightCell * cell, int index) { MessageTableCell * myCell = (MessageTableCell *)cell; - myCell->setMessage(m_messageTreeModel->children(index)->label()); + myCell->setMessage(m_messageTreeModel->childAtIndex(index)->label()); } void GenericSubController::setMessageTreeModel(const MessageTree * messageTreeModel) { diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index 5013a2bd4..7145f5c05 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -124,7 +124,7 @@ Layout PreferencesController::layoutForPreferences(I18n::Message message) { void PreferencesController::willDisplayCellForIndex(HighlightCell * cell, int index) { GenericSubController::willDisplayCellForIndex(cell, index); MessageTableCellWithExpression * myCell = (MessageTableCellWithExpression *)cell; - myCell->setLayout(layoutForPreferences(m_messageTreeModel->children(index)->label())); + myCell->setLayout(layoutForPreferences(m_messageTreeModel->childAtIndex(index)->label())); } KDCoordinate PreferencesController::rowHeight(int j) { diff --git a/apps/shared/settings_message_tree.h b/apps/shared/settings_message_tree.h index f3c3bf364..b37122b7a 100644 --- a/apps/shared/settings_message_tree.h +++ b/apps/shared/settings_message_tree.h @@ -19,7 +19,7 @@ public: m_children(children) {} - const MessageTree * children(int index) const override { return &m_children[index]; } + const MessageTree * childAtIndex(int index) const override { return &m_children[index]; } private: const SettingsMessageTree * m_children; diff --git a/escher/include/escher/message_tree.h b/escher/include/escher/message_tree.h index f6625cb3a..3983cc3f6 100644 --- a/escher/include/escher/message_tree.h +++ b/escher/include/escher/message_tree.h @@ -10,7 +10,7 @@ public: m_numberOfChildren(numberOfChildren) { }; - virtual const MessageTree * children(int index) const = 0; + virtual const MessageTree * childAtIndex(int index) const = 0; I18n::Message label() const { return m_label; } int numberOfChildren() const { return m_numberOfChildren; } bool isNull() const { return (m_label == (I18n::Message)0); } diff --git a/escher/include/escher/toolbox_message_tree.h b/escher/include/escher/toolbox_message_tree.h index c4a70d77c..835bccde5 100644 --- a/escher/include/escher/toolbox_message_tree.h +++ b/escher/include/escher/toolbox_message_tree.h @@ -24,7 +24,7 @@ public: N, true); } - const MessageTree * children(int index) const override { return &m_children[index]; } + const MessageTree * childAtIndex(int index) const override { return &m_children[index]; } I18n::Message text() const { return m_text; } I18n::Message insertedText() const { return m_insertedText; } bool stripInsertedText() const { return m_stripInsertedText; } diff --git a/escher/src/toolbox.cpp b/escher/src/toolbox.cpp index c2ebf0603..0066dd4bf 100644 --- a/escher/src/toolbox.cpp +++ b/escher/src/toolbox.cpp @@ -25,7 +25,7 @@ int Toolbox::reusableCellCount(int type) { } void Toolbox::willDisplayCellForIndex(HighlightCell * cell, int index) { - ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->children(index); + ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(index); if (messageTree->numberOfChildren() == 0) { MessageTableCellWithMessage * myCell = (MessageTableCellWithMessage *)cell; myCell->setMessage(messageTree->label()); @@ -39,7 +39,7 @@ void Toolbox::willDisplayCellForIndex(HighlightCell * cell, int index) { } int Toolbox::typeAtLocation(int i, int j) { - MessageTree * messageTree = (MessageTree *)m_messageTreeModel->children(j); + MessageTree * messageTree = (MessageTree *)m_messageTreeModel->childAtIndex(j); if (messageTree->numberOfChildren() == 0) { return LeafCellType; } @@ -48,7 +48,7 @@ int Toolbox::typeAtLocation(int i, int j) { bool Toolbox::selectSubMenu(int selectedRow) { m_selectableTableView.deselectTable(); - m_messageTreeModel = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow); + m_messageTreeModel = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow); return NestedMenuController::selectSubMenu(selectedRow); } @@ -63,7 +63,7 @@ bool Toolbox::returnToPreviousMenu() { ToolboxMessageTree * parentMessageTree = (ToolboxMessageTree *)rootModel(); Stack::State * previousState = m_stack.stateAtIndex(index++); while (currentDepth-- > 1) { - parentMessageTree = (ToolboxMessageTree *)parentMessageTree->children(previousState->selectedRow()); + parentMessageTree = (ToolboxMessageTree *)parentMessageTree->childAtIndex(previousState->selectedRow()); previousState = m_stack.stateAtIndex(index++); } m_messageTreeModel = parentMessageTree; From cf6b9d580bd69cde5fae922863caa7a26c384d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 14:32:21 +0200 Subject: [PATCH 254/453] [apps/code] rename Script::scriptContent() -> Script::content() --- apps/code/editor_controller.cpp | 4 ++-- apps/code/script.cpp | 2 +- apps/code/script.h | 2 +- apps/code/script_store.cpp | 2 +- apps/code/variable_box_controller.cpp | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 704b814f5..8ffb0f4c6 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -37,7 +37,7 @@ void EditorController::setScript(Script script, int scriptIndex) { * */ size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script); - m_editorView.setText(const_cast(m_script.scriptContent()), newScriptSize - Script::InformationSize()); + m_editorView.setText(const_cast(m_script.content()), newScriptSize - Script::InformationSize()); } void EditorController::willExitApp() { @@ -155,7 +155,7 @@ void EditorController::cleanStorageEmptySpace() { Ion::Storage::Record::Data scriptValue = m_script.value(); Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( m_script, - scriptValue.size - Script::InformationSize() - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches + scriptValue.size - Script::InformationSize() - (strlen(m_script.content()) + 1)); // TODO optimize number of script fetches } diff --git a/apps/code/script.cpp b/apps/code/script.cpp index 15a9419f5..f74e4e367 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -78,7 +78,7 @@ void Script::toggleAutoimportationStatus() { setValue(d); } -const char * Script::scriptContent() const { +const char * Script::content() const { Data d = value(); return ((const char *)d.buffer) + InformationSize(); } diff --git a/apps/code/script.h b/apps/code/script.h index 36dbe9ea6..c1d5e3664 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -29,7 +29,7 @@ public: Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {} bool autoImportationStatus() const; void toggleAutoimportationStatus(); - const char * scriptContent() const; + const char * content() const; bool contentFetchedFromConsole() const; void setContentFetchedFromConsole(bool fetch); }; diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 37fd45cbf..80fdb523d 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -33,7 +33,7 @@ const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) if (markAsFetched) { script.setContentFetchedFromConsole(true); } - return script.scriptContent(); + return script.content(); } void ScriptStore::clearFetchInformation() { diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 61bb7e7f7..e01bcbfb3 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -176,7 +176,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); Script script = m_scriptStore->scriptAtIndex(scriptIndex); assert(!script.isNull()); - const char * scriptContent = script.scriptContent(); + const char * scriptContent = script.content(); assert(scriptContent != nullptr); loadImportedVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); loadCurrentVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); @@ -235,7 +235,7 @@ void VariableBoxController::loadVariablesImportedFromScripts() { for (int i = 0; i < scriptsCount; i++) { Script script = m_scriptStore->scriptAtIndex(i); if (script.contentFetchedFromConsole()) { - loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.scriptContent(), nullptr, -1, false); // TODO optimize number of script fetches + loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.content(), nullptr, -1, false); // TODO optimize number of script fetches } } } @@ -773,7 +773,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par Script importedScript; const char * scriptFullName; if (importationSourceIsScript(importationSourceName, &scriptFullName, &importedScript)) { - const char * scriptContent = importedScript.scriptContent(); + const char * scriptContent = importedScript.content(); assert(scriptContent != nullptr); loadGlobalAndImportedVariablesInScriptAsImported(scriptFullName, scriptContent, textToAutocomplete, textToAutocompleteLength); } From 8ed902ceb2d217fb0a09b097f03fb1838fb02ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 14:37:18 +0200 Subject: [PATCH 255/453] [app/code] Comment about ContentFetchedFromConsoleStatus in Script --- apps/code/script.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/code/script.h b/apps/code/script.h index c1d5e3664..f58d4b428 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -5,8 +5,14 @@ namespace Code { -/* Record : | Total Size | Name | Body | - * Script: | AutoImportationStatus | Content |*/ +/* Record: | Size | Name | Body | + * Script: | | | AutoImportationStatus | ContentFetchedFromConsoleStatus | Content | + * + * AutoImportationStatus is 1 if the script should be auto imported when the + * console opens. + * + * ContentFetchedFromConsoleStatus is 1 if hte console has currently imported + * this script. This is used to import the right variables in the variable box. */ class Script : public Ion::Storage::Record { private: From 790cb374df36f9d170b35ce8321c45e46a8ab5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 14:43:29 +0200 Subject: [PATCH 256/453] [apps/code] i18n in alphabetical order --- apps/code/base.de.i18n | 14 +++++++------- apps/code/base.en.i18n | 14 +++++++------- apps/code/base.es.i18n | 14 +++++++------- apps/code/base.fr.i18n | 14 +++++++------- apps/code/base.it.i18n | 14 +++++++------- apps/code/base.nl.i18n | 14 +++++++------- apps/code/base.pt.i18n | 14 +++++++------- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/apps/code/base.de.i18n b/apps/code/base.de.i18n index a94f7e3e9..15a39732e 100644 --- a/apps/code/base.de.i18n +++ b/apps/code/base.de.i18n @@ -1,13 +1,13 @@ -Console = "Interaktive Konsole" AddScript = "Skript hinzufügen" -ScriptOptions = "Skriptoptionen" -ExecuteScript = "Skript ausführen" -AutoImportScript = "Automatischer Import in Konsole" -DeleteScript = "Skript löschen" -FunctionsAndVariables = "Funktionen und Variablen" AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _" Autocomplete = "Autovervollständigung" -ScriptInProgress = "Aktuelle Skript" +AutoImportScript = "Automatischer Import in Konsole" BuiltinsAndKeywords = "Native Funktionen und Schlüsselwörter" +Console = "Interaktive Konsole" +DeleteScript = "Skript löschen" +ExecuteScript = "Skript ausführen" +FunctionsAndVariables = "Funktionen und Variablen" ImportedModulesAndScripts = "Importierte Module und Skripte" NoWordAvailableHere = "Kein Wort ist hier verfübar." +ScriptInProgress = "Aktuelle Skript" +ScriptOptions = "Skriptoptionen" diff --git a/apps/code/base.en.i18n b/apps/code/base.en.i18n index ac53cd42f..4dcdfbd3b 100644 --- a/apps/code/base.en.i18n +++ b/apps/code/base.en.i18n @@ -1,13 +1,13 @@ -Console = "Python shell" AddScript = "Add a script" -ScriptOptions = "Script options" -ExecuteScript = "Execute script" -AutoImportScript = "Auto import in shell" -DeleteScript = "Delete script" -FunctionsAndVariables = "Functions and variables" AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" Autocomplete = "Autocomplete" -ScriptInProgress = "Script in progress" +AutoImportScript = "Auto import in shell" BuiltinsAndKeywords = "Builtins and keywords" +Console = "Python shell" +DeleteScript = "Delete script" +ExecuteScript = "Execute script" +FunctionsAndVariables = "Functions and variables" ImportedModulesAndScripts = "Imported modules and scripts" NoWordAvailableHere = "No word available here." +ScriptInProgress = "Script in progress" +ScriptOptions = "Script options" diff --git a/apps/code/base.es.i18n b/apps/code/base.es.i18n index 3ac3694ab..ccceb896f 100644 --- a/apps/code/base.es.i18n +++ b/apps/code/base.es.i18n @@ -1,13 +1,13 @@ -Console = "Interprete de comandos" AddScript = "Agregar un archivo" -ScriptOptions = "Opciones del archivo" -ExecuteScript = "Ejecutar el archivo" -AutoImportScript = "Importación auto en intérprete" -DeleteScript = "Eliminar el archivo" -FunctionsAndVariables = "Funciones y variables" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" Autocomplete = "Autocompleción" -ScriptInProgress = "Archivo en curso" +AutoImportScript = "Importación auto en intérprete" BuiltinsAndKeywords = "Funciones nativas y palabras clave" +Console = "Interprete de comandos" +DeleteScript = "Eliminar el archivo" +ExecuteScript = "Ejecutar el archivo" +FunctionsAndVariables = "Funciones y variables" ImportedModulesAndScripts = "Módulos y archivos importados" NoWordAvailableHere = "No hay ninguna palabra disponible aquí." +ScriptInProgress = "Archivo en curso" +ScriptOptions = "Opciones del archivo" diff --git a/apps/code/base.fr.i18n b/apps/code/base.fr.i18n index b133eba46..bd3179ee7 100644 --- a/apps/code/base.fr.i18n +++ b/apps/code/base.fr.i18n @@ -1,13 +1,13 @@ -Console = "Console d'exécution" AddScript = "Ajouter un script" -ScriptOptions = "Options de script" -ExecuteScript = "Exécuter le script" -AutoImportScript = "Importation auto dans la console" -DeleteScript = "Supprimer le script" -FunctionsAndVariables = "Fonctions et variables" AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" Autocomplete = "Auto-complétion" -ScriptInProgress = "Script en cours" +AutoImportScript = "Importation auto dans la console" BuiltinsAndKeywords = "Fonctions natives et mots-clés" +Console = "Console d'exécution" +DeleteScript = "Supprimer le script" +ExecuteScript = "Exécuter le script" +FunctionsAndVariables = "Fonctions et variables" ImportedModulesAndScripts = "Modules et scripts importés" NoWordAvailableHere = "Aucun mot disponible à cet endroit." +ScriptInProgress = "Script en cours" +ScriptOptions = "Options de script" diff --git a/apps/code/base.it.i18n b/apps/code/base.it.i18n index ea2a614e8..be1e56b8c 100644 --- a/apps/code/base.it.i18n +++ b/apps/code/base.it.i18n @@ -1,13 +1,13 @@ -Console = "Console d'esecuzione" AddScript = "Aggiungere script" -ScriptOptions = "Opzioni dello script" -ExecuteScript = "Eseguire lo script" -AutoImportScript = "Importazione automatica dello script" -DeleteScript = "Eliminare lo script" -FunctionsAndVariables = "Funzioni e variabili" AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _" Autocomplete = "Autocompletamento" -ScriptInProgress = "Script in corso" +AutoImportScript = "Importazione automatica dello script" BuiltinsAndKeywords = "Funzioni native e parole chiave" +Console = "Console d'esecuzione" +DeleteScript = "Eliminare lo script" +ExecuteScript = "Eseguire lo script" +FunctionsAndVariables = "Funzioni e variabili" ImportedModulesAndScripts = "Moduli e scripts importati" NoWordAvailableHere = "Nessuna parola disponibile qui." +ScriptInProgress = "Script in corso" +ScriptOptions = "Opzioni dello script" diff --git a/apps/code/base.nl.i18n b/apps/code/base.nl.i18n index b9916b3d2..e016172c2 100644 --- a/apps/code/base.nl.i18n +++ b/apps/code/base.nl.i18n @@ -1,13 +1,13 @@ -Console = "Python shell" AddScript = "Script toevoegen" -ScriptOptions = "Script opties" -ExecuteScript = "Script uitvoeren" -AutoImportScript = "Automatisch importeren in shell" -DeleteScript = "Script verwijderen" -FunctionsAndVariables = "Functies en variabelen" AllowedCharactersaz09 = "Toegestane tekens: a-z, 0-9, _" Autocomplete = "Autocomplete" -ScriptInProgress = "Script in progress" +AutoImportScript = "Automatisch importeren in shell" BuiltinsAndKeywords = "Builtins and keywords" +Console = "Python shell" +DeleteScript = "Script verwijderen" +ExecuteScript = "Script uitvoeren" +FunctionsAndVariables = "Functies en variabelen" ImportedModulesAndScripts = "Imported modules and scripts" NoWordAvailableHere = "No word available here." +ScriptInProgress = "Script in progress" +ScriptOptions = "Script opties" diff --git a/apps/code/base.pt.i18n b/apps/code/base.pt.i18n index 6c872142e..3a4a8839c 100644 --- a/apps/code/base.pt.i18n +++ b/apps/code/base.pt.i18n @@ -1,13 +1,13 @@ -Console = "Interpretador interativo" AddScript = "Adicionar um script" -ScriptOptions = "Opções de script" -ExecuteScript = "Executar o script" -AutoImportScript = "Importação auto no interpretador" -DeleteScript = "Eliminar o script" -FunctionsAndVariables = "Funções e variáveis" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" Autocomplete = "Preenchimento automático" -ScriptInProgress = "Script em curso" +AutoImportScript = "Importação auto no interpretador" BuiltinsAndKeywords = "Funções nativas e palavras-chave" +Console = "Interpretador interativo" +DeleteScript = "Eliminar o script" +ExecuteScript = "Executar o script" +FunctionsAndVariables = "Funções e variáveis" ImportedModulesAndScripts = "Módulos e scripts importados" NoWordAvailableHere = "Nenhuma palavra disponível aqui." +ScriptInProgress = "Script em curso" +ScriptOptions = "Opções de script" From 645a55284f576156819b24039b5ee4a613d4516d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 14:58:26 +0200 Subject: [PATCH 257/453] [apps/variable_box_empty_controller] Remove unneeded include --- apps/variable_box_empty_controller.h | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/variable_box_empty_controller.h b/apps/variable_box_empty_controller.h index fbedcf9af..da1e658b0 100644 --- a/apps/variable_box_empty_controller.h +++ b/apps/variable_box_empty_controller.h @@ -5,7 +5,6 @@ #include #include #include -#include class VariableBoxEmptyController : public ViewController { public: From f306b51fc5490de08325dbda3778e0f59633a085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 15:10:57 +0200 Subject: [PATCH 258/453] [apps/escher] Move ModalViewEmptyController to escher --- apps/Makefile | 1 - apps/code/variable_box_empty_controller.cpp | 2 +- apps/code/variable_box_empty_controller.h | 8 +++--- apps/math_variable_box_empty_controller.cpp | 2 +- apps/math_variable_box_empty_controller.h | 8 +++--- escher/Makefile | 1 + .../escher/modal_view_empty_controller.h | 12 ++++----- .../src/modal_view_empty_controller.cpp | 25 +++++++++---------- 8 files changed, 29 insertions(+), 30 deletions(-) rename apps/variable_box_empty_controller.h => escher/include/escher/modal_view_empty_controller.h (74%) rename apps/variable_box_empty_controller.cpp => escher/src/modal_view_empty_controller.cpp (71%) diff --git a/apps/Makefile b/apps/Makefile index 3d73f627b..6c2bb1e4e 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -39,7 +39,6 @@ apps_src += $(addprefix apps/,\ shift_alpha_lock_view.cpp \ suspend_timer.cpp \ title_bar_view.cpp \ - variable_box_empty_controller.cpp \ ) tests_src += apps/exam_mode_configuration_official.cpp diff --git a/apps/code/variable_box_empty_controller.cpp b/apps/code/variable_box_empty_controller.cpp index 28afc0fd5..83bd42471 100644 --- a/apps/code/variable_box_empty_controller.cpp +++ b/apps/code/variable_box_empty_controller.cpp @@ -4,7 +4,7 @@ namespace Code { VariableBoxEmptyController::VariableBoxEmptyView::VariableBoxEmptyView() : - ::VariableBoxEmptyController::VariableBoxEmptyView() + ::ModalViewEmptyController::ModalViewEmptyView() { initMessageViews(); m_message.setMessage(I18n::Message::NoWordAvailableHere); diff --git a/apps/code/variable_box_empty_controller.h b/apps/code/variable_box_empty_controller.h index f29d3a928..d78cea504 100644 --- a/apps/code/variable_box_empty_controller.h +++ b/apps/code/variable_box_empty_controller.h @@ -1,20 +1,20 @@ #ifndef APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H #define APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H -#include +#include namespace Code { -class VariableBoxEmptyController : public ::VariableBoxEmptyController { +class VariableBoxEmptyController : public ModalViewEmptyController { public: VariableBoxEmptyController() : - ::VariableBoxEmptyController(), + ModalViewEmptyController(), m_view() {} // View Controller View * view() override { return &m_view; } private: - class VariableBoxEmptyView : public ::VariableBoxEmptyController::VariableBoxEmptyView { + class VariableBoxEmptyView : public ModalViewEmptyController::ModalViewEmptyView { public: constexpr static int k_numberOfMessages = 1; VariableBoxEmptyView(); diff --git a/apps/math_variable_box_empty_controller.cpp b/apps/math_variable_box_empty_controller.cpp index f36380d99..f5ad187f7 100644 --- a/apps/math_variable_box_empty_controller.cpp +++ b/apps/math_variable_box_empty_controller.cpp @@ -4,7 +4,7 @@ #include MathVariableBoxEmptyController::MathVariableBoxEmptyView::MathVariableBoxEmptyView() : - VariableBoxEmptyView(), + ModalViewEmptyView(), m_layoutExample(0.5f, 0.5f, KDColorBlack, Palette::WallScreen) { initMessageViews(); diff --git a/apps/math_variable_box_empty_controller.h b/apps/math_variable_box_empty_controller.h index 9083b3bca..120ff42b6 100644 --- a/apps/math_variable_box_empty_controller.h +++ b/apps/math_variable_box_empty_controller.h @@ -1,13 +1,13 @@ #ifndef APPS_MATH_VARIABLE_BOX_EMPTY_CONTROLLER_H #define APPS_MATH_VARIABLE_BOX_EMPTY_CONTROLLER_H +#include #include -#include "variable_box_empty_controller.h" -class MathVariableBoxEmptyController : public VariableBoxEmptyController { +class MathVariableBoxEmptyController : public ModalViewEmptyController { public: MathVariableBoxEmptyController() : - VariableBoxEmptyController(), + ModalViewEmptyController(), m_view() {} enum class Type { @@ -20,7 +20,7 @@ public: View * view() override { return &m_view; } void viewDidDisappear() override; private: - class MathVariableBoxEmptyView : public VariableBoxEmptyView { + class MathVariableBoxEmptyView : public ModalViewEmptyController::ModalViewEmptyView { public: constexpr static int k_numberOfMessages = 4; MathVariableBoxEmptyView(); diff --git a/escher/Makefile b/escher/Makefile index f47a998ac..ce108c712 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -47,6 +47,7 @@ escher_src += $(addprefix escher/src/,\ message_text_view.cpp \ metric.cpp \ modal_view_controller.cpp \ + modal_view_empty_controller.cpp \ nested_menu_controller.cpp \ palette.cpp \ pointer_text_view.cpp \ diff --git a/apps/variable_box_empty_controller.h b/escher/include/escher/modal_view_empty_controller.h similarity index 74% rename from apps/variable_box_empty_controller.h rename to escher/include/escher/modal_view_empty_controller.h index da1e658b0..cf175aab4 100644 --- a/apps/variable_box_empty_controller.h +++ b/escher/include/escher/modal_view_empty_controller.h @@ -1,19 +1,19 @@ -#ifndef APPS_VARIABLE_BOX_EMPTY_CONTROLLER_H -#define APPS_VARIABLE_BOX_EMPTY_CONTROLLER_H +#ifndef ESCHER_EMPTY_MODAL_VIEW_EMPTY_CONTROLLER_H +#define ESCHER_EMPTY_MODAL_VIEW_EMPTY_CONTROLLER_H #include #include #include #include -class VariableBoxEmptyController : public ViewController { +class ModalViewEmptyController : public ViewController { public: - VariableBoxEmptyController() : ViewController(nullptr) {} + ModalViewEmptyController() : ViewController(nullptr) {} void setMessages(I18n::Message * messages); // View Controller DisplayParameter displayParameter() override { return DisplayParameter::DoNotShowOwnTitle; } protected: - class VariableBoxEmptyView : public View, public Bordered { + class ModalViewEmptyView : public View, public Bordered { public: constexpr static const KDFont * k_font = KDFont::SmallFont; void initMessageViews(); @@ -28,7 +28,7 @@ protected: virtual int numberOfMessageTextViews() const = 0; virtual MessageTextView * messageTextViewAtIndex(int index) = 0; bool hasExpressionView() const { - return const_cast(this)->expressionView() != nullptr; + return const_cast(this)->expressionView() != nullptr; } virtual ExpressionView * expressionView() { return nullptr; } }; diff --git a/apps/variable_box_empty_controller.cpp b/escher/src/modal_view_empty_controller.cpp similarity index 71% rename from apps/variable_box_empty_controller.cpp rename to escher/src/modal_view_empty_controller.cpp index a31799c50..3a3d071d6 100644 --- a/apps/variable_box_empty_controller.cpp +++ b/escher/src/modal_view_empty_controller.cpp @@ -1,12 +1,11 @@ -#include "variable_box_empty_controller.h" -#include +#include #include #include -const KDColor VariableBoxEmptyController::VariableBoxEmptyView::k_backgroundColor; +const KDColor ModalViewEmptyController::ModalViewEmptyView::k_backgroundColor; -// VariableBoxEmptyController::VariableBoxEmptyView -void VariableBoxEmptyController::VariableBoxEmptyView::initMessageViews() { +// ModalViewEmptyController::ModalViewEmptyView +void ModalViewEmptyController::ModalViewEmptyView::initMessageViews() { const int numberOfMessageViews = numberOfMessageTextViews(); for (int i = 0; i < numberOfMessageViews; i++) { MessageTextView * message = messageTextViewAtIndex(i); @@ -22,23 +21,23 @@ void VariableBoxEmptyController::VariableBoxEmptyView::initMessageViews() { } } -void VariableBoxEmptyController::VariableBoxEmptyView::setMessages(I18n::Message * message) { +void ModalViewEmptyController::ModalViewEmptyView::setMessages(I18n::Message * message) { const int numberOfMessageViews = numberOfMessageTextViews(); for (int i = 0; i < numberOfMessageViews; i++) { messageTextViewAtIndex(i)->setMessage(message[i]); } } -void VariableBoxEmptyController::VariableBoxEmptyView::drawRect(KDContext * ctx, KDRect rect) const { +void ModalViewEmptyController::ModalViewEmptyView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(bounds(), k_backgroundColor); drawBorderOfRect(ctx, bounds(), Palette::GreyBright); } -int VariableBoxEmptyController::VariableBoxEmptyView::numberOfSubviews() const { +int ModalViewEmptyController::ModalViewEmptyView::numberOfSubviews() const { return numberOfMessageTextViews() + hasExpressionView(); } -View * VariableBoxEmptyController::VariableBoxEmptyView::subviewAtIndex(int index) { +View * ModalViewEmptyController::ModalViewEmptyView::subviewAtIndex(int index) { if (hasExpressionView()) { if (index == k_expressionViewRowIndex) { return expressionView(); @@ -48,7 +47,7 @@ View * VariableBoxEmptyController::VariableBoxEmptyView::subviewAtIndex(int inde return messageTextViewAtIndex(index); } -void VariableBoxEmptyController::VariableBoxEmptyView::layoutSubviews(bool force) { +void ModalViewEmptyController::ModalViewEmptyView::layoutSubviews(bool force) { const int numberOfMessageViews = numberOfMessageTextViews(); const bool hasExpression = hasExpressionView(); KDCoordinate width = bounds().width() - 2 * k_separatorThickness; @@ -75,8 +74,8 @@ void VariableBoxEmptyController::VariableBoxEmptyView::layoutSubviews(bool force } } -// VariableBoxEmptyController +// ModalViewEmptyController -void VariableBoxEmptyController::setMessages(I18n::Message * messages) { - static_cast(view())->setMessages(messages); +void ModalViewEmptyController::setMessages(I18n::Message * messages) { + static_cast(view())->setMessages(messages); } From 59db24c51852990b3f6a0c28cdfcb1b1ee5efe33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 15:16:53 +0200 Subject: [PATCH 259/453] [apps/code/variable_box_controller] Comment out unused variables --- apps/code/variable_box_controller.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index e01bcbfb3..1602b4c27 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -26,14 +26,16 @@ constexpr static uint PN_funcdef = 3; constexpr static uint PN_expr_stmt = 5; constexpr static uint PN_import_name = 14; // import math // import math as m // import math, cmath // import math as m, cmath as cm constexpr static uint PN_import_from = 15; // from math import * // from math import sin // from math import sin as stew // from math import sin, cos // from math import sin as stew, cos as cabbage // from a.b import * -constexpr static uint PN_import_stmt = 92; // ? -constexpr static uint PN_import_from_2 = 93; // ? -constexpr static uint PN_import_from_2b = 94; // "from .foo import" -constexpr static uint PN_import_from_3 = 95; // ? -constexpr static uint PN_import_as_names_paren = 96; // ? -constexpr static uint PN_import_as_name = 99; // sin as stew +constexpr static uint PN_import_as_name = 99; // sin as stew constexpr static uint PN_import_as_names = 102; // ... import sin as stew, cos as cabbage constexpr static uint PN_dotted_name = 104; +/* These are not used for now but might be relevant at some point? +constexpr static uint PN_import_stmt = 92; +constexpr static uint PN_import_from_2 = 93; +constexpr static uint PN_import_from_2b = 94; // "from .foo import" +constexpr static uint PN_import_from_3 = 95; +constexpr static uint PN_import_as_names_paren = 96; +*/ VariableBoxController::VariableBoxController(ScriptStore * scriptStore) : AlternateEmptyNestedMenuController(I18n::Message::FunctionsAndVariables), From e28f4ed7e2ad1a97623ec802d1b179c0c703c7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 15:18:27 +0200 Subject: [PATCH 260/453] [apps/code/variable_box_controller] Use std::min --- apps/code/variable_box_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 1602b4c27..ec31fbae1 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -9,6 +9,7 @@ #include #include #include +#include extern "C" { #include "py/lexer.h" @@ -18,8 +19,6 @@ extern "C" { namespace Code { -static inline int minInt(int x, int y) { return x < y ? x : y; } - // Got these in python/py/src/compile.cpp compiled file constexpr static uint PN_file_input_2 = 1; constexpr static uint PN_funcdef = 3; @@ -256,7 +255,7 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, assert(nameLength > 0); const char * nodeName = node->name(); const int nodeNameLength = node->nameLength() < 0 ? strlen(nodeName) : node->nameLength(); - const int comparisonLength = minInt(nameLength, nodeNameLength); + const int comparisonLength = std::min(nameLength, nodeNameLength); int result = strncmp(nodeName, name, comparisonLength); if (result != 0) { return result; @@ -377,7 +376,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { void VariableBoxController::insertTextInCaller(const char * text, int textLength) { int textLen = textLength < 0 ? strlen(text) : textLength; - int commandBufferMaxSize = minInt(k_maxScriptObjectNameSize, textLen + 1); + int commandBufferMaxSize = std::min(k_maxScriptObjectNameSize, textLen + 1); char commandBuffer[k_maxScriptObjectNameSize]; Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLen, commandBuffer, commandBufferMaxSize, true); sender()->handleEventWithText(commandBuffer); From 43d0ab5ea7b4049ddd340511066375d9e09dcae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 15:20:31 +0200 Subject: [PATCH 261/453] [apps] Rename displayEmptyController -> displayEmptyControllerIfNeeded --- apps/alternate_empty_nested_menu_controller.cpp | 2 +- apps/alternate_empty_nested_menu_controller.h | 2 +- apps/code/variable_box_controller.cpp | 2 +- apps/math_variable_box_controller.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/alternate_empty_nested_menu_controller.cpp b/apps/alternate_empty_nested_menu_controller.cpp index b09acca75..d3a89f0f9 100644 --- a/apps/alternate_empty_nested_menu_controller.cpp +++ b/apps/alternate_empty_nested_menu_controller.cpp @@ -7,7 +7,7 @@ void AlternateEmptyNestedMenuController::viewDidDisappear() { NestedMenuController::viewDidDisappear(); } -bool AlternateEmptyNestedMenuController::displayEmptyController() { +bool AlternateEmptyNestedMenuController::displayEmptyControllerIfNeeded() { assert(!isDisplayingEmptyController()); // If the content is empty, we push an empty controller. if (numberOfRows() == 0) { diff --git a/apps/alternate_empty_nested_menu_controller.h b/apps/alternate_empty_nested_menu_controller.h index 0427a2bf8..3397cf66d 100644 --- a/apps/alternate_empty_nested_menu_controller.h +++ b/apps/alternate_empty_nested_menu_controller.h @@ -13,7 +13,7 @@ public: protected: virtual ViewController * emptyViewController() = 0; virtual bool isDisplayingEmptyController() = 0; - bool displayEmptyController(); + bool displayEmptyControllerIfNeeded(); }; #endif diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index ec31fbae1..ff296d6a7 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -62,7 +62,7 @@ void VariableBoxController::didEnterResponderChain(Responder * previousFirstResp * when leaving the VariableBoxController, so we do not lose the environment * that was loaded when entering the VariableBoxController. */ assert(App::app()->pythonIsInited()); - displayEmptyController(); + displayEmptyControllerIfNeeded(); } KDCoordinate VariableBoxController::rowHeight(int j) { diff --git a/apps/math_variable_box_controller.cpp b/apps/math_variable_box_controller.cpp index 7eb72b39e..1d6c968ce 100644 --- a/apps/math_variable_box_controller.cpp +++ b/apps/math_variable_box_controller.cpp @@ -62,7 +62,7 @@ bool MathVariableBoxController::handleEvent(Ion::Events::Event event) { int newSelectedRow = rowIndex >= numberOfRows() ? numberOfRows()-1 : rowIndex; selectCellAtLocation(selectedColumn(), newSelectedRow); m_selectableTableView.reloadData(); - displayEmptyController(); + displayEmptyControllerIfNeeded(); return true; } return AlternateEmptyNestedMenuController::handleEvent(event); @@ -160,7 +160,7 @@ bool MathVariableBoxController::selectSubMenu(int selectedRow) { m_selectableTableView.deselectTable(); setPage(pageAtIndex(selectedRow)); bool selectSubMenu = AlternateEmptyNestedMenuController::selectSubMenu(selectedRow); - if (displayEmptyController()) { + if (displayEmptyControllerIfNeeded()) { return true; } return selectSubMenu; From c5f2f7cf839650ee9a47b7e3d452ec6b10cd1f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 15:22:31 +0200 Subject: [PATCH 262/453] [apps/code] Remove TODO comments --- apps/code/variable_box_controller.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index ff296d6a7..9e658366c 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -70,8 +70,8 @@ KDCoordinate VariableBoxController::rowHeight(int j) { int cumulatedOriginsCount = 0; int cellType = typeAndOriginAtLocation(j, &cellOrigin, &cumulatedOriginsCount); if (cellType == k_itemCellType) { - //TODO LEA if cellOrigin == Imported? if (scriptNodeAtIndex(j - cumulatedOriginsCount)->description() != nullptr) { + // If there is a node description, the cell is bigger return ScriptNodeCell::k_complexItemHeight; } return ScriptNodeCell::k_simpleItemHeight; @@ -236,7 +236,7 @@ void VariableBoxController::loadVariablesImportedFromScripts() { for (int i = 0; i < scriptsCount; i++) { Script script = m_scriptStore->scriptAtIndex(i); if (script.contentFetchedFromConsole()) { - loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.content(), nullptr, -1, false); // TODO optimize number of script fetches + loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.content(), nullptr, -1, false); } } } @@ -250,7 +250,6 @@ void VariableBoxController::empty() { // PRIVATE METHODS int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith) { - // TODO LEA compare until parenthesis assert(strictlyStartsWith == nullptr || *strictlyStartsWith == false); assert(nameLength > 0); const char * nodeName = node->name(); @@ -383,8 +382,9 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength } void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { - //TODO LEA could be great to use strings defined in STATIC const char *const tok_kw[] from python/lexer.c - //TODO LEA Prune these (check all are usable in our Python, but just comment those which aren't -> there might become usable later) + //TODO Could be great to use strings defined in STATIC const char *const tok_kw[] in python/lexer.c + /* The commented values do not work with our current MicroPython but might + * work later, which is chy we keep them. */ static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { {"False", ScriptNode::Type::WithoutParentheses}, {"None", ScriptNode::Type::WithoutParentheses}, @@ -529,7 +529,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in } } -/*TODO LEA very dirty +/* WARNING: This is very dirty. * This is done to get the lexer position during lexing. As the _mp_reader_mem_t * struct is private and declared in python/src/py/reader.c, we copy-paste it * here to be able to use it. */ @@ -542,7 +542,7 @@ typedef struct _mp_reader_mem_t { void VariableBoxController::loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) { /* Load the imported variables and functions: lex and the parse on a line per - * line basis untils parsing fails, while detecting import structures. */ + * line basis until parsing fails, while detecting import structures. */ nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { const char * parseStart = scriptContent; @@ -550,7 +550,6 @@ void VariableBoxController::loadImportedVariablesInScript(const char * scriptCon while (*parseStart == '\n' && *parseStart != 0) { parseStart++; } - //TODO LEA also look for ";" ? But what if in string? const char * parseEnd = UTF8Helper::CodePointSearch(parseStart, '\n'); while (parseStart != parseEnd) { @@ -612,7 +611,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont /* This is a trick to get the token position in the text, as name and * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. - * The -2 was found from stepping in the code and trying. */ + * This was found from stepping in the code and trying. */ // TODO LEA FIXME for (int i = 0; i < 3; i++) { if (strncmp(tokenInText, name, nameLength) != 0) { @@ -723,9 +722,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par /* If a module and a script have the same name, the micropython * importation algorithm first looks for a module then for a script. We * should thus check that the id is not a module name before retreiving - * a script name to put it as source. - * TODO Should importationSourceIsModule be called in - * importationSourceIsScript?*/ + * a script name to put it as source. */ if (!importationSourceIsScript(id, &sourceId) && !importFromModules) { // Warning : must be done in this order /* We call importationSourceIsScript to load the script name in * sourceId. We also use it to make sure, if importFromModules is @@ -767,7 +764,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); } } else { - //TODO LEA get module variables + //TODO LEA get module variables that are not in the toolbox } } else { // Try fetching the nodes from a script @@ -796,7 +793,6 @@ const char * VariableBoxController::importationSourceNameFromNode(mp_parse_node_ } /* The importation source is "complex", for instance: * from matplotlib.pyplot import * - * TODO LEA * FIXME The solution would be to build a single qstr for this name, * such as in python/src/compile.c, function do_import_name, from line * 1117 (found by searching PN_dotted_name). From 68867e45e7e7d63c6a464d968e145b4903f38e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 16:26:36 +0200 Subject: [PATCH 263/453] [apps] Factorize isDisplayingEmptyController Because we can now, it might need to be de-factorized later, if more classes inherit from alternate_empty_nested_menu_controller --- apps/alternate_empty_nested_menu_controller.h | 2 +- apps/code/variable_box_controller.h | 1 - apps/math_variable_box_controller.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/alternate_empty_nested_menu_controller.h b/apps/alternate_empty_nested_menu_controller.h index 3397cf66d..d310b15b6 100644 --- a/apps/alternate_empty_nested_menu_controller.h +++ b/apps/alternate_empty_nested_menu_controller.h @@ -12,7 +12,7 @@ public: void viewDidDisappear() override; protected: virtual ViewController * emptyViewController() = 0; - virtual bool isDisplayingEmptyController() = 0; + bool isDisplayingEmptyController() { return StackViewController::depth() == 2; } bool displayEmptyControllerIfNeeded(); }; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 0537c7f62..18a2bf4ca 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -32,7 +32,6 @@ public: //AlternateEmptyNestedMenuController ViewController * emptyViewController() override { return &m_variableBoxEmptyController; } - bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } //TODO LEA factorize with math toolbox /* VariableBoxController */ void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); diff --git a/apps/math_variable_box_controller.h b/apps/math_variable_box_controller.h index 25bb29703..8e6052a11 100644 --- a/apps/math_variable_box_controller.h +++ b/apps/math_variable_box_controller.h @@ -47,7 +47,6 @@ private: const char * extension() const; Ion::Storage::Record recordAtIndex(int rowIndex); ViewController * emptyViewController() override; - bool isDisplayingEmptyController() override { return StackViewController::depth() == 2; } void resetMemoization(); void destroyRecordAtRowIndex(int rowIndex); Page m_currentPage; From 714410287ab09202bdb47ddaea26cca2bb00a88e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 16:28:05 +0200 Subject: [PATCH 264/453] [apps/code] Remove TODOs --- apps/code/console_controller.cpp | 18 +++++------------- apps/code/variable_box_controller.cpp | 1 + apps/code/variable_box_controller.h | 1 - 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 04cdc79c4..1ee087939 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -47,20 +47,12 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe } bool ConsoleController::loadPythonEnvironment() { - if (m_pythonDelegate->isPythonUser(this)) { - return true; + if (!m_pythonDelegate->isPythonUser(this)) { + emptyOutputAccumulationBuffer(); + m_pythonDelegate->initPythonWithUser(this); + MicroPython::registerScriptProvider(m_scriptStore); + m_importScriptsWhenViewAppears = m_autoImportScripts; } - emptyOutputAccumulationBuffer(); - m_pythonDelegate->initPythonWithUser(this); - MicroPython::registerScriptProvider(m_scriptStore); - m_importScriptsWhenViewAppears = m_autoImportScripts; -#if 0 - //TODO LEA - /* We load functions and variables names in the variable box before running - * any other python code to avoid failling to load functions and variables - * due to memory exhaustion. */ - App::app()->variableBoxController()->loadFunctionsAndVariables(-1, nullptr, -1); -#endif return true; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 9e658366c..8bf260cf2 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -375,6 +375,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { void VariableBoxController::insertTextInCaller(const char * text, int textLength) { int textLen = textLength < 0 ? strlen(text) : textLength; + constexpr int k_maxScriptObjectNameSize = 100; // Ad hoc value int commandBufferMaxSize = std::min(k_maxScriptObjectNameSize, textLen + 1); char commandBuffer[k_maxScriptObjectNameSize]; Shared::ToolboxHelpers::TextToInsertForCommandText(text, textLen, commandBuffer, commandBufferMaxSize, true); diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 18a2bf4ca..3b6d44822 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -42,7 +42,6 @@ public: private: //TODO LEA use size_t - constexpr static int k_maxScriptObjectNameSize = 100; //TODO LEA constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 107; From 7ef17960c83adebf3aaf6435226c1ffd57903c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 16:32:42 +0200 Subject: [PATCH 265/453] [apps/code/variable_box_controller] More TODOs removal --- apps/code/variable_box_controller.cpp | 2 +- apps/code/variable_box_controller.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8bf260cf2..eb78d6681 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -106,7 +106,7 @@ int VariableBoxController::reusableCellCount(int type) { return k_scriptOriginsCount; } assert(type == k_itemCellType); - return k_maxNumberOfDisplayedRows; + return k_maxNumberOfDisplayedItems; } void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) { diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 3b6d44822..31f1dd6ff 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -42,7 +42,7 @@ public: private: //TODO LEA use size_t - constexpr static int k_maxNumberOfDisplayedRows = 8; // (240 - titlebar - margin)/27 //TODO LEA + constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom constexpr static int k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 107; constexpr static uint8_t k_scriptOriginsCount = 3; @@ -105,7 +105,7 @@ private: ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; ScriptNode m_importedNodes[k_maxScriptNodesCount]; - ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedRows]; + ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedItems]; MessageTableCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; // TODO LEA Put these in an array? From 0dac6b5bacb6ef76c3fd3333083396b572349ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 16:54:39 +0200 Subject: [PATCH 266/453] [apps/code] Replace int with size_t --- apps/code/variable_box_controller.cpp | 35 +++++++++++++++------------ apps/code/variable_box_controller.h | 13 +++++----- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index eb78d6681..eed3de696 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -271,12 +271,12 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { if (origin == NodeOrigin::Builtins) { - return m_builtinNodesCount; + return static_cast(m_builtinNodesCount); } - return *(const_cast(this)->nodesCountPointerForOrigin(origin)); + return static_cast(*(const_cast(this)->nodesCountPointerForOrigin(origin))); } -int * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { +size_t * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { if (origin == NodeOrigin::CurrentScript) { return &m_currentScriptNodesCount; } @@ -935,7 +935,7 @@ bool VariableBoxController::contains(const char * name, int nameLength) { void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName, const char * description) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - int * currentNodeCount = nodesCountPointerForOrigin(origin); + size_t * currentNodeCount = nodesCountPointerForOrigin(origin); if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { // There is no room to add another node return; @@ -943,21 +943,24 @@ void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, co /* We want to insert the node in alphabetical order, so we look for the * insertion index. */ ScriptNode * nodes = nodesForOrigin(origin); - int insertionIndex = 0; - while (insertionIndex < *currentNodeCount) { - ScriptNode * node = nodes + insertionIndex; - int nameComparison = NodeNameCompare(node, name, nameLength); - assert(nameComparison != 0); // We already checked that the name is not present already - if (nameComparison > 0) { - break; + size_t insertionIndex = 0; + if (*currentNodeCount != 0) { + while (insertionIndex < *currentNodeCount) { + ScriptNode * node = nodes + insertionIndex; + int nameComparison = NodeNameCompare(node, name, nameLength); + assert(nameComparison != 0); // We already checked that the name is not present already + if (nameComparison > 0) { + break; + } + insertionIndex++; + } + + // Shift all the following nodes + for (size_t i = *currentNodeCount; i > insertionIndex; i--) { + nodes[i] = nodes[i - 1]; } - insertionIndex++; } - // Shift all the following nodes - for (int i = *currentNodeCount - 1; i >= insertionIndex; i--) { - nodes[i+1] = nodes[i]; - } // Check if the node source name fits, if not, do not use it if (!ScriptNodeCell::CanDisplayNameAndSource(nameLength, nodeSourceName)) { nodeSourceName = nullptr; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 31f1dd6ff..201d26268 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -41,9 +41,8 @@ public: void empty(); private: - //TODO LEA use size_t constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom - constexpr static int k_maxScriptNodesCount = 32; //TODO LEA + constexpr static size_t k_maxScriptNodesCount = 32; //TODO LEA constexpr static int k_totalBuiltinNodesCount = 107; constexpr static uint8_t k_scriptOriginsCount = 3; constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable @@ -66,12 +65,12 @@ private: static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith = nullptr); // Nodes and nodes count - static int MaxNodesCountForOrigin(NodeOrigin origin) { + static size_t MaxNodesCountForOrigin(NodeOrigin origin) { assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); return k_maxScriptNodesCount; } int nodesCountForOrigin(NodeOrigin origin) const; - int * nodesCountPointerForOrigin(NodeOrigin origin); + size_t * nodesCountPointerForOrigin(NodeOrigin origin); ScriptNode * nodesForOrigin(NodeOrigin origin); ScriptNode * scriptNodeAtIndex(int index); @@ -109,9 +108,9 @@ private: MessageTableCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; // TODO LEA Put these in an array? - int m_currentScriptNodesCount; - int m_builtinNodesCount; - int m_importedNodesCount; + size_t m_currentScriptNodesCount; + size_t m_builtinNodesCount; + size_t m_importedNodesCount; int m_shortenResultCharCount; // This is used to send only the completing text when we are autocompleting }; From 8142e1d344fb8754692119d6e2861aacd84751d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 17:10:07 +0200 Subject: [PATCH 267/453] [apps/code] Remove TODO comment --- apps/code/variable_box_controller.h | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 201d26268..697bd1a5c 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -107,7 +107,6 @@ private: ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedItems]; MessageTableCell m_subtitleCells[k_scriptOriginsCount]; ScriptStore * m_scriptStore; - // TODO LEA Put these in an array? size_t m_currentScriptNodesCount; size_t m_builtinNodesCount; size_t m_importedNodesCount; From e4aac3f9c60e07bceffc10cdf044efc3cca7af59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 30 Apr 2020 17:14:12 +0200 Subject: [PATCH 268/453] [apps/code] Remove more TODOs --- apps/code/python_text_area.cpp | 3 --- apps/code/script_node.h | 4 ++-- apps/code/script_node_cell.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 6d9074aa5..b165f0101 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -296,7 +296,6 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { } else if(event == Ion::Events::Up || event == Ion::Events::Down) { - //TODO LEA handle only one suggestion in var box. cycleAutocompletion(event == Ion::Events::Down); return true; } else { @@ -343,9 +342,7 @@ void PythonTextArea::removeAutocompletionText() { const char * autocompleteStart = m_contentView.cursorLocation(); const char * autocompleteEnd = m_contentView.autocompletionEnd(); assert(autocompleteEnd != nullptr && autocompleteEnd > autocompleteStart); - //TODO LEA if (autocompleteEnd > autocompleteStart) { m_contentView.removeText(autocompleteStart, autocompleteEnd); - //TODO LEA } } void PythonTextArea::addAutocompletion() { diff --git a/apps/code/script_node.h b/apps/code/script_node.h index 695d7ae9b..6f2bd49f0 100644 --- a/apps/code/script_node.h +++ b/apps/code/script_node.h @@ -21,7 +21,7 @@ public: {} Type type() const { return m_type; } const char * name() const { return m_name; } - int nameLength() const { return m_nameLength; } + int nameLength() const { return static_cast(m_nameLength); } const char * nodeSourceName() const { return m_nodeSourceName; } const char * description() const { return m_description; } private: @@ -29,7 +29,7 @@ private: const char * m_name; const char * m_nodeSourceName; const char * m_description; - int m_nameLength; // TODO LEA smaller type ? + size_t m_nameLength; }; } diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp index e0b42b68e..6ea546596 100644 --- a/apps/code/script_node_cell.cpp +++ b/apps/code/script_node_cell.cpp @@ -28,7 +28,7 @@ void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) cons } /* If it exists, draw the source name. If it did not fit, we would have put - * nullptr at the node creation. TODO LEA */ + * nullptr at the node creation. */ const char * sourceName = m_scriptNode->nodeSourceName(); if (sourceName != nullptr) { KDSize sourceNameSize = k_font->stringSize(sourceName); From c915eb0b271437365bd885f753ad472309e14f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 4 May 2020 14:28:49 +0200 Subject: [PATCH 269/453] [apps/code] Do not autocomplete with arguments Eg : arr|ow(x,y,dx,dy) should give arrow(|,,,) --- apps/code/python_text_area.cpp | 19 +++++++++++++----- apps/code/variable_box_controller.cpp | 29 ++++++++++++++++----------- apps/code/variable_box_controller.h | 1 + 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index b165f0101..dff91f6f3 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -356,7 +356,7 @@ void PythonTextArea::addAutocompletion() { // First load variables and functions that complete the textToAutocomplete const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex(); - m_contentView.pythonDelegate()->variableBoxController()->loadFunctionsAndVariables(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning); + m_contentView.pythonDelegate()->variableBoxController()->loadFunctionsAndVariables(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning); if (addAutocompletionTextAtIndex(0)) { m_contentView.setAutocompleting(true); @@ -403,12 +403,21 @@ void PythonTextArea::cycleAutocompletion(bool downwards) { void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) { assert(m_contentView.isAutocompleting()); - const char * autocompEnd = m_contentView.autocompletionEnd(); - m_contentView.setAutocompleting(false); - m_contentView.setAutocompletionEnd(nullptr); + + // Save the cursor location + const char * previousCursorLocation = cursorLocation(); + + removeAutocompletion(); + + m_contentView.pythonDelegate()->variableBoxController()->setSender(this); + m_contentView.pythonDelegate()->variableBoxController()->insertAutocompletionResultAtIndex(m_autocompletionResultIndex); + + /* Add the autocompletion if we moved the cursor. If we did not want to move + * the cursor, restore its position. */ if (moveCursorToEndOfAutocompletion) { - setCursorLocation(autocompEnd); addAutocompletion(); + } else { + setCursorLocation(previousCursorLocation); } } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index eed3de696..68b53e5e9 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -247,6 +247,22 @@ void VariableBoxController::empty() { m_importedNodesCount = 0; } +void VariableBoxController::insertAutocompletionResultAtIndex(int index) { + ScriptNode * selectedScriptNode = scriptNodeAtIndex(index); + + /* We need to check now if we need to add parentheses: insertTextInCaller + * calls handleEventWithText, which will reload the autocompletion for the + * added text, which will probably change the script nodes and + * selectedScriptNode will become invalid. */ + const bool shouldAddParentheses = selectedScriptNode->type() == ScriptNode::Type::WithParentheses; + insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); + // WARNING: selectedScriptNode is now invalid + + if (shouldAddParentheses) { + insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); + } +} + // PRIVATE METHODS int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith) { @@ -355,19 +371,8 @@ bool VariableBoxController::selectLeaf(int rowIndex) { int cellType = typeAndOriginAtLocation(rowIndex, nullptr, &cumulatedOriginsCount); assert(cellType == k_itemCellType); (void)cellType; // Silence warnings - ScriptNode * selectedScriptNode = scriptNodeAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index - /* We need to check now if we need to add parentheses: insertTextInCaller - * calls handleEventWithText, which will reload the autocompletion for the - * added text, which will probably chande the script nodes and - * selectedScriptNode will become invalid. */ - const bool shouldAddParentheses = selectedScriptNode->type() == ScriptNode::Type::WithParentheses; - insertTextInCaller(selectedScriptNode->name() + m_shortenResultCharCount, selectedScriptNode->nameLength() - m_shortenResultCharCount); - // WARNING: selectedScriptNode is now invalid - - if (shouldAddParentheses) { - insertTextInCaller(ScriptNodeCell::k_parenthesesWithEmpty); - } + insertAutocompletionResultAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index Container::activeApp()->dismissModalViewController(); return true; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 697bd1a5c..a6780b85a 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -39,6 +39,7 @@ public: const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr); void loadVariablesImportedFromScripts(); void empty(); + void insertAutocompletionResultAtIndex(int index); private: constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom From b070eaad45cd7a153af7009d7cade283aca0d3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 5 May 2020 16:56:43 +0200 Subject: [PATCH 270/453] [apps/code] Remove double call to addAutocompletion --- apps/code/python_text_area.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index dff91f6f3..821895b2b 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -412,11 +412,10 @@ void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) m_contentView.pythonDelegate()->variableBoxController()->setSender(this); m_contentView.pythonDelegate()->variableBoxController()->insertAutocompletionResultAtIndex(m_autocompletionResultIndex); - /* Add the autocompletion if we moved the cursor. If we did not want to move - * the cursor, restore its position. */ - if (moveCursorToEndOfAutocompletion) { - addAutocompletion(); - } else { + // insertAutocompletionResultAtIndex already added the autocompletion + + // If we did not want to move the cursor, restore its position. + if (!moveCursorToEndOfAutocompletion) { setCursorLocation(previousCursorLocation); } } From 780c593c26f2a104e421c440a130f796dd67c2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 5 May 2020 17:26:00 +0200 Subject: [PATCH 271/453] [apps/code] Autocompletion for "abs" proposes parentheses --- apps/code/python_text_area.cpp | 36 ++++++++++++++++----------- apps/code/variable_box_controller.cpp | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 821895b2b..0ce5009ef 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -375,24 +375,30 @@ bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIn bool addParentheses = false; const char * textToInsert = varBox->autocompletionAlternativeAtIndex(autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses, nextIndex, currentIndexToUpdate); - // Try to insert the text (this might fail if the buffer is full) - if (textToInsert != nullptr - && textToInsertLength > 0 - && m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) - { + if (textToInsert == nullptr) { + return false; + } + + if (textToInsertLength > 0) { + // Try to insert the text (this might fail if the buffer is full) + if (!m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) { + return false; + } autocompletionLocation += textToInsertLength; m_contentView.setAutocompletionEnd(autocompletionLocation); - // Try to insert the parentheses if needed text - const char * parentheses = ScriptNodeCell::k_parentheses; - constexpr int parenthesesLength = 2; - assert(strlen(parentheses) == parenthesesLength); - if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) { - m_contentView.setAutocompleting(true); - m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); - } - return true; } - return false; + + // Try to insert the parentheses if needed + const char * parentheses = ScriptNodeCell::k_parentheses; + constexpr int parenthesesLength = 2; + assert(strlen(parentheses) == parenthesesLength); + /* If couldInsertText is false, we should not try to add the parentheses as + * there was already not enough space to add the autocompletion. */ + if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) { + m_contentView.setAutocompleting(true); + m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength); + } + return true; } void PythonTextArea::cycleAutocompletion(bool downwards) { diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 68b53e5e9..5f24c98a5 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -522,7 +522,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in bool strictlyStartsWith = false; startsWith = NodeNameCompare(&node, textToAutocomplete, textToAutocompleteLength, &strictlyStartsWith); if (startsWith == 0) { // The node name and name are equal - startsWith = builtinNames[i].type == ScriptNode::Type::WithParentheses ? 0 : -1; // We accept the node only if it has parentheses + startsWith = node.type() == ScriptNode::Type::WithParentheses ? 0 : -1; // We accept the node only if it has parentheses } else if (strictlyStartsWith) { startsWith = 0; } else if (startsWith > 0) { From f763bb50ac9e68dc3f809275d37889cb06f4da30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 6 May 2020 11:15:55 +0200 Subject: [PATCH 272/453] [apps/code] Do not display subtitles in var box from console --- apps/code/console_controller.cpp | 3 ++- apps/code/editor_controller.cpp | 1 + apps/code/variable_box_controller.cpp | 20 +++++++++++++------- apps/code/variable_box_controller.h | 2 ++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 1ee087939..0a90ef9d2 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -372,8 +372,9 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { VariableBoxController * ConsoleController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * varBox = App::app()->variableBoxController(); - varBox->setTitle(I18n::Message::FunctionsAndVariables); varBox->loadVariablesImportedFromScripts(); + varBox->setTitle(I18n::Message::FunctionsAndVariables); + varBox->setDisplaySubtitles(false); return varBox; } diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 8ffb0f4c6..2c003df88 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -141,6 +141,7 @@ VariableBoxController * EditorController::variableBoxForInputEventHandler(InputE varBox->loadFunctionsAndVariables(m_scriptIndex, beginningOfAutocompletion, cursor - beginningOfAutocompletion); } varBox->setTitle(I18n::Message::Autocomplete); + varBox->setDisplaySubtitles(true); return varBox; } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 5f24c98a5..5e650112b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -70,12 +70,13 @@ KDCoordinate VariableBoxController::rowHeight(int j) { int cumulatedOriginsCount = 0; int cellType = typeAndOriginAtLocation(j, &cellOrigin, &cumulatedOriginsCount); if (cellType == k_itemCellType) { - if (scriptNodeAtIndex(j - cumulatedOriginsCount)->description() != nullptr) { + if (scriptNodeAtIndex(j - (m_displaySubtitles ? cumulatedOriginsCount : 0))->description() != nullptr) { // If there is a node description, the cell is bigger return ScriptNodeCell::k_complexItemHeight; } return ScriptNodeCell::k_simpleItemHeight; } + assert(m_displaySubtitles); assert(cellType == k_subtitleCellType); return k_subtitleRowHeight; } @@ -86,7 +87,7 @@ int VariableBoxController::numberOfRows() const { for (NodeOrigin origin : origins) { int nodeCount = nodesCountForOrigin(origin); if (nodeCount > 0) { - result += nodeCount + 1; // 1 for the subtitle cell + result += nodeCount + (m_displaySubtitles ? 1 : 0); } } return result; @@ -97,12 +98,14 @@ HighlightCell * VariableBoxController::reusableCell(int index, int type) { if (type == k_itemCellType) { return m_itemCells + index; } + assert(m_displaySubtitles); assert(type == k_subtitleCellType); return m_subtitleCells + index; } int VariableBoxController::reusableCellCount(int type) { if (type == k_subtitleCellType) { + assert(m_displaySubtitles); return k_scriptOriginsCount; } assert(type == k_itemCellType); @@ -115,9 +118,10 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in int cumulatedOriginsCount = 0; int cellType = typeAndOriginAtLocation(index, &cellOrigin, &cumulatedOriginsCount); if (cellType == k_itemCellType) { - static_cast(cell)->setScriptNode(scriptNodeAtIndex(index - cumulatedOriginsCount)); // Remove the number of subtitle cells from the index + static_cast(cell)->setScriptNode(scriptNodeAtIndex(index - (m_displaySubtitles ? cumulatedOriginsCount : 0))); return; } + assert(m_displaySubtitles); assert(cellType == k_subtitleCellType); I18n::Message subtitleMessages[k_scriptOriginsCount] = { I18n::Message::ScriptInProgress, @@ -128,9 +132,10 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in } void VariableBoxController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { - if (withinTemporarySelection) { + if (withinTemporarySelection || !m_displaySubtitles) { return; } + // Make sure subtitle cells cannot be selected const int currentSelectedRow = selectedRow(); if (currentSelectedRow >= 0 && typeAtLocation(0, currentSelectedRow) == k_subtitleCellType) { if (currentSelectedRow == 0) { @@ -339,10 +344,10 @@ int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOri if (nodeCount > 0) { originsCount++; int result = -1; - if (i == cellIndex) { + if (m_displaySubtitles && i == cellIndex) { result = k_subtitleCellType; } else { - cellIndex += nodeCount + 1; // 1 for the subtitle cell + cellIndex += nodeCount + (m_displaySubtitles ? 1 : 0); if (i < cellIndex) { result = k_itemCellType; } @@ -354,6 +359,7 @@ int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOri if (cumulatedOriginsCount != nullptr) { *cumulatedOriginsCount = originsCount; } + assert(result != k_subtitleCellType || m_displaySubtitles); return result; } } @@ -372,7 +378,7 @@ bool VariableBoxController::selectLeaf(int rowIndex) { assert(cellType == k_itemCellType); (void)cellType; // Silence warnings - insertAutocompletionResultAtIndex(rowIndex - cumulatedOriginsCount); // Remove the number of subtitle cells from the index + insertAutocompletionResultAtIndex(rowIndex - (m_displaySubtitles ? cumulatedOriginsCount : 0)); Container::activeApp()->dismissModalViewController(); return true; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index a6780b85a..da00ba389 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -34,6 +34,7 @@ public: ViewController * emptyViewController() override { return &m_variableBoxEmptyController; } /* VariableBoxController */ + void setDisplaySubtitles(bool display) { m_displaySubtitles = display; } void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses); const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr); @@ -112,6 +113,7 @@ private: size_t m_builtinNodesCount; size_t m_importedNodesCount; int m_shortenResultCharCount; // This is used to send only the completing text when we are autocompleting + bool m_displaySubtitles; }; } From a53edf52022cda65d863614a8659e767cb0125e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 6 May 2020 11:34:05 +0200 Subject: [PATCH 273/453] [apps/code] Remove TODOs --- apps/code/variable_box_controller.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 5e650112b..d99e7aa9c 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -624,7 +624,6 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. * This was found from stepping in the code and trying. */ - // TODO LEA FIXME for (int i = 0; i < 3; i++) { if (strncmp(tokenInText, name, nameLength) != 0) { tokenInText--; @@ -773,10 +772,10 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par assert(numberOfModuleChildren > numberOfNodesToSkip); for (int i = numberOfNodesToSkip; i < numberOfModuleChildren; i++) { const char * name = I18n::translate((moduleChildren + i)->label()); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()) /*TODO LEA text or label?*/); + checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text())); } } else { - //TODO LEA get module variables that are not in the toolbox + //TODO get module variables that are not in the toolbox } } else { // Try fetching the nodes from a script @@ -921,7 +920,7 @@ bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int t bool VariableBoxController::contains(const char * name, int nameLength) { assert(nameLength > 0); bool alreadyInVarBox = false; - // TODO LEA speed this up with dichotomia? + // This could be faster with dichotomia, but there is no speed problem for now NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; for (NodeOrigin origin : origins) { const int nodesCount = nodesCountForOrigin(origin); From 0b88bb076774f5aab0a7c1fb574cc9dcbc118cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 7 May 2020 14:55:36 +0200 Subject: [PATCH 274/453] [apps/code] Reset m_autocompletionResultIndex when addingAutocompletion --- apps/code/python_text_area.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 0ce5009ef..7af7ddfe8 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -349,6 +349,7 @@ void PythonTextArea::addAutocompletion() { assert(!m_contentView.isAutocompleting()); const char * autocompletionTokenBeginning = nullptr; const char * autocompletionLocation = const_cast(cursorLocation()); + m_autocompletionResultIndex = 0; if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) != AutocompletionType::EndOfIdentifier) { // The cursor is not at the end of an identifier. return; From 67b1c12bf7e60f55ab98848b70f6f99ecd409921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 30 Apr 2020 18:21:08 +0200 Subject: [PATCH 275/453] [poincare] Remove useless variables --- poincare/include/poincare/unit.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index be7c14910..8c7f8c64e 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -773,9 +773,6 @@ public: static void ChooseBestRepresentativeAndPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, true, reductionContext); } static void ChooseBestPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, false, reductionContext); } - static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; - static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; - static constexpr double JouleToWatthourFactor = 1.0/3600.0; private: UnitNode * node() const { return static_cast(Expression::node()); } static void ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); From 3b7d7e789867c120455f3a67b625a35aadd0aa86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 6 May 2020 12:10:30 +0200 Subject: [PATCH 276/453] [poincare] Clean magic numbers in Unit --- poincare/include/poincare/unit.h | 7 +++++++ poincare/src/unit.cpp | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 8c7f8c64e..84931a149 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -773,7 +773,14 @@ public: static void ChooseBestRepresentativeAndPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, true, reductionContext); } static void ChooseBestPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, false, reductionContext); } + // This could be computed from the time representatives but we save time by using constexpr double + static constexpr double SecondsPerMinute = 60.0; private: + static constexpr double MinutesPerHour = 60.0; + static constexpr double HoursPerDay = 24.0; + static constexpr double DaysPerYear = 365.25; + static constexpr double MonthPerYear = 12.0; + static constexpr double DaysPerMonth = DaysPerYear/MonthPerYear; UnitNode * node() const { return static_cast(Expression::node()); } static void ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); void chooseBestMultipleForValue(double * value, const int exponent, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 2aa75e81b..46302f3d3 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -452,8 +452,7 @@ Expression Unit::BuildTimeSplit(double seconds, Context * context, Preferences:: double remain = std::round(seconds*err)/err; constexpr static int numberOfTimeUnits = 6; - // This could be computed from the time representatives but we same time by using constexpr double - constexpr static double timeFactors[numberOfTimeUnits] = {365.25*24.0*60.0*60.0, 365.25/12.0*24.0*60.0*60.0, 24.0*60.0*60.0, 60.0*60.0, 60.0, 1.0 }; + constexpr static double timeFactors[numberOfTimeUnits] = {MonthPerYear*DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, HoursPerDay*MinutesPerHour*SecondsPerMinute, MinutesPerHour*SecondsPerMinute, SecondsPerMinute, 1.0 }; Unit units[numberOfTimeUnits] = {Unit::Year(), Unit::Month(), Unit::Day(), Unit::Hour(), Unit::Minute(), Unit::Second() }; double valuesPerUnit[numberOfTimeUnits]; Addition a = Addition::Builder(); From b6ee72bc214e8b1ed5ad69e78d754d707625e97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 6 May 2020 12:12:07 +0200 Subject: [PATCH 277/453] [poincare] Clean tests on Unit --- apps/calculation/calculation.cpp | 2 + poincare/test/expression.cpp | 63 ++++------------------ poincare/test/expression_properties.cpp | 43 ++++++++++++++- poincare/test/expression_serialization.cpp | 7 --- poincare/test/helper.cpp | 7 +++ poincare/test/helper.h | 3 ++ 6 files changed, 65 insertions(+), 60 deletions(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index abcafd696..b0e723eba 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -3,8 +3,10 @@ #include "../shared/scrollable_multiple_expressions_view.h" #include "../global_preferences.h" #include "../exam_mode_configuration.h" +#include "app.h" #include #include +#include #include #include #include diff --git a/poincare/test/expression.cpp b/poincare/test/expression.cpp index 10f81b9d9..bd1ae80fc 100644 --- a/poincare/test/expression.cpp +++ b/poincare/test/expression.cpp @@ -74,60 +74,19 @@ QUIZ_CASE(poincare_expression_rational_constructor) { assert_pool_size(initialPoolSize+6); } -void assert_seconds_split_to(double totalSeconds, const char * splittedTime, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { - Expression time = Unit::BuildTimeSplit(totalSeconds, context, complexFormat, angleUnit); - constexpr static int bufferSize = 100; - char buffer[bufferSize]; - time.serialize(buffer, bufferSize, DecimalMode); - quiz_assert_print_if_failure(strcmp(buffer, splittedTime) == 0, splittedTime); -} - QUIZ_CASE(poincare_expression_unit_constructor) { - Shared::GlobalContext globalContext; - ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); - // 1. Time - // 1.a. Test Unit::Second constructor - Unit s = Unit::Second(); - // 1.b. Test Unit::isSecond helper - quiz_assert(s.isSecond()); - quiz_assert(!s.isMeter()); - // 1.c. Test Unit::BuildTimeSplit constructor - assert_seconds_split_to(1234567890, "39×_year+1×_month+13×_day+19×_h+1×_min+30×_s", &globalContext, Cartesian, Degree); - assert_seconds_split_to(-122, "-2×_min-2×_s", &globalContext, Cartesian, Degree); + Unit u = Unit::Second(); + assert_expression_serialize_to(u, "_s"); - // 2. Speed - // 2.a. test Unit::Kilometer and Unit::Hour constructors - Expression kilometerPerHour = Multiplication::Builder( - Unit::Kilometer(), - Power::Builder( - Unit::Hour(), - Rational::Builder(-1) - ) - ); - kilometerPerHour = kilometerPerHour.reduce(reductionContext); - Expression meterPerSecond; - kilometerPerHour = kilometerPerHour.removeUnit(&meterPerSecond); - // 2.b. Test Unit::IsISSpeed helper - quiz_assert(Unit::IsISSpeed(meterPerSecond)); + u = Unit::Hour(); + assert_expression_serialize_to(u, "_h"); - // 3. Volume - // 3.a. test Unit::Liter constructor - Expression liter = Unit::Liter(); - liter = liter.reduce(reductionContext); - Expression meter3; - liter = liter.removeUnit(&meter3); - // 3.b. Test Unit::IsISVolume helper - quiz_assert(Unit::IsISVolume(meter3)); + u = Unit::Kilometer(); + assert_expression_serialize_to(u, "_km"); - // 4. Energy - // 4.a. test Unit::Watt and Unit::Hour constructors - Expression wattHour = Multiplication::Builder( - Unit::Watt(), - Unit::Hour() - ); - wattHour = wattHour.reduce(reductionContext); - Expression kilogramMeter2PerSecond2; - wattHour = wattHour.removeUnit(&kilogramMeter2PerSecond2); - // 4.b. Test Unit::IsISEnergy helper - quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); + u = Unit::Liter(); + assert_expression_serialize_to(u, "_L"); + + u = Unit::Watt(); + assert_expression_serialize_to(u, "_W"); } diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index ffb6f7229..03074eb3e 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -382,10 +382,51 @@ void assert_reduced_expression_unit_is(const char * expression, const char * uni quiz_assert_print_if_failure(u1.isUninitialized() == u2.isUninitialized() && (u1.isUninitialized() || u1.isIdenticalTo(u2)), expression); } -QUIZ_CASE(poincare_properties_get_unit) { +QUIZ_CASE(poincare_properties_remove_unit) { assert_reduced_expression_unit_is("_km", "_m"); assert_reduced_expression_unit_is("_min/_km", "_m^(-1)×_s"); assert_reduced_expression_unit_is("_km^3", "_m^3"); assert_reduced_expression_unit_is("1_m+_km", "_m"); assert_reduced_expression_unit_is("_L^2×3×_s", "_m^6×_s"); } + +void assert_seconds_split_to(double totalSeconds, const char * splittedTime, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { + Expression time = Unit::BuildTimeSplit(totalSeconds, context, complexFormat, angleUnit); + constexpr static int bufferSize = 100; + char buffer[bufferSize]; + time.serialize(buffer, bufferSize, DecimalMode); + quiz_assert_print_if_failure(strcmp(buffer, splittedTime) == 0, splittedTime); +} + +Expression extract_unit(const char * expression) { + Shared::GlobalContext globalContext; + ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); + Expression e = parse_expression(expression, &globalContext, false).reduce(reductionContext); + Expression unit; + e.removeUnit(&unit); + return unit; +} + +QUIZ_CASE(poincare_expression_unit_helper) { + // 1. Time + Expression s = extract_unit("_s"); + quiz_assert(s.type() == ExpressionNode::Type::Unit && static_cast(s).isSecond()); + quiz_assert(!static_cast(s).isMeter()); + + Shared::GlobalContext globalContext; + assert_seconds_split_to(1234567890, "39×_year+1×_month+13×_day+19×_h+1×_min+30×_s", &globalContext, Cartesian, Degree); + assert_seconds_split_to(-122, "-2×_min-2×_s", &globalContext, Cartesian, Degree); + + // 2. Speed + Expression meterPerSecond = extract_unit("_m×_s^-1"); + quiz_assert(Unit::IsISSpeed(meterPerSecond)); + + // 3. Volume + Expression meter3 = extract_unit("_m^3"); + quiz_assert(Unit::IsISVolume(meter3)); + + // 4. Energy + Expression kilogramMeter2PerSecond2 = extract_unit("_kg×_m^2×_s^-2"); + quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); +} + diff --git a/poincare/test/expression_serialization.cpp b/poincare/test/expression_serialization.cpp index 8972460e6..41eed110e 100644 --- a/poincare/test/expression_serialization.cpp +++ b/poincare/test/expression_serialization.cpp @@ -2,13 +2,6 @@ using namespace Poincare; -void assert_expression_serialize_to(Poincare::Expression expression, const char * serialization, Preferences::PrintFloatMode mode = ScientificMode, int numberOfSignificantDigits = 7) { - constexpr int bufferSize = 500; - char buffer[bufferSize]; - expression.serialize(buffer, bufferSize, mode, numberOfSignificantDigits); - quiz_assert_print_if_failure(strcmp(serialization, buffer) == 0, serialization); -} - QUIZ_CASE(poincare_serialization_based_integer) { assert_expression_serialize_to(BasedInteger::Builder(Integer(23), Integer::Base::Decimal), "23"); assert_expression_serialize_to(BasedInteger::Builder(Integer(23), Integer::Base::Binary), "0b10111"); diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index ba019ab4c..5d14942c1 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -127,6 +127,13 @@ void assert_expression_simplifies_approximates_to(const char * expression, const }, numberOfDigits); } +void assert_expression_serialize_to(Poincare::Expression expression, const char * serialization, Preferences::PrintFloatMode mode, int numberOfSignificantDigits) { + constexpr int bufferSize = 500; + char buffer[bufferSize]; + expression.serialize(buffer, bufferSize, mode, numberOfSignificantDigits); + quiz_assert_print_if_failure(strcmp(serialization, buffer) == 0, serialization); +} + void assert_layout_serialize_to(Poincare::Layout layout, const char * serialization) { constexpr int bufferSize = 255; char buffer[bufferSize]; diff --git a/poincare/test/helper.h b/poincare/test/helper.h index a6e069828..229ef4274 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -50,6 +50,9 @@ void assert_expression_simplifies_and_approximates_to(const char * expression, c template void assert_expression_simplifies_approximates_to(const char * expression, const char * approximation, Poincare::Preferences::AngleUnit angleUnit = Degree, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, int numberOfSignificantDigits = -1); +// Expression serializing + +void assert_expression_serialize_to(Poincare::Expression expression, const char * serialization, Poincare::Preferences::PrintFloatMode mode = ScientificMode, int numberOfSignificantDigits = 7); // Layout serializing From bcbdc9312eee4ff1d787194e7902fe73736b6e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 6 May 2020 12:13:04 +0200 Subject: [PATCH 278/453] [poincare] Fix Unit::isSecond, Unit::isMeter and Unit::isKilogram: the EmptyPrefix is not unique, we can't only compare pointers --- poincare/include/poincare/unit.h | 1 + poincare/src/unit.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 84931a149..689203e4a 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -38,6 +38,7 @@ public: m_symbol(symbol), m_exponent(exponent) {} + inline bool operator==(const Prefix& p) const { return m_exponent == p.m_exponent && strcmp(m_symbol, p.m_symbol) == 0; } const char * symbol() const { return m_symbol; } int8_t exponent() const { return m_exponent; } int serialize(char * buffer, int bufferSize) const; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 46302f3d3..8082cfef5 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -392,16 +392,16 @@ Expression Unit::removeUnit(Expression * unit) { } bool Unit::isSecond() const { - return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && node()->prefix() == &EmptyPrefix; + return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && *(node()->prefix()) == EmptyPrefix; } bool Unit::isMeter() const { - return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; + return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && *(node()->prefix()) == EmptyPrefix; } bool Unit::isKilogram() const { - return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; + return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && *(node()->prefix()) == KiloPrefix; } bool Unit::IsISSpeed(Expression & e) { From a48f65ba9506087a77f1769d881eea9ce095a474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 6 May 2020 14:37:37 +0200 Subject: [PATCH 279/453] [poincare] Unit: ensure one unique instance of each prefix --- poincare/include/poincare/unit.h | 116 +++++++++++++++---------------- poincare/src/unit.cpp | 27 +++---- poincare/test/parsing.cpp | 4 +- poincare/test/simplification.cpp | 3 +- 4 files changed, 76 insertions(+), 74 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 689203e4a..3be06ccf6 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -38,7 +38,6 @@ public: m_symbol(symbol), m_exponent(exponent) {} - inline bool operator==(const Prefix& p) const { return m_exponent == p.m_exponent && strcmp(m_symbol, p.m_symbol) == 0; } const char * symbol() const { return m_symbol; } int8_t exponent() const { return m_exponent; } int serialize(char * buffer, int bufferSize) const; @@ -57,19 +56,19 @@ public: Yes }; template - constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix (&outputPrefixes)[N]) : + constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix * const (&outputPrefixes)[N]) : m_rootSymbol(rootSymbol), m_definition(definition), m_prefixable(prefixable), m_outputPrefixes(outputPrefixes), - m_outputPrefixesUpperBound(outputPrefixes + N) + m_outputPrefixesLength(N) { } const char * rootSymbol() const { return m_rootSymbol; } const char * definition() const { return m_definition; } bool isPrefixable() const { return m_prefixable == Prefixable::Yes; } - const Prefix * outputPrefixes() const { return m_outputPrefixes; } - const Prefix * outputPrefixesUpperBound() const { return m_outputPrefixesUpperBound; } + const Prefix * const * outputPrefixes() const { return m_outputPrefixes; } + size_t outputPrefixesLength() const { return m_outputPrefixesLength; } bool canParse(const char * symbol, size_t length, const Prefix * * prefix) const; int serialize(char * buffer, int bufferSize, const Prefix * prefix) const; @@ -78,8 +77,8 @@ public: const char * m_rootSymbol; const char * m_definition; const Prefixable m_prefixable; - const Prefix * m_outputPrefixes; - const Prefix * m_outputPrefixesUpperBound; + const Prefix * const * m_outputPrefixes; + const size_t m_outputPrefixesLength; }; class Dimension { @@ -203,58 +202,57 @@ public: MegaPrefix = Prefix("M", 6), GigaPrefix = Prefix("G", 9), TeraPrefix = Prefix("T", 12); - static constexpr const Prefix - NoPrefix[] = { - EmptyPrefix - }, - NegativeLongScalePrefixes[] = { - PicoPrefix, - NanoPrefix, - MicroPrefix, - MilliPrefix, - EmptyPrefix, - }, - PositiveLongScalePrefixes[] = { - EmptyPrefix, - KiloPrefix, - MegaPrefix, - GigaPrefix, - TeraPrefix, - }, - LongScalePrefixes[] = { - PicoPrefix, - NanoPrefix, - MicroPrefix, - MilliPrefix, - EmptyPrefix, - KiloPrefix, - MegaPrefix, - GigaPrefix, - TeraPrefix, - }, - NegativePrefixes[] = { - PicoPrefix, - NanoPrefix, - MicroPrefix, - MilliPrefix, - CentiPrefix, - DeciPrefix, - EmptyPrefix, - }, - AllPrefixes[] = { - PicoPrefix, - NanoPrefix, - MicroPrefix, - MilliPrefix, - CentiPrefix, - DeciPrefix, - EmptyPrefix, - DecaPrefix, - HectoPrefix, - KiloPrefix, - MegaPrefix, - GigaPrefix, - TeraPrefix, + static constexpr const Prefix * NoPrefix[] = { + &EmptyPrefix + }; + static constexpr const Prefix * NegativeLongScalePrefixes[] = { + &PicoPrefix, + &NanoPrefix, + &MicroPrefix, + &MilliPrefix, + &EmptyPrefix, + }; + static constexpr const Prefix * PositiveLongScalePrefixes[] = { + &EmptyPrefix, + &KiloPrefix, + &MegaPrefix, + &GigaPrefix, + &TeraPrefix, + }; + static constexpr const Prefix * LongScalePrefixes[] = { + &PicoPrefix, + &NanoPrefix, + &MicroPrefix, + &MilliPrefix, + &EmptyPrefix, + &KiloPrefix, + &MegaPrefix, + &GigaPrefix, + &TeraPrefix, + }; + static constexpr const Prefix * NegativePrefixes[] = { + &PicoPrefix, + &NanoPrefix, + &MicroPrefix, + &MilliPrefix, + &CentiPrefix, + &DeciPrefix, + &EmptyPrefix, + }; + static constexpr const Prefix * AllPrefixes[] = { + &PicoPrefix, + &NanoPrefix, + &MicroPrefix, + &MilliPrefix, + &CentiPrefix, + &DeciPrefix, + &EmptyPrefix, + &DecaPrefix, + &HectoPrefix, + &KiloPrefix, + &MegaPrefix, + &GigaPrefix, + &TeraPrefix, }; static constexpr size_t NumberOfBaseUnits = UnitNode::NumberOfBaseUnits; static constexpr const Representative diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 8082cfef5..97b05093a 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -30,8 +30,9 @@ bool UnitNode::Representative::canParse(const char * symbol, size_t length, *prefix = &Unit::EmptyPrefix; return length == 0; } - const Prefix * pre = Unit::AllPrefixes; - while (pre < Unit::AllPrefixes + sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix)) { + size_t numberOfPrefixes = sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix *); + for (size_t i = 0; i < numberOfPrefixes; i++) { + const Prefix * pre = Unit::AllPrefixes[i]; const char * prefixSymbol = pre->symbol(); if (strncmp(symbol, prefixSymbol, length) == 0 && prefixSymbol[length] == 0) @@ -66,7 +67,8 @@ const UnitNode::Prefix * UnitNode::Representative::bestPrefixForValue(double & v * magnitude of 'value'. */ const int orderOfMagnitude = IEEE754::exponentBase10(std::fabs(value)); - for (const Prefix * pre = m_outputPrefixes; pre < m_outputPrefixesUpperBound; pre++) { + for (size_t i = 0; i < m_outputPrefixesLength; i++) { + const Prefix * pre = m_outputPrefixes[i]; unsigned int newDiff = absInt(orderOfMagnitude - pre->exponent() * exponent); if (newDiff < diff) { diff = newDiff; @@ -234,13 +236,12 @@ constexpr const Unit::Prefix Unit::MegaPrefix, Unit::GigaPrefix, Unit::TeraPrefix; -constexpr const Unit::Prefix - Unit::NoPrefix[], - Unit::NegativeLongScalePrefixes[], - Unit::PositiveLongScalePrefixes[], - Unit::LongScalePrefixes[], - Unit::NegativePrefixes[], - Unit::AllPrefixes[]; +constexpr const Unit::Prefix * const Unit::NoPrefix[]; +constexpr const Unit::Prefix * const Unit::NegativeLongScalePrefixes[]; +constexpr const Unit::Prefix * const Unit::PositiveLongScalePrefixes[]; +constexpr const Unit::Prefix * const Unit::LongScalePrefixes[]; +constexpr const Unit::Prefix * const Unit::NegativePrefixes[]; +constexpr const Unit::Prefix * const Unit::AllPrefixes[]; constexpr const Unit::Representative Unit::TimeRepresentatives[], Unit::DistanceRepresentatives[], @@ -392,16 +393,16 @@ Expression Unit::removeUnit(Expression * unit) { } bool Unit::isSecond() const { - return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && *(node()->prefix()) == EmptyPrefix; + return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && node()->prefix() == &EmptyPrefix; } bool Unit::isMeter() const { - return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && *(node()->prefix()) == EmptyPrefix; + return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; } bool Unit::isKilogram() const { - return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && *(node()->prefix()) == KiloPrefix; + return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; } bool Unit::IsISSpeed(Expression & e) { diff --git a/poincare/test/parsing.cpp b/poincare/test/parsing.cpp index 8ed79c0b8..4ee1a88e1 100644 --- a/poincare/test/parsing.cpp +++ b/poincare/test/parsing.cpp @@ -294,7 +294,9 @@ QUIZ_CASE(poincare_parsing_units) { Expression unit = parse_expression(buffer, nullptr, false); quiz_assert_print_if_failure(unit.type() == ExpressionNode::Type::Unit, "Should be parsed as a Unit"); if (rep->isPrefixable()) { - for (const Unit::Prefix * pre = Unit::AllPrefixes; pre < Unit::AllPrefixes + sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix); pre++) { + size_t numberOfPrefixes = sizeof(Unit::AllPrefixes)/sizeof(Unit::Prefix *); + for (size_t i = 0; i < numberOfPrefixes; i++) { + const Unit::Prefix * pre = Unit::AllPrefixes[i]; Unit::Builder(dim, rep, pre).serialize(buffer, bufferSize, Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits); Expression unit = parse_expression(buffer, nullptr, false); quiz_assert_print_if_failure(unit.type() == ExpressionNode::Type::Unit, "Should be parsed as a Unit"); diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index a6f1069fb..309deabbb 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -245,7 +245,8 @@ QUIZ_CASE(poincare_simplification_units) { Unit::Builder(dim, rep, &Unit::EmptyPrefix).serialize(buffer+strlen("1×"), bufferSize-strlen("1×"), Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits); assert_parsed_expression_simplify_to(buffer, buffer); if (rep->isPrefixable()) { - for (const Unit::Prefix * pre = rep->outputPrefixes(); pre < rep->outputPrefixesUpperBound(); pre++) { + for (size_t i = 0; i < rep->outputPrefixesLength(); i++) { + const Unit::Prefix * pre = rep->outputPrefixes()[i]; Unit::Builder(dim, rep, pre).serialize(buffer+strlen("1×"), bufferSize-strlen("1×"), Preferences::PrintFloatMode::Decimal, Preferences::VeryShortNumberOfSignificantDigits); assert_parsed_expression_simplify_to(buffer, buffer); } From 0f4eee2d715108f8c06850bf0e85c7fc0d3b5dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 10:23:39 +0200 Subject: [PATCH 280/453] [poincare] Add comment on how Units are built --- poincare/include/poincare/unit.h | 7 +++++++ poincare/src/unit.cpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 3be06ccf6..e78b58905 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -188,6 +188,13 @@ public: typedef UnitNode::Prefix Prefix; typedef UnitNode::Representative Representative; typedef UnitNode::Dimension Dimension; + /* TODO: Prefix, Representative and Dimension defined below must be defined + * only once and all units must be constructed from their pointers. This way + * we can easily check if two Unit objects are equal by comparing pointers. + * This saves us from overloading the == operator on Prefix, Representative + * and Dimension and saves time at execution. We should assert at compilation + * that only one occurence of each is built by maybe privatizing constructors + * on these classes? */ static constexpr const Prefix PicoPrefix = Prefix("p", -12), NanoPrefix = Prefix("n", -9), diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 97b05093a..769e575a3 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -393,15 +393,18 @@ Expression Unit::removeUnit(Expression * unit) { } bool Unit::isSecond() const { + // TODO: comparing pointers suffices because all time dimension are built from the same pointers. This should be asserted some way at compile-time? return node()->dimension() == TimeDimension && node()->representative() == SecondRepresentative && node()->prefix() == &EmptyPrefix; } bool Unit::isMeter() const { + // See comment on isSecond return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; } bool Unit::isKilogram() const { + // See comment on isSecond return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; } From 7b2d020128dc46553069355cb6a320698793c570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 11:48:52 +0200 Subject: [PATCH 281/453] [poincare] Unit: implement IsIS --- poincare/include/poincare/unit.h | 2 ++ poincare/src/unit.cpp | 30 +++++++++++++++++++++++++ poincare/test/expression_properties.cpp | 10 +++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index e78b58905..d286d4bc6 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -766,6 +766,7 @@ public: static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } static Expression BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); + static bool IsIS(Expression & e); static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); static bool IsISEnergy(Expression & e); @@ -788,6 +789,7 @@ private: static constexpr double MonthPerYear = 12.0; static constexpr double DaysPerMonth = DaysPerYear/MonthPerYear; UnitNode * node() const { return static_cast(Expression::node()); } + bool isIS() const; static void ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); void chooseBestMultipleForValue(double * value, const int exponent, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext); Expression removeUnit(Expression * unit); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 769e575a3..9065a1ccc 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -408,6 +408,36 @@ bool Unit::isKilogram() const { return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; } +bool Unit::isIS() const { + UnitNode * unitNode = node(); + const Dimension * dim = unitNode->dimension(); + const Representative * rep = unitNode->representative(); + return rep == dim->stdRepresentative() && + rep->definition() == nullptr && + unitNode->prefix() == dim->stdRepresentativePrefix(); +} + +bool Unit::IsIS(Expression & e) { + if (e.type() == ExpressionNode::Type::Multiplication) { + for (int i = 0; i < e.numberOfChildren(); i++) { + Expression child = e.childAtIndex(i); + assert(child.type() == ExpressionNode::Type::Power || child.type() == ExpressionNode::Type::Unit); + if (!IsIS(child)) { + return false; + } + } + return true; + } + if (e.type() == ExpressionNode::Type::Power) { + assert(e.childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).convert().isInteger()); + Expression child = e.childAtIndex(0); + assert(child.type() == ExpressionNode::Type::Unit); + return IsIS(child); + } + assert(e.type() == ExpressionNode::Type::Unit); + return static_cast(e).isIS(); +} + bool Unit::IsISSpeed(Expression & e) { // Form m*s^-1 return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 2 && diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 03074eb3e..e2b0133f2 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -400,7 +400,7 @@ void assert_seconds_split_to(double totalSeconds, const char * splittedTime, Con Expression extract_unit(const char * expression) { Shared::GlobalContext globalContext; - ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User); + ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, User, ReplaceAllSymbolsWithUndefined, NoUnitConversion); Expression e = parse_expression(expression, &globalContext, false).reduce(reductionContext); Expression unit; e.removeUnit(&unit); @@ -428,5 +428,11 @@ QUIZ_CASE(poincare_expression_unit_helper) { // 4. Energy Expression kilogramMeter2PerSecond2 = extract_unit("_kg×_m^2×_s^-2"); quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); -} + // 5. International System + quiz_assert(Unit::IsIS(kilogramMeter2PerSecond2)); + quiz_assert(Unit::IsIS(meter3)); + quiz_assert(Unit::IsIS(meterPerSecond)); + Expression joule = extract_unit("_J"); + quiz_assert(!Unit::IsIS(joule)); +} From 1f9cdc5648c3862ad622367d37377832b5674583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 12:06:11 +0200 Subject: [PATCH 282/453] [apps] Calculation: do not offer additional results on units if there will be only one identical to the output --- apps/calculation/calculation.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index b0e723eba..603c89dd5 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -252,7 +252,32 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) { return AdditionalInformationType::Trigonometry; } - if (o.hasUnit()) { // TODO: find a way to check that it'll do have additional results + if (o.hasUnit()) { + Expression unit; + ExpressionNode::ReductionContext reductionContext( + App::app()->localContext(), + Preferences::sharedPreferences()->complexFormat(), + Preferences::sharedPreferences()->angleUnit(), + ExpressionNode::ReductionTarget::User, + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, + ExpressionNode::UnitConversion::None); + o = o.reduce(reductionContext).removeUnit(&unit); + if (Unit::IsIS(unit)) { + if (Unit::IsISSpeed(unit) || Unit::IsISVolume(unit) || Unit::IsISEnergy(unit)) { + /* All these units will provide misc. classic representatives in + * addition to the SI unit in additional information. */ + return AdditionalInformationType::Unit; + } + if (Unit::IsISTime(unit)) { + /* If the number of seconds is above 60s, we can write it in the form + * of an addition: 23_min + 12_s for instance. */ + double value = Shared::PoincareHelpers::ApproximateToScalar(o, App::app()->localContext()); + if (value > Unit::SecondsPerMinute) { + return AdditionalInformationType::Unit; + } + } + return AdditionalInformationType::None; + } return AdditionalInformationType::Unit; } if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { From 05a42cd2eb1f7de3f604af5081fccd0a7c1acb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 13:46:24 +0200 Subject: [PATCH 283/453] [apps/shared] PoincareHelpers: implement Reduce static inline function --- .../additional_outputs/unit_list_controller.cpp | 15 ++++++++------- apps/calculation/calculation.cpp | 10 ++-------- apps/shared/poincare_helpers.h | 7 +++++++ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index c8f654e10..e60800d11 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -8,6 +8,7 @@ #include using namespace Poincare; +using namespace Shared; namespace Calculation { @@ -22,16 +23,10 @@ void UnitListController::setExpression(Poincare::Expression e) { size_t numberOfMemoizedExpressions = 0; // 1. First rows: miscellaneous classic units for some dimensions - ExpressionNode::ReductionContext reductionContext( - App::app()->localContext(), - Preferences::sharedPreferences()->complexFormat(), - Preferences::sharedPreferences()->angleUnit(), - ExpressionNode::ReductionTarget::User, - ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); Expression copy = m_expression.clone(); Expression units; // Reduce to be able to recognize units - copy = copy.reduce(reductionContext); + PoincareHelpers::Reduce(©, App::app()->localContext(), ExpressionNode::ReductionTarget::User); copy = copy.removeUnit(&units); bool requireSimplification = false; bool canChangeUnitPrefix = false; @@ -88,6 +83,12 @@ void UnitListController::setExpression(Poincare::Expression e) { Expression newUnits; m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits); double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext()); + ExpressionNode::ReductionContext reductionContext( + App::app()->localContext(), + Preferences::sharedPreferences()->complexFormat(), + Preferences::sharedPreferences()->angleUnit(), + ExpressionNode::ReductionTarget::User, + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext); m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits); } diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 603c89dd5..ca69ca7ce 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -254,14 +254,8 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co } if (o.hasUnit()) { Expression unit; - ExpressionNode::ReductionContext reductionContext( - App::app()->localContext(), - Preferences::sharedPreferences()->complexFormat(), - Preferences::sharedPreferences()->angleUnit(), - ExpressionNode::ReductionTarget::User, - ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, - ExpressionNode::UnitConversion::None); - o = o.reduce(reductionContext).removeUnit(&unit); + PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User,ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None); + o = o.removeUnit(&unit); if (Unit::IsIS(unit)) { if (Unit::IsISSpeed(unit) || Unit::IsISVolume(unit) || Unit::IsISEnergy(unit)) { /* All these units will provide misc. classic representatives in diff --git a/apps/shared/poincare_helpers.h b/apps/shared/poincare_helpers.h index d2124de32..774547e17 100644 --- a/apps/shared/poincare_helpers.h +++ b/apps/shared/poincare_helpers.h @@ -69,6 +69,13 @@ inline void Simplify(Poincare::Expression * e, Poincare::Context * context, Poin *e = e->simplify(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), target, symbolicComputation, unitConversion)); } +inline void Reduce(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = Poincare::ExpressionNode::UnitConversion::Default) { + Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); + Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), *e, context); + + *e = e->reduce(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), target, symbolicComputation, unitConversion)); +} + inline void ParseAndSimplifyAndApproximate(const char * text, Poincare::Expression * simplifiedExpression, Poincare::Expression * approximateExpression, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), text); From 7bb4a2ae98ba6d3757f38ad42dc2ff3959796237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 15:04:22 +0200 Subject: [PATCH 284/453] [apps/calculation] Additional outputs: do not display identical unit as the outpu --- .../unit_list_controller.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index e60800d11..d961cc5f4 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -13,10 +13,9 @@ using namespace Shared; namespace Calculation { void UnitListController::setExpression(Poincare::Expression e) { - // TODO: order of call issue!!! ExpressionsListController::setExpression(e); assert(!m_expression.isUninitialized()); - // Reinitizlize m_memoizedExpressions + // Reinitialize m_memoizedExpressions for (size_t i = 0; i < k_maxNumberOfCells; i++) { m_memoizedExpressions[i] = Expression(); } @@ -43,14 +42,14 @@ void UnitListController::setExpression(Poincare::Expression e) { ) ) ); - requireSimplification = true; // Reduce the conversion + requireSimplification = true; // Simplify the conversion } else if (Unit::IsISVolume(units)) { // 1.b. Turn volume into L m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder( m_expression.clone(), Unit::Liter() ); - requireSimplification = true; // reduce the conversion + requireSimplification = true; // Simplify the conversion canChangeUnitPrefix = true; // Pick best prefix (mL) } else if (Unit::IsISEnergy(units)) { // 1.c. Turn energy into Wh @@ -65,7 +64,7 @@ void UnitListController::setExpression(Poincare::Expression e) { m_expression.clone(), Unit::ElectronVolt() ); - requireSimplification = true; // reduce the conversion + requireSimplification = true; // Simplify the conversion canChangeUnitPrefix = true; // Pick best prefix (kWh) } else if (Unit::IsISTime(units)) { // Turn time into ? year + ? month + ? day + ? h + ? min + ? s @@ -102,11 +101,16 @@ void UnitListController::setExpression(Poincare::Expression e) { numberOfMemoizedExpressions++; // 3. Get rid of duplicates + Expression reduceExpression = m_expression.clone(); + // Make m_expression compareable to m_memoizedExpressions (turn BasedInteger into Rational for instance) + Shared::PoincareHelpers::Simplify(&reduceExpression, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::None); currentExpressionIndex = 1; while (currentExpressionIndex < numberOfMemoizedExpressions) { - for (size_t i = 0; i < currentExpressionIndex; i++) { - assert(!m_memoizedExpressions[i].isUninitialized()); - if (m_memoizedExpressions[i].isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) { + for (size_t i = 0; i < currentExpressionIndex + 1; i++) { + // Compare the currentExpression to all previous memoized expressions and to m_expression + Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : m_memoizedExpressions[i]; + assert(!comparedExpression.isUninitialized()); + if (comparedExpression.isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) { numberOfMemoizedExpressions--; // Shift next expressions for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions; j++) { From 88a39c335fde4b091141ec285ddcc1644268761b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 7 May 2020 15:33:52 +0200 Subject: [PATCH 285/453] [poincare] Fix Unit::IsISEnergy --- poincare/src/unit.cpp | 6 +++--- poincare/test/expression_properties.cpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 9065a1ccc..e67ec6f10 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -459,11 +459,11 @@ bool Unit::IsISEnergy(Expression & e) { return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 3 && e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert().isKilogram() && e.childAtIndex(1).type() == ExpressionNode::Type::Power && - e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isMeter(); + e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isMeter() && e.childAtIndex(1).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isTwo() && e.childAtIndex(2).type() == ExpressionNode::Type::Power && - e.childAtIndex(2).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isSecond(); - e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusTwo(); + e.childAtIndex(2).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(2).childAtIndex(0).convert().isSecond() && + e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(2).childAtIndex(1).convert().isMinusTwo(); } bool Unit::IsISTime(Expression & e) { diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index e2b0133f2..c595aa0d5 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -428,6 +428,8 @@ QUIZ_CASE(poincare_expression_unit_helper) { // 4. Energy Expression kilogramMeter2PerSecond2 = extract_unit("_kg×_m^2×_s^-2"); quiz_assert(Unit::IsISEnergy(kilogramMeter2PerSecond2)); + Expression kilogramMeter3PerSecond2 = extract_unit("_kg×_m^3×_s^-2"); + quiz_assert(!Unit::IsISEnergy(kilogramMeter3PerSecond2)); // 5. International System quiz_assert(Unit::IsIS(kilogramMeter2PerSecond2)); From 6dfccc6edfe2fd8120b84b8af6bee74af9621a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 7 May 2020 14:56:49 +0200 Subject: [PATCH 286/453] Revert "[apps/code] EXE event accepts autocompletion" This reverts commit 5a96fd0e5de4a9bda30900e0c81a0b15f3fe081a. --- apps/code/python_text_area.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 7af7ddfe8..77a6f299b 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -277,8 +277,7 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) { // Handle event with autocompletion if (event == Ion::Events::Right || event == Ion::Events::ShiftRight - || event == Ion::Events::OK - || event == Ion::Events::EXE) + || event == Ion::Events::OK) { m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false); acceptAutocompletion(event != Ion::Events::ShiftRight); From d41b93c71124c622b25313ae6e824281231670e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 11:50:20 +0200 Subject: [PATCH 287/453] [apps/code] Put back the squares script template --- apps/code/script_template.cpp | 39 +++++++++++++---------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index df6350040..d2d4c9d7a 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -5,32 +5,21 @@ namespace Code { constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01\x00" R"(from math import * )"); -constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"( -#from math import sin as stew, cos as cabbage -from math import * -)"); +constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"(from math import * +from turtle import * +def squares(angle=0.5): + reset() + L=330 + speed(10) + penup() + goto(-L/2,-L/2) + pendown() + for i in range(660): + forward(L) + left(90+angle) + L=L-L*sin(angle*pi/180) + hideturtle())"); -/*constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"( -import math -import math as m -import math, cmath -import math as m, cmath as cm -from math import * -from math import sin -from math import sin as stew -from math import sin, cos -from math import sin as stew, cos as cabbage)");*/ -/* -import math // math -import math as m // math -import math, cmath // math math -import math as m, cmath as cm -from math import * -from math import sin -from math import sin as stew -from math import sin, cos -from math import sin as stew, cos as cabbage -*/ constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01\x00" R"(# This script draws a Mandelbrot fractal set # N_iteration: degree of precision import kandinsky From b8244ec0c5cb335f78247bc557e0ba6b130b2179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 15:37:38 +0200 Subject: [PATCH 288/453] [apps] Fix margins of LanguageController Add margin at the bottom and fix margin values --- apps/on_boarding/language_controller.cpp | 6 +++++- apps/settings/main_controller.cpp | 2 +- apps/shared/language_controller.cpp | 6 +++--- apps/shared/language_controller.h | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/on_boarding/language_controller.cpp b/apps/on_boarding/language_controller.cpp index 3319b507c..f65fce0cd 100644 --- a/apps/on_boarding/language_controller.cpp +++ b/apps/on_boarding/language_controller.cpp @@ -1,11 +1,15 @@ #include "language_controller.h" #include "../global_preferences.h" #include "../apps_container.h" +#include namespace OnBoarding { LanguageController::LanguageController(Responder * parentResponder) : - Shared::LanguageController(parentResponder, (Ion::Display::Height - I18n::NumberOfLanguages*Metric::ParameterCellHeight)/2) + Shared::LanguageController( + parentResponder, + std::max(static_cast(Metric::CommonLeftMargin), + (Ion::Display::Height - I18n::NumberOfLanguages*Metric::ParameterCellHeight)/2)) { } diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 5464241ed..c8b922a81 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -22,7 +22,7 @@ MainController::MainController(Responder * parentResponder, InputEventHandlerDel m_selectableTableView(this), m_preferencesController(this), m_displayModeController(this, inputEventHandlerDelegate), - m_languageController(this, 13), + m_languageController(this, Metric::CommonTopMargin), m_examModeController(this), m_aboutController(this) { diff --git a/apps/shared/language_controller.cpp b/apps/shared/language_controller.cpp index 97f81123d..5c0897f53 100644 --- a/apps/shared/language_controller.cpp +++ b/apps/shared/language_controller.cpp @@ -5,12 +5,12 @@ namespace Shared { -LanguageController::LanguageController(Responder * parentResponder, KDCoordinate topMargin) : +LanguageController::LanguageController(Responder * parentResponder, KDCoordinate verticalMargin) : ViewController(parentResponder), m_selectableTableView(this, this, this) { - m_selectableTableView.setTopMargin(topMargin); - m_selectableTableView.setBottomMargin(0); + m_selectableTableView.setTopMargin(verticalMargin); + m_selectableTableView.setBottomMargin(verticalMargin); for (int i = 0; i < I18n::NumberOfLanguages; i++) { m_cells[i].setMessageFont(KDFont::LargeFont); } diff --git a/apps/shared/language_controller.h b/apps/shared/language_controller.h index fac81fb7c..6658ca550 100644 --- a/apps/shared/language_controller.h +++ b/apps/shared/language_controller.h @@ -8,7 +8,7 @@ namespace Shared { class LanguageController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource { public: - LanguageController(Responder * parentResponder, KDCoordinate topMargin); + LanguageController(Responder * parentResponder, KDCoordinate verticalMargin); void resetSelection(); View * view() override; From 5f26ca40cc33a9fbb11e811d8b1be13a358d58e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 15:58:48 +0200 Subject: [PATCH 289/453] [apps/escher] Fix scroll view indicator margin So it does not overflow the scrolled view. Fixed for the language controllers (on boarding app and settings), one value was changed from a magic 14 to Metric::CommonTopMargin = 15, it did not seem to break anything. --- apps/on_boarding/language_controller.cpp | 4 ++++ apps/shared/language_controller.h | 5 ++++- escher/src/scroll_view_indicator.cpp | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/on_boarding/language_controller.cpp b/apps/on_boarding/language_controller.cpp index f65fce0cd..d4a3ae679 100644 --- a/apps/on_boarding/language_controller.cpp +++ b/apps/on_boarding/language_controller.cpp @@ -1,6 +1,7 @@ #include "language_controller.h" #include "../global_preferences.h" #include "../apps_container.h" +#include #include namespace OnBoarding { @@ -11,6 +12,9 @@ LanguageController::LanguageController(Responder * parentResponder) : std::max(static_cast(Metric::CommonLeftMargin), (Ion::Display::Height - I18n::NumberOfLanguages*Metric::ParameterCellHeight)/2)) { + static_cast(m_selectableTableView.decorator()->indicatorAtIndex(1))->setMargin( + std::max(static_cast(Metric::CommonLeftMargin), + (Ion::Display::Height - I18n::NumberOfLanguages*Metric::ParameterCellHeight)/2)); } bool LanguageController::handleEvent(Ion::Events::Event event) { diff --git a/apps/shared/language_controller.h b/apps/shared/language_controller.h index 6658ca550..a3ab284e2 100644 --- a/apps/shared/language_controller.h +++ b/apps/shared/language_controller.h @@ -23,8 +23,11 @@ public: int reusableCellCount() const override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; -private: + +protected: SelectableTableView m_selectableTableView; + +private: MessageTableCell m_cells[I18n::NumberOfLanguages]; }; diff --git a/escher/src/scroll_view_indicator.cpp b/escher/src/scroll_view_indicator.cpp index be36a152b..536e54d33 100644 --- a/escher/src/scroll_view_indicator.cpp +++ b/escher/src/scroll_view_indicator.cpp @@ -1,4 +1,5 @@ #include +#include #include extern "C" { #include @@ -8,7 +9,7 @@ extern "C" { ScrollViewIndicator::ScrollViewIndicator() : View(), m_color(Palette::GreyDark), - m_margin(14) + m_margin(Metric::CommonTopMargin) { } From 503227b49bbb8070df8dc5c6e1d360b3f6bc825a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 16:06:16 +0200 Subject: [PATCH 290/453] [apps/proba] Fix float/integer comparison --- apps/probability/distribution/geometric_distribution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/probability/distribution/geometric_distribution.cpp b/apps/probability/distribution/geometric_distribution.cpp index 1ac3559cd..20271258a 100644 --- a/apps/probability/distribution/geometric_distribution.cpp +++ b/apps/probability/distribution/geometric_distribution.cpp @@ -10,7 +10,7 @@ float GeometricDistribution::xMin() const { } float GeometricDistribution::xMax() const { - assert(m_parameter1 != 0); + assert(m_parameter1 != 0.0f); return 5/m_parameter1 * (1.0f + k_displayRightMarginRatio); } From d200688f20a21f2a9e45edec5e470d92eb0982d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 16:06:39 +0200 Subject: [PATCH 291/453] [apps/proba] Geometric distibution should return 0, not nan for x < 0 --- .../distribution/geometric_distribution.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/probability/distribution/geometric_distribution.cpp b/apps/probability/distribution/geometric_distribution.cpp index 20271258a..6c76fd365 100644 --- a/apps/probability/distribution/geometric_distribution.cpp +++ b/apps/probability/distribution/geometric_distribution.cpp @@ -31,13 +31,13 @@ bool GeometricDistribution::authorizedValueAtIndex(float x, int index) const { template T GeometricDistribution::templatedApproximateAtAbscissa(T x) const { if (x < 0) { - return NAN; + return static_cast(0.0); } - T p = (T)m_parameter1; - if (p == (T)1.0) { - return (T)(x == 0 ? 1.0 : 0.0); + T p = static_cast(m_parameter1); + if (p == static_cast(1.0)) { + return static_cast(x == 0 ? 1.0 : 0.0); } - T lResult = x * std::log(((T)1.0) - p); + T lResult = x * std::log(static_cast(1.0) - p); return p*std::exp(lResult); } From a9c47a946837bf8d76fa0e625480cee13ca0c76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 11 May 2020 16:27:37 +0200 Subject: [PATCH 292/453] [apps/probability] Change geometric distribution definition THe distribution now represents the number of trials neded before a success, so is defined for k in {1, 2, 3, ...} --- .../distribution/geometric_distribution.cpp | 17 +++++++++-------- .../distribution/geometric_distribution.h | 4 +--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/probability/distribution/geometric_distribution.cpp b/apps/probability/distribution/geometric_distribution.cpp index 6c76fd365..ed64b23ab 100644 --- a/apps/probability/distribution/geometric_distribution.cpp +++ b/apps/probability/distribution/geometric_distribution.cpp @@ -15,8 +15,7 @@ float GeometricDistribution::xMax() const { } float GeometricDistribution::yMax() const { - int maxAbscissa = 0; - float result = evaluateAtAbscissa(maxAbscissa); + float result = evaluateAtAbscissa(1.0); // Tha probability is max for x == 1 return result * (1.0f + k_displayTopMarginRatio); } @@ -29,16 +28,18 @@ bool GeometricDistribution::authorizedValueAtIndex(float x, int index) const { } template -T GeometricDistribution::templatedApproximateAtAbscissa(T x) const { - if (x < 0) { +T GeometricDistribution::templatedApproximateAtAbscissa(T k) const { + constexpr T castedOne = static_cast(1.0); + if (k < castedOne) { return static_cast(0.0); } T p = static_cast(m_parameter1); - if (p == static_cast(1.0)) { - return static_cast(x == 0 ? 1.0 : 0.0); + if (p == castedOne) { + return k == castedOne ? castedOne : static_cast(0.0); } - T lResult = x * std::log(static_cast(1.0) - p); - return p*std::exp(lResult); + // The result is p * (1-p)^{k-1} + T lResult = (k - castedOne) * std::log(castedOne - p); + return p * std::exp(lResult); } } diff --git a/apps/probability/distribution/geometric_distribution.h b/apps/probability/distribution/geometric_distribution.h index 035d2945e..e6903555a 100644 --- a/apps/probability/distribution/geometric_distribution.h +++ b/apps/probability/distribution/geometric_distribution.h @@ -7,9 +7,7 @@ namespace Probability { /* We chose the definition: * 0 < p <= 1 for success probability - * k failures where k ∈ {0, 1, 2, ... } - * The distribution follows the probability distribution of the number of failures before - * the first success. */ + * k number of trials needed to get one success, where k ∈ {1, 2, 3, ...}. */ class GeometricDistribution final : public OneParameterDistribution { public: From 9b2f91f5e1989a09548e85fee80ad7ea58672c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 12 May 2020 14:10:25 +0200 Subject: [PATCH 293/453] [apps/probability] Geometric distribution default computed value is 1 --- apps/probability/app.cpp | 23 +++++++++++-------- apps/probability/app.h | 5 ++++ apps/probability/calculation/calculation.cpp | 5 ---- apps/probability/calculation/calculation.h | 5 ++-- .../calculation/discrete_calculation.cpp | 7 +++--- .../calculation/discrete_calculation.h | 2 +- .../finite_integral_calculation.cpp | 9 ++++---- .../calculation/finite_integral_calculation.h | 2 +- .../calculation/left_integral_calculation.cpp | 7 +++--- .../calculation/left_integral_calculation.h | 2 +- .../right_integral_calculation.cpp | 7 +++--- .../calculation/right_integral_calculation.h | 2 +- apps/probability/calculation_controller.cpp | 17 +++++++------- apps/probability/distribution/distribution.h | 1 + .../distribution/geometric_distribution.h | 1 + 15 files changed, 49 insertions(+), 46 deletions(-) diff --git a/apps/probability/app.cpp b/apps/probability/app.cpp index 7b840ce50..f2b9f981c 100644 --- a/apps/probability/app.cpp +++ b/apps/probability/app.cpp @@ -24,14 +24,11 @@ App::Snapshot::Snapshot() : m_calculation{}, m_activePage(Page::Distribution) { - new(m_distribution) BinomialDistribution(); - new(m_calculation) LeftIntegralCalculation(); - calculation()->setDistribution(distribution()); + initializeDistributionAndCalculation(); } App::Snapshot::~Snapshot() { - distribution()->~Distribution(); - calculation()->~Calculation(); + deleteDistributionAndCalculation(); } App * App::Snapshot::unpack(Container * container) { @@ -44,10 +41,8 @@ App::Descriptor * App::Snapshot::descriptor() { } void App::Snapshot::reset() { - distribution()->~Distribution(); - new(m_distribution) BinomialDistribution(); - calculation()->~Calculation(); - new(m_calculation) LeftIntegralCalculation(); + deleteDistributionAndCalculation(); + initializeDistributionAndCalculation(); m_activePage = Page::Distribution; } @@ -59,6 +54,16 @@ Calculation * App::Snapshot::calculation() { return (Calculation *)m_calculation; } +void App::Snapshot::deleteDistributionAndCalculation() { + distribution()->~Distribution(); + calculation()->~Calculation(); +} + +void App::Snapshot::initializeDistributionAndCalculation() { + new(m_distribution) BinomialDistribution(); + new(m_calculation) LeftIntegralCalculation(distribution()); +} + void App::Snapshot::setActivePage(Page activePage) { m_activePage = activePage; } diff --git a/apps/probability/app.h b/apps/probability/app.h index fcf41951a..afb9075a7 100644 --- a/apps/probability/app.h +++ b/apps/probability/app.h @@ -45,9 +45,14 @@ public: Calculation * calculation(); Page activePage(); void setActivePage(Page activePage); + private: constexpr static int k_distributionSizes[] = {sizeof(BinomialDistribution),sizeof(ExponentialDistribution), sizeof(NormalDistribution), sizeof(PoissonDistribution), sizeof(UniformDistribution), 0}; constexpr static size_t k_distributionSize = max(k_distributionSizes); + + void deleteDistributionAndCalculation(); + void initializeDistributionAndCalculation(); + char m_distribution[k_distributionSize]; constexpr static int k_calculationSizes[] = {sizeof(LeftIntegralCalculation),sizeof(FiniteIntegralCalculation), sizeof(RightIntegralCalculation), 0}; constexpr static size_t k_calculationSize = max(k_calculationSizes); diff --git a/apps/probability/calculation/calculation.cpp b/apps/probability/calculation/calculation.cpp index f45f31460..a059a938e 100644 --- a/apps/probability/calculation/calculation.cpp +++ b/apps/probability/calculation/calculation.cpp @@ -4,11 +4,6 @@ namespace Probability { -void Calculation::setDistribution(Distribution * distribution) { - m_distribution = distribution; - compute(0); -} - double Calculation::lowerBound() { return -INFINITY; } diff --git a/apps/probability/calculation/calculation.h b/apps/probability/calculation/calculation.h index 215daece6..f7847dba4 100644 --- a/apps/probability/calculation/calculation.h +++ b/apps/probability/calculation/calculation.h @@ -13,10 +13,11 @@ public: RightIntegral, Discrete, }; - Calculation() : m_distribution(nullptr) {} + Calculation(Distribution * distribution) : m_distribution(distribution) { + assert(distribution != nullptr); + } virtual ~Calculation() = default; virtual Type type() = 0; - void setDistribution(Distribution * distribution); virtual int numberOfParameters() = 0; virtual I18n::Message legendForParameterAtIndex(int index) = 0; virtual void setParameterAtIndex(double f, int index) = 0; diff --git a/apps/probability/calculation/discrete_calculation.cpp b/apps/probability/calculation/discrete_calculation.cpp index 075038512..798281e70 100644 --- a/apps/probability/calculation/discrete_calculation.cpp +++ b/apps/probability/calculation/discrete_calculation.cpp @@ -5,10 +5,9 @@ namespace Probability { -DiscreteCalculation::DiscreteCalculation() : - Calculation(), - m_abscissa(0.0), - m_result(0.0) +DiscreteCalculation::DiscreteCalculation(Distribution * distribution) : + Calculation(distribution), + m_abscissa(distribution->defaultComputedValue()) { compute(0); } diff --git a/apps/probability/calculation/discrete_calculation.h b/apps/probability/calculation/discrete_calculation.h index 6bf1b332a..9ca655e94 100644 --- a/apps/probability/calculation/discrete_calculation.h +++ b/apps/probability/calculation/discrete_calculation.h @@ -7,7 +7,7 @@ namespace Probability { class DiscreteCalculation final : public Calculation { public: - DiscreteCalculation(); + DiscreteCalculation(Distribution * distribution); Type type() override { return Type::Discrete; } int numberOfParameters() override { return 2; } I18n::Message legendForParameterAtIndex(int index) override; diff --git a/apps/probability/calculation/finite_integral_calculation.cpp b/apps/probability/calculation/finite_integral_calculation.cpp index a1ac5d9c8..2341bc15b 100644 --- a/apps/probability/calculation/finite_integral_calculation.cpp +++ b/apps/probability/calculation/finite_integral_calculation.cpp @@ -6,11 +6,10 @@ namespace Probability { -FiniteIntegralCalculation::FiniteIntegralCalculation() : - Calculation(), - m_lowerBound(0.0), - m_upperBound(1.0), - m_result(0.0) +FiniteIntegralCalculation::FiniteIntegralCalculation(Distribution * distribution) : + Calculation(distribution), + m_lowerBound(distribution->defaultComputedValue()), + m_upperBound(m_lowerBound + 1.0) { compute(0); } diff --git a/apps/probability/calculation/finite_integral_calculation.h b/apps/probability/calculation/finite_integral_calculation.h index ccbd2afd0..fbbb867ac 100644 --- a/apps/probability/calculation/finite_integral_calculation.h +++ b/apps/probability/calculation/finite_integral_calculation.h @@ -7,7 +7,7 @@ namespace Probability { class FiniteIntegralCalculation : public Calculation { public: - FiniteIntegralCalculation(); + FiniteIntegralCalculation(Distribution * distribution); Type type() override { return Type::FiniteIntegral; } int numberOfParameters() override { return 3; } I18n::Message legendForParameterAtIndex(int index) override; diff --git a/apps/probability/calculation/left_integral_calculation.cpp b/apps/probability/calculation/left_integral_calculation.cpp index f589ce4e8..d24430b74 100644 --- a/apps/probability/calculation/left_integral_calculation.cpp +++ b/apps/probability/calculation/left_integral_calculation.cpp @@ -5,10 +5,9 @@ namespace Probability { -LeftIntegralCalculation::LeftIntegralCalculation() : - Calculation(), - m_upperBound(0.0), - m_result(0.0) +LeftIntegralCalculation::LeftIntegralCalculation(Distribution * distribution) : + Calculation(distribution), + m_upperBound(distribution->defaultComputedValue()) { compute(0); } diff --git a/apps/probability/calculation/left_integral_calculation.h b/apps/probability/calculation/left_integral_calculation.h index f998cdb12..032a52581 100644 --- a/apps/probability/calculation/left_integral_calculation.h +++ b/apps/probability/calculation/left_integral_calculation.h @@ -7,7 +7,7 @@ namespace Probability { class LeftIntegralCalculation final : public Calculation { public: - LeftIntegralCalculation(); + LeftIntegralCalculation(Distribution * distribution); Type type() override { return Type::LeftIntegral; } int numberOfParameters() override { return 2; } I18n::Message legendForParameterAtIndex(int index) override; diff --git a/apps/probability/calculation/right_integral_calculation.cpp b/apps/probability/calculation/right_integral_calculation.cpp index 08903df47..068fe3552 100644 --- a/apps/probability/calculation/right_integral_calculation.cpp +++ b/apps/probability/calculation/right_integral_calculation.cpp @@ -5,10 +5,9 @@ namespace Probability { -RightIntegralCalculation::RightIntegralCalculation() : - Calculation(), - m_lowerBound(0.0), - m_result(0.0) +RightIntegralCalculation::RightIntegralCalculation(Distribution * distribution) : + Calculation(distribution), + m_lowerBound(distribution->defaultComputedValue()) { compute(0); } diff --git a/apps/probability/calculation/right_integral_calculation.h b/apps/probability/calculation/right_integral_calculation.h index 71f1e5530..9cb8f001d 100644 --- a/apps/probability/calculation/right_integral_calculation.h +++ b/apps/probability/calculation/right_integral_calculation.h @@ -7,7 +7,7 @@ namespace Probability { class RightIntegralCalculation final : public Calculation { public: - RightIntegralCalculation(); + RightIntegralCalculation(Distribution * distribution); Type type() override { return Type::RightIntegral; } int numberOfParameters() override { return 2; } I18n::Message legendForParameterAtIndex(int index) override; diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index a0782cdf3..2869f5abf 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -251,21 +251,20 @@ void CalculationController::setCalculationAccordingToIndex(int index, bool force m_calculation->~Calculation(); switch (index) { case 0: - new(m_calculation) LeftIntegralCalculation(); - break; + new(m_calculation) LeftIntegralCalculation(m_distribution); + return; case 1: - new(m_calculation) FiniteIntegralCalculation(); - break; + new(m_calculation) FiniteIntegralCalculation(m_distribution); + return; case 2: - new(m_calculation) RightIntegralCalculation(); - break; + new(m_calculation) RightIntegralCalculation(m_distribution); + return; case 3: - new(m_calculation) DiscreteCalculation(); - break; + new(m_calculation) DiscreteCalculation(m_distribution); + return; default: return; } - m_calculation->setDistribution(m_distribution); } void CalculationController::updateTitle() { diff --git a/apps/probability/distribution/distribution.h b/apps/probability/distribution/distribution.h index 95575ed43..e7e9d5332 100644 --- a/apps/probability/distribution/distribution.h +++ b/apps/probability/distribution/distribution.h @@ -39,6 +39,7 @@ public: virtual double rightIntegralInverseForProbability(double * probability); virtual double evaluateAtDiscreteAbscissa(int k) const; constexpr static int k_maxNumberOfOperations = 1000000; + virtual double defaultComputedValue() const { return 0.0f; } protected: static_assert(Poincare::Preferences::LargeNumberOfSignificantDigits == 7, "k_maxProbability is ill-defined compared to LargeNumberOfSignificantDigits"); constexpr static double k_maxProbability = 0.9999995; diff --git a/apps/probability/distribution/geometric_distribution.h b/apps/probability/distribution/geometric_distribution.h index e6903555a..e3323abfa 100644 --- a/apps/probability/distribution/geometric_distribution.h +++ b/apps/probability/distribution/geometric_distribution.h @@ -30,6 +30,7 @@ public: return templatedApproximateAtAbscissa(x); } bool authorizedValueAtIndex(float x, int index) const override; + double defaultComputedValue() const override { return 1.0f; } private: double evaluateAtDiscreteAbscissa(int k) const override { return templatedApproximateAtAbscissa((double)k); From e8d97f561c7d05a4b40c21db5993f5dc6037b279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 12 May 2020 15:48:24 +0200 Subject: [PATCH 294/453] [apps/proba] Fix tests --- apps/probability/test/distributions.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/probability/test/distributions.cpp b/apps/probability/test/distributions.cpp index 20bd9d9f9..f28c1c9ba 100644 --- a/apps/probability/test/distributions.cpp +++ b/apps/probability/test/distributions.cpp @@ -110,19 +110,19 @@ QUIZ_CASE(geometric_distribution) { // Geometric distribution with probability of success 0.5 Probability::GeometricDistribution distribution; distribution.setParameterAtIndex(0.5, 0); - assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.0, 0.875); - assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 3.0, 0.9375); + assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.0, 0.5); + assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.0, 0.75); // Geometric distribution with probability of success 0.2 distribution.setParameterAtIndex(0.2, 0); - assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 7.0, 0.8322278399999998299563230830244719982147216796875); - assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 3.0, 0.5904); + assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 6.0, 0.737856); + assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.0, 0.36); // Geometric distribution with probability of success 0.4 distribution.setParameterAtIndex(0.4, 0); - assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.24); + assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.4); assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0); - assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.384); + assert_finite_integral_between_abscissas_is(&distribution, 2.0, 3.0, 0.384); } QUIZ_CASE(fisher_distribution) { From 3e4478454ca55239b365388cbf69b7f0c86f5a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:13:47 +0200 Subject: [PATCH 295/453] [escher] Avoid useless redrawing in ExpressionView::setLayout --- escher/src/expression_view.cpp | 10 ++++------ poincare/include/poincare/tree_handle.h | 3 +++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/escher/src/expression_view.cpp b/escher/src/expression_view.cpp index 35f0f65cf..75dab0d4e 100644 --- a/escher/src/expression_view.cpp +++ b/escher/src/expression_view.cpp @@ -18,13 +18,11 @@ ExpressionView::ExpressionView(float horizontalAlignment, float verticalAlignmen } bool ExpressionView::setLayout(Layout layoutR) { - /* TODO: this would avoid some useless redrawing. However, when we call - * setLayout after raising an Exception that led to erase all - * Poincare::TreePool, accessing m_layout will result in an ACCESS ERROR. - * How do we avoid that? */ - /*if (m_layout.isIdenticalTo(layoutR)) { + if (!m_layout.wasErasedByException() && m_layout.isIdenticalTo(layoutR)) { + /* Check m_layout.wasErasedByException(), otherwise accessing m_layout would + * result in an ACCESS ERROR. */ return false; - }*/ + } m_layout = layoutR; markRectAsDirty(bounds()); return true; diff --git a/poincare/include/poincare/tree_handle.h b/poincare/include/poincare/tree_handle.h index b171871b6..30aea87fd 100644 --- a/poincare/include/poincare/tree_handle.h +++ b/poincare/include/poincare/tree_handle.h @@ -62,6 +62,9 @@ public: uint16_t identifier() const { return m_identifier; } TreeNode * node() const; + bool wasErasedByException() const { + return hasNode(m_identifier) && node() == nullptr; + } int nodeRetainCount() const { return node()->retainCount(); } size_t size() const; void * addressInPool() const { return reinterpret_cast(node()); } From 9d5e58f32b14dd2f65789ccc45ed33b96e7efa3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:15:39 +0200 Subject: [PATCH 296/453] [escher/scroll_view] Do not compute offset if view invisible --- escher/src/scroll_view.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index 294ec5350..ec06497d9 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -53,9 +53,16 @@ void ScrollView::scrollToContentPoint(KDPoint p, bool allowOverscroll) { if (!allowOverscroll && !m_contentView->bounds().contains(p)) { return; } + + KDRect visibleRect = visibleContentRect(); + + if (visibleRect.width() < 0 || visibleRect.height() < 0) { + return; + } + KDCoordinate offsetX = 0; KDCoordinate offsetY = 0; - KDRect visibleRect = visibleContentRect(); + if (visibleRect.left() > p.x()) { offsetX = p.x() - visibleRect.left(); } From 12a45ef8e689b747aa99d2d4f35a3be17c438219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:16:20 +0200 Subject: [PATCH 297/453] [escher/poincare] Coding style --- escher/src/scroll_view.cpp | 12 ++++++++++-- poincare/src/tree_node.cpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index ec06497d9..ab8f8cabd 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -81,8 +81,16 @@ void ScrollView::scrollToContentPoint(KDPoint p, bool allowOverscroll) { // Handle cases when the size of the view has decreased. setContentOffset(KDPoint( - std::min(contentOffset().x(), std::max(minimalSizeForOptimalDisplay().width() - bounds().width(), KDCoordinate{0})), - std::min(contentOffset().y(), std::max(minimalSizeForOptimalDisplay().height() - bounds().height(), 0)))); + std::min( + contentOffset().x(), + std::max( + minimalSizeForOptimalDisplay().width() - bounds().width(), + KDCoordinate(0))), + std::min( + contentOffset().y(), + std::max( + minimalSizeForOptimalDisplay().height() - bounds().height(), + KDCoordinate(0))))); } void ScrollView::scrollToContentRect(KDRect rect, bool allowOverscroll) { diff --git a/poincare/src/tree_node.cpp b/poincare/src/tree_node.cpp index 3052b4a7e..5076cc277 100644 --- a/poincare/src/tree_node.cpp +++ b/poincare/src/tree_node.cpp @@ -31,7 +31,7 @@ void TreeNode::rename(uint16_t identifier, bool unregisterPreviousIdentifier) { TreeNode * TreeNode::parent() const { assert(m_parentIdentifier != m_identifier); - return TreeHandle::hasNode(m_parentIdentifier) ? TreePool::sharedPool()->node(m_parentIdentifier) : nullptr; + return TreeHandle::hasNode(m_parentIdentifier) ? TreePool::sharedPool()->node(m_parentIdentifier) : nullptr; } TreeNode * TreeNode::root() { From 515aa543d38f65135d6bab1927d635ad37883e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:17:09 +0200 Subject: [PATCH 298/453] [escher/table_view] Remove dead code --- escher/include/escher/table_view.h | 2 -- escher/src/table_view.cpp | 19 ------------------- 2 files changed, 21 deletions(-) diff --git a/escher/include/escher/table_view.h b/escher/include/escher/table_view.h index b7eb77ae5..106c46261 100644 --- a/escher/include/escher/table_view.h +++ b/escher/include/escher/table_view.h @@ -58,8 +58,6 @@ protected: * coordinates that refer to the data source entire table */ int absoluteColumnNumberFromSubviewIndex(int index) const; int absoluteRowNumberFromSubviewIndex(int index) const; - int numberOfFullyDisplayableRows() const; - int numberOfFullyDisplayableColumns() const; int typeOfSubviewAtIndex(int index) const; /* This method transform a index (of subview for instance) into an index * refering to the set of cells of type "type". */ diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index 01ea22a2d..28d3dfd74 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -177,25 +177,6 @@ void TableView::ContentView::layoutSubviews(bool force) { } } - -int TableView::ContentView::numberOfFullyDisplayableRows() const { - // The number of displayable rows taking into accounts margins - int rowOffsetWithMargin = m_dataSource->indexFromCumulatedHeight(m_tableView->contentOffset().y() + - m_tableView->topMargin()); - int displayedHeightWithOffsetAndMargin = m_dataSource->indexFromCumulatedHeight(m_tableView->maxContentHeightDisplayableWithoutScrolling() + - m_tableView->contentOffset().y() + m_tableView->topMargin()); - return displayedHeightWithOffsetAndMargin - rowOffsetWithMargin; -} - -int TableView::ContentView::numberOfFullyDisplayableColumns() const { - // The number of displayable rows taking into accounts margins - int columnOffsetWithMargin = m_dataSource->indexFromCumulatedWidth(m_tableView->contentOffset().x() + - m_tableView->leftMargin()); - int displayedWidthWithOffsetAndMargin = m_dataSource->indexFromCumulatedWidth(m_tableView->maxContentWidthDisplayableWithoutScrolling() + - m_tableView->contentOffset().x() + m_tableView->leftMargin()); - return displayedWidthWithOffsetAndMargin - columnOffsetWithMargin; -} - int TableView::ContentView::numberOfDisplayableRows() const { int rowOffset = rowsScrollingOffset(); int displayedHeightWithOffset = m_dataSource->indexFromCumulatedHeight(m_tableView->bounds().height() + m_tableView->contentOffset().y()); From 44af4b1fdef79456ccc0611626201bd36f4bc73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:43:27 +0200 Subject: [PATCH 299/453] [escher/table_view] Fix numberOfDisplayableRows/Columns Did not take into account the margin so was too big sometimes --- escher/src/table_view.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index 28d3dfd74..aacbd8d42 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -179,20 +179,14 @@ void TableView::ContentView::layoutSubviews(bool force) { int TableView::ContentView::numberOfDisplayableRows() const { int rowOffset = rowsScrollingOffset(); - int displayedHeightWithOffset = m_dataSource->indexFromCumulatedHeight(m_tableView->bounds().height() + m_tableView->contentOffset().y()); - return std::min( - m_dataSource->numberOfRows(), - displayedHeightWithOffset + 1 - ) - rowOffset; + int displayedHeightWithOffset = m_dataSource->indexFromCumulatedHeight(m_tableView->bounds().height() + (m_tableView->contentOffset().y() - m_tableView->topMargin())); + return std::min(m_dataSource->numberOfRows(), displayedHeightWithOffset + 1) - rowOffset; } int TableView::ContentView::numberOfDisplayableColumns() const { int columnOffset = columnsScrollingOffset(); - int displayedWidthWithOffset = m_dataSource->indexFromCumulatedWidth(m_tableView->bounds().width() + m_tableView->contentOffset().x()); - return std::min( - m_dataSource->numberOfColumns(), - displayedWidthWithOffset + 1 - ) - columnOffset; + int displayedWidthWithOffset = m_dataSource->indexFromCumulatedWidth(m_tableView->bounds().width() + m_tableView->contentOffset().x() - m_tableView->leftMargin()); + return std::min(m_dataSource->numberOfColumns(), displayedWidthWithOffset + 1) - columnOffset; } int TableView::ContentView::rowsScrollingOffset() const { From b096d6f5e4e5b8c5c7cb15424d780938ee314bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 May 2020 17:44:24 +0200 Subject: [PATCH 300/453] [escher/table_view] COding style --- escher/src/table_view.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/escher/src/table_view.cpp b/escher/src/table_view.cpp index aacbd8d42..91c587908 100644 --- a/escher/src/table_view.cpp +++ b/escher/src/table_view.cpp @@ -192,15 +192,13 @@ int TableView::ContentView::numberOfDisplayableColumns() const { int TableView::ContentView::rowsScrollingOffset() const { /* Here, we want to translate the offset at which our tableView is displaying * us into an integer offset we can use to ask cells to our data source. */ - KDCoordinate invisibleHeight = m_tableView->contentOffset().y()-m_tableView->topMargin(); - invisibleHeight = invisibleHeight < 0 ? 0 : invisibleHeight; + KDCoordinate invisibleHeight = std::max(m_tableView->contentOffset().y() - m_tableView->topMargin(), 0); return m_dataSource->indexFromCumulatedHeight(invisibleHeight); } int TableView::ContentView::columnsScrollingOffset() const { /* Here, we want to translate the offset at which our tableView is displaying * us into an integer offset we can use to ask cells to our data source. */ - KDCoordinate invisibleWidth = m_tableView->contentOffset().x()-m_tableView->leftMargin(); - invisibleWidth = invisibleWidth < 0 ? 0 : invisibleWidth; + KDCoordinate invisibleWidth = std::max(m_tableView->contentOffset().x() - m_tableView->leftMargin(), 0); return m_dataSource->indexFromCumulatedWidth(invisibleWidth); } From 7d5304686db535d3a1b99e051763dda6e8161001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 May 2020 10:16:48 +0200 Subject: [PATCH 301/453] [apps/scrollable_multiple_expressions_view] Add TODO comment --- apps/shared/scrollable_multiple_expressions_view.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/shared/scrollable_multiple_expressions_view.cpp b/apps/shared/scrollable_multiple_expressions_view.cpp index ea57f98a4..50f97419b 100644 --- a/apps/shared/scrollable_multiple_expressions_view.cpp +++ b/apps/shared/scrollable_multiple_expressions_view.cpp @@ -244,7 +244,10 @@ void AbstractScrollableMultipleExpressionsView::setLayouts(Poincare::Layout left contentCell()->layoutSubviews(); // Reload the scroll content view layout (the content size might have changed) layoutSubviews(); - // Do no reload scroll here as 'setLayouts' is called every time the table is re-layout (when scrolling for instance) + /* TODO revert commit 87e48361961d1? + * We can call reloadScroll here instead of in didBecome firstResponder, + * because we fixed setLayouts (updateLeftLayout, updateCenterLayout and + * updateRightLayout are now sometimes false). */ } } From f2a1c635ef0c32c0aeaad60742d112d70578440a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 14:05:37 +0200 Subject: [PATCH 302/453] [apps/code] I18n: Missing translations --- apps/code/catalog.it.i18n | 2 +- apps/code/catalog.pt.i18n | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 0ca9d0f86..8fa8decfb 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -167,7 +167,7 @@ PythonTurtleBlue = "Colore blu" PythonTurtleBrown = "Colore marrone" PythonTurtleCircle = "Cerchio di raggio r pixel" PythonTurtleColor = "Modifica il colore del tratto" -PythonTurtleColorMode = "Set the color mode to 1.0 or 255" +PythonTurtleColorMode = "Imposta la modalità colore a 1.0 o 255" PythonTurtleForward = "Avanza di x pixel" PythonTurtleFunction = "Prefisso funzione modello turtle" PythonTurtleGoto = "Spostati alle coordinate (x,y)" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 5d3b58e78..20b63e96a 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -167,7 +167,7 @@ PythonTurtleBlue = "Cor azul" PythonTurtleBrown = "Cor castanha" PythonTurtleCircle = "Circunferência de raio r pixels" PythonTurtleColor = "Definir a cor da caneta" -PythonTurtleColorMode = "Set the color mode to 1.0 or 255" +PythonTurtleColorMode = "Ajustar o modo de cor para 1.0 ou 255" PythonTurtleForward = "Avançar x pixels" PythonTurtleFunction = "Prefixo da função do módulo turtle" PythonTurtleGoto = "Ir paras as coordenadas (x,y)" From ab69c0069c99e19d2eff0c3dafdf285c6b46715d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 15:18:26 +0200 Subject: [PATCH 303/453] [python] Fix alignement issues in MicroPython::collectRootsAtAddress --- python/port/port.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/python/port/port.cpp b/python/port/port.cpp index 6ae0c36c9..0a2ebc4b7 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -155,12 +155,28 @@ void MicroPython::registerScriptProvider(ScriptProvider * s) { } void MicroPython::collectRootsAtAddress(char * address, int byteLength) { - /* All addresses stored on the stack are aligned on sizeof(void *), as - * asserted. This is a consequence of the alignment requirements of compilers - * (Cf http://www.catb.org/esr/structure-packing/). */ - assert(((unsigned long)address) % ((unsigned long)sizeof(void *)) == 0); - assert(byteLength % sizeof(void *) == 0); - gc_collect_root((void **)address, byteLength / sizeof(void *)); + /* The given address is not necessarily aligned on sizeof(void *). However, + * any pointer stored in the range [address, address + byteLength] will be + * aligned on sizeof(void *). This is a consequence of the alignment + * requirements of compilers (Cf http://www.catb.org/esr/structure-packing/). + * Micropython gc_collect_root scans looking for pointers jumping every + * sizeof(void *). It has to be provided with a sizeof(uintptr_t)-aligned + * address. */ + // Compute the aligned address + // 0b000...00011 with 2 (or 3 for x64 arch) 1s + uintptr_t bitMaskOnes = sizeof(uintptr_t) - 1; + // 0b111...11100 with sizeof(uintptr_t)-1 0s + uintptr_t bitMaskZeros = ~bitMaskOnes; + uintptr_t alignedAddress = reinterpret_cast(address) & bitMaskZeros; + /* Increase the length consequently with the new alignment + * (We don't need to increase the byteLength to a sizeof(uintptr_t)-aligned + * lenght because no pointer can be stored on less than sizeof(uintptr_t) + * bytes.) */ + int alignedByteLength = byteLength; + alignedByteLength += reinterpret_cast(address) & bitMaskOnes; + + assert(alignedAddress % ((uintptr_t)sizeof(uintptr_t)) == 0); + gc_collect_root((void **)alignedAddress, byteLength / sizeof(uintptr_t)); } KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorMode ColorMode){ From 465fa5c63f37f8fb2eb80fab74636858f3cc3684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 15:59:46 +0200 Subject: [PATCH 304/453] [escher] TextField: fix insertTextAtLocation (confusion between size and length) This fixes the following bug: in a textfield, input '000', clear, input '00', backspace --> crash --- escher/src/text_field.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index da9109d55..b16e5c70f 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -135,7 +135,7 @@ bool TextField::ContentView::insertTextAtLocation(const char * text, char * loca char overridenByte = *overridenByteLocation; strlcpy(location, text, copySize); *overridenByteLocation = overridenByte; - m_currentDraftTextLength += copySize; + m_currentDraftTextLength += copySize-1; // Do no count the null-termination reloadRectFromPosition(m_horizontalAlignment == 0.0f ? location : s_draftTextBuffer); return true; From d3bd08612513e6ce21ecb66c0bd8b1249245a735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 16:52:17 +0200 Subject: [PATCH 305/453] [apps/graph] Fix order of actions to edit the function name, we should update the bufferSize before setting the text This fixes the following bug: add a function, rename it "f123456", change its type to a polar function, rename it --> crash --- apps/graph/list/text_field_function_title_cell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/graph/list/text_field_function_title_cell.cpp b/apps/graph/list/text_field_function_title_cell.cpp index 55c7f6676..38f0284f2 100644 --- a/apps/graph/list/text_field_function_title_cell.cpp +++ b/apps/graph/list/text_field_function_title_cell.cpp @@ -27,8 +27,8 @@ void TextFieldFunctionTitleCell::setEditing(bool editing) { int extensionLength = UTF8Helper::HasCodePoint(previousText, UCodePointGreekSmallLetterTheta) ? Shared::Function::k_parenthesedThetaArgumentByteLength : Shared::Function::k_parenthesedXNTArgumentByteLength; m_textField.setExtensionLength(extensionLength); m_textField.setEditing(true); - m_textField.setText(previousText); m_textField.setDraftTextBufferSize(Poincare::SymbolAbstract::k_maxNameSize+extensionLength); + m_textField.setText(previousText); } bool TextFieldFunctionTitleCell::isEditing() const { From 6a0d65b049f3b27f7127ce44edd9ab4586ee8233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 20 May 2020 10:26:17 +0200 Subject: [PATCH 306/453] [apps/calculation] additional_outputs: the complex illustration chose its range to be orthornomal --- .../additional_outputs/complex_model.h | 49 +++++++++++++++++-- .../illustrated_list_controller.h | 2 +- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/apps/calculation/additional_outputs/complex_model.h b/apps/calculation/additional_outputs/complex_model.h index 827418c1e..685d6bdaf 100644 --- a/apps/calculation/additional_outputs/complex_model.h +++ b/apps/calculation/additional_outputs/complex_model.h @@ -2,6 +2,7 @@ #define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_MODEL_H #include "../../shared/curve_view_range.h" +#include "illustrated_list_controller.h" #include namespace Calculation { @@ -17,11 +18,53 @@ public: void setComplex(std::complex c) { *this = ComplexModel(c); } - - static constexpr float k_minVerticalMarginFactor = -0.5f; - static constexpr float k_maxVerticalMarginFactor = 1.2f; + /* The range is computed from these criteria: + * - The real part is centered horizontally + * - Both left and right margins are equal to the real length + * - The imaginary part is the same length as the real part + * - The remaining vertical margin are splitted as one third at the top, 2 + * thirds at the bottom + * + * | | 1/3 * vertical_margin + * +----------+ + * | / | | + * | / | | Imaginary + * | / | | + * | / | | + * ----------+----------+---------- + * | + * | 2/3 * vertical_margin + * ----------- + * Real + * + */ + // Horizontal range static constexpr float k_minHorizontalMarginFactor = -1.0f; static constexpr float k_maxHorizontalMarginFactor = 2.0f; + // Vertical range + static constexpr KDCoordinate k_width = Ion::Display::Width - Metric::PopUpRightMargin - Metric::PopUpLeftMargin; + static constexpr KDCoordinate k_height = IllustratedListController::k_illustrationHeight; + static constexpr KDCoordinate k_unit = k_width/3; + /* + * VerticalMaring = k_height - k_unit + * + * Values | Coordinates + * --------+---------------------------------- + * imag | k_unit + * Ymax | k_unit + (1/3)*VerticalMargin + * Ymin | -(2/3)*VerticalMargin + * + * Thus: + * Ymin = -(2/3)*k_verticalMargin*imag/k_unit + * = -(2/3)*(k_height/k_unit - 1)*imag + * = 2/3*(1 - k_height/k_unit)*imag + * Ymax = (k_unit + (1/3)*VerticalMargin)*imag/k_unit + * = (1 + (1/3)*(k_height/k_unit - 1))*imag + * = 1/3*(2 + k_height/k_unit)*imag + * + * */ + static constexpr float k_minVerticalMarginFactor = 2.0f/3.0f*(1.0f - (float)k_height/(float)k_unit); + static constexpr float k_maxVerticalMarginFactor = 1.0f/3.0f*(2.0f + (float)k_height/(float)k_unit); private: float rangeBound(float direction, bool horizontal) const; diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.h b/apps/calculation/additional_outputs/illustrated_list_controller.h index d06ca7edc..c4bca2415 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.h +++ b/apps/calculation/additional_outputs/illustrated_list_controller.h @@ -31,7 +31,7 @@ public: // IllustratedListController void setExpression(Poincare::Expression e) override; - constexpr static KDCoordinate k_illustrationHeight = 100; + constexpr static KDCoordinate k_illustrationHeight = 120; protected: Poincare::Expression m_savedExpression; CalculationStore m_calculationStore; From a4c591dea63736a8c5f24322b029235bee1ca604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 20 May 2020 10:29:24 +0200 Subject: [PATCH 307/453] [apps/calculation] additional_outputs: fix complex range for infinite values --- apps/calculation/additional_outputs/complex_model.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/calculation/additional_outputs/complex_model.cpp b/apps/calculation/additional_outputs/complex_model.cpp index 6d59f3810..5a2322415 100644 --- a/apps/calculation/additional_outputs/complex_model.cpp +++ b/apps/calculation/additional_outputs/complex_model.cpp @@ -17,10 +17,10 @@ float ComplexModel::rangeBound(float direction, bool horizontal) const { maxFactor = k_maxHorizontalMarginFactor; value = real(); } - if (std::isnan(value) || std::isinf(value) || value == 0.0f) { - return direction*maxFactor; - } float factor = direction*value >= 0.0f ? maxFactor : minFactor; + if (std::isnan(value) || std::isinf(value) || value == 0.0f) { + return direction*factor; + } return factor*value; } From b596488a01b3fd4e287e5b5c05985e35b03ea8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 20 May 2020 11:38:37 +0200 Subject: [PATCH 308/453] [poincare] Multiplication::shallowBeautify: removeUnit can only be called on reduced expression This fixes the following bug: input i+10*sqrt(i) --- poincare/src/multiplication.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 519d8c520..f8ffdb9e4 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -356,13 +356,15 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } Expression result; + Expression self = *this; // Step 2: Handle the units - Expression self = *this; - Expression units; - self = removeUnit(&units); + if (hasUnit()) { + Expression units; + self = deepReduce(reductionContext); // removeUnit has to be called on reduced expression + self = removeUnit(&units); - if (!units.isUninitialized()) { + assert(!units.isUninitialized()); ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion(); if (unitConversionMode == ExpressionNode::UnitConversion::Default) { /* Step 2a: Recognize derived units From 03367cfdf6fb8ce36d1f11e053b76cc50f8b302d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 20 May 2020 11:40:05 +0200 Subject: [PATCH 309/453] [poincare] Makefile: POINCARE_TREE_LOG is by set by default when DEBUG=1 --- poincare/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poincare/Makefile b/poincare/Makefile index 69dfcd8f5..1cf6c7752 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -184,6 +184,10 @@ tests_src += $(addprefix poincare/test/,\ simplification.cpp\ ) +ifeq ($(DEBUG),1) +POINCARE_TREE_LOG ?= 1 +endif + ifdef POINCARE_TREE_LOG SFLAGS += -DPOINCARE_TREE_LOG=1 endif From 691c6739afcc734f4e1a6d0c560f2a6efb5bec32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 May 2020 11:59:18 +0200 Subject: [PATCH 310/453] [apps/variable_box_controller] Fix loadCurrentVariablesInScript Scenario: write the script: def squares(): for i in range(660): forward(L)lo) Put the cursor right of "lo" and press backspace. --- apps/code/variable_box_controller.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d99e7aa9c..aba82d4a5 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -624,8 +624,13 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont * nameLength are temporary variables that will be overriden when the * lexer continues lexing or is destroyed. * This was found from stepping in the code and trying. */ + /* TODO: Try to understand what is happening with tokenInText and + * remove this trick.*/ + while (*tokenInText == ' ') { + tokenInText++; + } for (int i = 0; i < 3; i++) { - if (strncmp(tokenInText, name, nameLength) != 0) { + if (strncmp(tokenInText, name, nameLength) != 0 && tokenInText > scriptContent) { tokenInText--; } else { break; From a53379781fb10f6b67314668c77ab5f5e9941eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 09:49:53 +0200 Subject: [PATCH 311/453] [apps/shared] Fix comment --- apps/shared/zoom_parameter_controller.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/shared/zoom_parameter_controller.cpp b/apps/shared/zoom_parameter_controller.cpp index 55496dba4..5f45669fb 100644 --- a/apps/shared/zoom_parameter_controller.cpp +++ b/apps/shared/zoom_parameter_controller.cpp @@ -58,11 +58,9 @@ int ZoomParameterController::ContentView::numberOfSubviews() const { View * ZoomParameterController::ContentView::subviewAtIndex(int index) { assert(index >= 0 && index < 2); - /* The order of subview is important here : - * If we redraw the curveView before the legendView, that can have some display issue, when exiting sleep mode, which - can be visible, if the redraw of curveView is long (with complicated curve), so we prefer to have legendView - at first subview. - */ + /* The order of subviews matters here: redrawing curve view can be long and + * if it was redraw before the legend view, you could see noise when + * switching the device on and off. */ if (index == 0) { return &m_legendView; } From 79e7626dc3085299dc8c3c2ce35ddb4bb69186e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 09:58:42 +0200 Subject: [PATCH 312/453] [escher] LayoutField: the insertion cursor can't point to an EmptyLayout as it might be destroyed This fixes the following crash: input 1, OK, input ans/[], go up to the history --> crash --- escher/include/escher/layout_field.h | 6 +----- escher/src/layout_field.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/escher/include/escher/layout_field.h b/escher/include/escher/layout_field.h index 7476727d2..d8c4694b1 100644 --- a/escher/include/escher/layout_field.h +++ b/escher/include/escher/layout_field.h @@ -87,11 +87,7 @@ private: bool selectionIsEmpty() const; void deleteSelection(); void invalidateInsertionCursor() { m_insertionCursor = Poincare::LayoutCursor(); } - void updateInsertionCursor() { - if (!m_insertionCursor.isDefined()) { - m_insertionCursor = m_cursor; - } - } + void updateInsertionCursor(); private: int numberOfSubviews() const override { return 2; } diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 4575f5258..6df1de2f0 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -234,6 +235,17 @@ void LayoutField::ContentView::deleteSelection() { resetSelection(); } +void LayoutField::ContentView::updateInsertionCursor() { + if (!m_insertionCursor.isDefined()) { + Layout l = m_cursor.layout(); + if (l.type() == LayoutNode::Type::EmptyLayout && static_cast(l).color() == EmptyLayoutNode::Color::Grey) { + // Don't set m_insertionCursor pointing to a layout which might disappear + return; + } + m_insertionCursor = m_cursor; + } +} + View * LayoutField::ContentView::subviewAtIndex(int index) { assert(0 <= index && index < numberOfSubviews()); View * m_views[] = {&m_expressionView, &m_cursorView}; From 9a3e2c960f30090a6cf4f5b4f79de9808edc4f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 10:00:53 +0200 Subject: [PATCH 313/453] [escher] LayoutField: update the grey squares when using insertion cursor --- escher/src/layout_field.cpp | 2 ++ poincare/include/poincare/empty_layout.h | 1 + 2 files changed, 3 insertions(+) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 6df1de2f0..52f457e46 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -43,7 +43,9 @@ bool LayoutField::ContentView::setEditing(bool isEditing) { void LayoutField::ContentView::useInsertionCursor() { if (m_insertionCursor.isDefined()) { + m_cursor.layout().removeGreySquaresFromAllMatrixAncestors(); m_cursor = m_insertionCursor; + m_cursor.layout().addGreySquaresToAllMatrixAncestors(); } } diff --git a/poincare/include/poincare/empty_layout.h b/poincare/include/poincare/empty_layout.h index 14cd3bb15..8edb9c538 100644 --- a/poincare/include/poincare/empty_layout.h +++ b/poincare/include/poincare/empty_layout.h @@ -82,6 +82,7 @@ public: node()->setVisible(visible); } + EmptyLayoutNode::Color color() const { return node()->color(); } void setColor(EmptyLayoutNode::Color color) { node()->setColor(color); } From 80015ca6aa72e90259c9937bc4863010e30c475b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 14:31:26 +0200 Subject: [PATCH 314/453] [apps/shared] RoundCursorView: fix potential black trail when redrawing cursor (issue #1458 on GitHub) --- apps/shared/round_cursor_view.cpp | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/apps/shared/round_cursor_view.cpp b/apps/shared/round_cursor_view.cpp index 74661c644..e8bdd2051 100644 --- a/apps/shared/round_cursor_view.cpp +++ b/apps/shared/round_cursor_view.cpp @@ -68,37 +68,9 @@ bool RoundCursorView::eraseCursorIfPossible() { // Erase the cursor KDColor cursorWorkingBuffer[k_cursorSize * k_cursorSize]; KDContext * ctx = KDIonContext::sharedContext(); - ctx->setOrigin(currentFrame.origin()); + ctx->setOrigin(absoluteOrigin()); ctx->setClippingRect(currentFrame); KDSize cursorSize = KDSize(k_cursorSize, k_cursorSize); - - /* We assert that the visible frame is not cropped (indeed a cursor is always - * fully inside the window, thanks to panToMakeCursorVisible). Otherwise, we - * would need to change this algorithm. - * - * +---+ - * | |<- frame m_underneathPixelBuffer: +---+ - * +----+---+--------+ |000| - * | |xxx| |<- parentVisibleFrame |xxx| - * | +---+ | +---+ - * | | - * +-----------------+ - * - * +---+ - * |xxx|: absoluteVisibleFrame - * +---+ - * - * What we would draw with the current algorithm: - * +---+ - * | |<- frame - * +----+---+--------+ - * | |000| |<- parentVisibleFrame - * | +---+ | - * | | - * +-----------------+ - * - * */ - assert(currentFrame.size() == cursorSize); ctx->fillRectWithPixels(KDRect(0, 0, cursorSize), m_underneathPixelBuffer, cursorWorkingBuffer); // TODO Restore the context to previous values? return true; From 5725ba1c1499efd1e989e2d8fb99bf66f020b879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 16:01:41 +0200 Subject: [PATCH 315/453] [escher] LayoutField: reset selection when clearing layout --- escher/src/layout_field.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 52f457e46..4a8a58197 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -52,6 +52,7 @@ void LayoutField::ContentView::useInsertionCursor() { void LayoutField::ContentView::clearLayout() { HorizontalLayout h = HorizontalLayout::Builder(); if (m_expressionView.setLayout(h)) { + resetSelection(); m_cursor.setLayout(h); } } From 5aaa6723d05e39a38a7462d727dc9758e1c2f711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 22 May 2020 16:39:34 +0200 Subject: [PATCH 316/453] [apps/calculation] Fix duplicate removal in unit additional results This fixes the following bug: input _ns, go to additional results --> crash --- .../additional_outputs/unit_list_controller.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index d961cc5f4..5f15c86a5 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -106,6 +106,7 @@ void UnitListController::setExpression(Poincare::Expression e) { Shared::PoincareHelpers::Simplify(&reduceExpression, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::None); currentExpressionIndex = 1; while (currentExpressionIndex < numberOfMemoizedExpressions) { + bool duplicateFound = false; for (size_t i = 0; i < currentExpressionIndex + 1; i++) { // Compare the currentExpression to all previous memoized expressions and to m_expression Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : m_memoizedExpressions[i]; @@ -118,12 +119,15 @@ void UnitListController::setExpression(Poincare::Expression e) { } // Remove last expression m_memoizedExpressions[numberOfMemoizedExpressions] = Expression(); - // The current expression has been discarded, no need to increment thre current index - continue; + // The current expression has been discarded, no need to increment the current index + duplicateFound = true; + break; } } - // The current expression is not a duplicate, check next expression - currentExpressionIndex++; + if (!duplicateFound) { + // The current expression is not a duplicate, check next expression + currentExpressionIndex++; + } } } From 273d10dc2690ae0898eed0fccba998995ed000b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 15 May 2020 15:26:47 +0200 Subject: [PATCH 317/453] [python] Change names: ColorParse::ParseColor --> Color::Parse --- python/port/mod/kandinsky/modkandinsky.cpp | 10 ++--- python/port/mod/turtle/modturtle.cpp | 10 ++--- python/port/mod/turtle/turtle.h | 8 ++-- python/port/port.cpp | 44 +++++++++++----------- python/port/port.h | 23 ++++++----- 5 files changed, 47 insertions(+), 48 deletions(-) diff --git a/python/port/mod/kandinsky/modkandinsky.cpp b/python/port/mod/kandinsky/modkandinsky.cpp index 97b070e51..cf1b326d3 100644 --- a/python/port/mod/kandinsky/modkandinsky.cpp +++ b/python/port/mod/kandinsky/modkandinsky.cpp @@ -31,7 +31,7 @@ mp_obj_t modkandinsky_color(size_t n_args, const mp_obj_t *args) { assert(n_args == 3); color = mp_obj_new_tuple(n_args, args); } - return TupleForKDColor(MicroPython::ColorParser::ParseColor(color)); + return TupleForKDColor(MicroPython::Color::Parse(color)); } /* Calling ExecutionEnvironment::displaySandbox() hides the console and switches @@ -48,7 +48,7 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y) { mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t input) { KDPoint point(mp_obj_get_int(x), mp_obj_get_int(y)); - KDColor kdColor = MicroPython::ColorParser::ParseColor(input); + KDColor kdColor = MicroPython::Color::Parse(input); MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->setPixel(point, kdColor); return mp_const_none; @@ -58,8 +58,8 @@ mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t input) { mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t * args) { const char * text = mp_obj_str_get_str(args[0]); KDPoint point(mp_obj_get_int(args[1]), mp_obj_get_int(args[2])); - KDColor textColor = (n_args >= 4) ? MicroPython::ColorParser::ParseColor(args[3]) : KDColorBlack; - KDColor backgroundColor = (n_args >= 5) ? MicroPython::ColorParser::ParseColor(args[4]) : KDColorWhite; + KDColor textColor = (n_args >= 4) ? MicroPython::Color::Parse(args[3]) : KDColorBlack; + KDColor backgroundColor = (n_args >= 5) ? MicroPython::Color::Parse(args[4]) : KDColorWhite; MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, textColor, backgroundColor); /* Before and after execution of "modkandinsky_draw_string", @@ -89,7 +89,7 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) { y = y - height; } KDRect rect(x, y, width, height); - KDColor color = MicroPython::ColorParser::ParseColor(args[4]); + KDColor color = MicroPython::Color::Parse(args[4]); MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->fillRect(rect, color); // Cf comment on modkandinsky_draw_string diff --git a/python/port/mod/turtle/modturtle.cpp b/python/port/mod/turtle/modturtle.cpp index e6bafba70..4d48fe17b 100644 --- a/python/port/mod/turtle/modturtle.cpp +++ b/python/port/mod/turtle/modturtle.cpp @@ -139,7 +139,7 @@ mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) { // pencolor() KDColor c = sTurtle.color(); mp_obj_t mp_col[3]; - if(sTurtle.colorMode() == MicroPython::ColorParser::ColorMode::MaxIntensity255){ + if(sTurtle.colorMode() == MicroPython::Color::Mode::MaxIntensity255){ mp_col[0] = mp_obj_new_int_from_uint(c.red()); mp_col[1] = mp_obj_new_int_from_uint(c.green()); mp_col[2] = mp_obj_new_int_from_uint(c.blue()); @@ -161,7 +161,7 @@ mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) { assert(n_args == 3); color = mp_obj_new_tuple(n_args, args); } - sTurtle.setColor(MicroPython::ColorParser::ParseColor(color, sTurtle.colorMode())); + sTurtle.setColor(MicroPython::Color::Parse(color, sTurtle.colorMode())); return mp_const_none; } @@ -170,12 +170,12 @@ mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int_from_uint(static_cast(sTurtle.colorMode())); } else{ int colorMode = mp_obj_get_int(args[0]); - if (colorMode != static_cast(MicroPython::ColorParser::ColorMode::MaxIntensity1) && - colorMode != static_cast(MicroPython::ColorParser::ColorMode::MaxIntensity255)) { + if (colorMode != static_cast(MicroPython::Color::Mode::MaxIntensity1) && + colorMode != static_cast(MicroPython::Color::Mode::MaxIntensity255)) { mp_raise_ValueError("Colormode can be 1 or 255"); return mp_const_none; } - sTurtle.setColorMode(static_cast(colorMode)); + sTurtle.setColorMode(static_cast(colorMode)); return mp_const_none; } } diff --git a/python/port/mod/turtle/turtle.h b/python/port/mod/turtle/turtle.h index 2c49c6b1d..55a1c5e3c 100644 --- a/python/port/mod/turtle/turtle.h +++ b/python/port/mod/turtle/turtle.h @@ -30,7 +30,7 @@ public: m_y(0), m_heading(0), m_color(k_defaultColor), - m_colorMode(MicroPython::ColorParser::ColorMode::MaxIntensity255), + m_colorMode(MicroPython::Color::Mode::MaxIntensity255), m_penDown(true), m_visible(true), m_speed(k_defaultSpeed), @@ -73,8 +73,8 @@ public: void setColor(uint8_t r, uint8_t g, uint8_t b) { m_color = KDColor::RGB888(r, g, b); } - MicroPython::ColorParser::ColorMode colorMode() const {return m_colorMode; } - void setColorMode(MicroPython::ColorParser::ColorMode colorMode){ + MicroPython::Color::Mode colorMode() const {return m_colorMode; } + void setColorMode(MicroPython::Color::Mode colorMode){ m_colorMode = colorMode; } @@ -141,7 +141,7 @@ private: mp_float_t m_heading; KDColor m_color; - MicroPython::ColorParser::ColorMode m_colorMode; + MicroPython::Color::Mode m_colorMode; bool m_penDown; bool m_visible; diff --git a/python/port/port.cpp b/python/port/port.cpp index 0a2ebc4b7..e4dae7789 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -179,32 +179,32 @@ void MicroPython::collectRootsAtAddress(char * address, int byteLength) { gc_collect_root((void **)alignedAddress, byteLength / sizeof(uintptr_t)); } -KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorMode ColorMode){ - static constexpr int maxColorIntensity = static_cast(ColorMode::MaxIntensity255); +KDColor MicroPython::Color::Parse(mp_obj_t input, Mode mode){ + static constexpr int maxColorIntensity = static_cast(Mode::MaxIntensity255); if (mp_obj_is_str(input)) { size_t l; const char * color = mp_obj_str_get_data(input, &l); // TODO add cyan - constexpr NameColorPair pairs[] = { - NameColorPair("blue", KDColorBlue), - NameColorPair("b", KDColorBlue), - NameColorPair("red", KDColorRed), - NameColorPair("r", KDColorRed), - NameColorPair("green", Palette::Green), - NameColorPair("g", Palette::Green), - NameColorPair("yellow", KDColorYellow), - NameColorPair("y", KDColorYellow), - NameColorPair("brown", Palette::Brown), - NameColorPair("black", KDColorBlack), - NameColorPair("k", KDColorBlack), - NameColorPair("white", KDColorWhite), - NameColorPair("w", KDColorWhite), - NameColorPair("pink", Palette::Pink), - NameColorPair("orange", Palette::Orange), - NameColorPair("purple", Palette::Purple), - NameColorPair("grey", Palette::GreyDark) + constexpr NamedColor pairs[] = { + NamedColor("blue", KDColorBlue), + NamedColor("b", KDColorBlue), + NamedColor("red", KDColorRed), + NamedColor("r", KDColorRed), + NamedColor("green", Palette::Green), + NamedColor("g", Palette::Green), + NamedColor("yellow", KDColorYellow), + NamedColor("y", KDColorYellow), + NamedColor("brown", Palette::Brown), + NamedColor("black", KDColorBlack), + NamedColor("k", KDColorBlack), + NamedColor("white", KDColorWhite), + NamedColor("w", KDColorWhite), + NamedColor("pink", Palette::Pink), + NamedColor("orange", Palette::Orange), + NamedColor("purple", Palette::Purple), + NamedColor("grey", Palette::GreyDark) }; - for (NameColorPair p : pairs) { + for (NamedColor p : pairs) { if (strcmp(p.name(), color) == 0) { return p.color(); } @@ -237,7 +237,7 @@ KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorMode ColorMode if (len != 3) { mp_raise_TypeError("Color needs 3 components"); } - int intensityFactor = maxColorIntensity/static_cast(ColorMode); + int intensityFactor = maxColorIntensity/static_cast(mode); return KDColor::RGB888( intensityFactor * mp_obj_get_float(elem[0]), intensityFactor * mp_obj_get_float(elem[1]), diff --git a/python/port/port.h b/python/port/port.h index 3cef6ec0a..24a7524bd 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -42,11 +42,18 @@ void deinit(); void registerScriptProvider(ScriptProvider * s); void collectRootsAtAddress(char * address, int len); -class ColorParser { - private: - class NameColorPair { +class Color { +public: + enum class Mode { + MaxIntensity1 = 1, + MaxIntensity255 = 255, + }; + + static KDColor Parse(mp_obj_t input, Mode Mode = Mode::MaxIntensity255); +private: + class NamedColor { public: - constexpr NameColorPair(const char * name, KDColor color) : + constexpr NamedColor(const char * name, KDColor color) : m_name(name), m_color(color) {} @@ -56,14 +63,6 @@ class ColorParser { const char * m_name; KDColor m_color; }; - - public: - enum class ColorMode { - MaxIntensity1 = 1, - MaxIntensity255 = 255, - }; - - static KDColor ParseColor(mp_obj_t input, ColorMode ColorMode = ColorMode::MaxIntensity255); }; From a22990943bdb1fbc9906564c4b5a1f52ead62f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 18 May 2020 10:48:31 +0200 Subject: [PATCH 318/453] [python] matplotlib: missing static keyword --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 4381c2520..e6a78d470 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -42,7 +42,7 @@ static size_t extractArgumentsAndCheckEqualSize(mp_obj_t x, mp_obj_t y, mp_obj_t * - of the required size */ -size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength, mp_obj_t ** items) { +static size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength, mp_obj_t ** items) { size_t itemLength = extractArgument(arg, items); if (itemLength > 1 && requiredlength > 1 && itemLength != requiredlength) { mp_raise_ValueError("shape mismatch"); From e2c06cbb446146f7d8df248a6d0f4025da76eb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 18 May 2020 10:50:12 +0200 Subject: [PATCH 319/453] [python] matplotlib: add color argument to plot, scatter, hist, bar and arrow --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 39 ++++++++++++------- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- .../mod/matplotlib/pyplot/modpyplot_table.c | 10 ++--- python/test/matplotlib.cpp | 5 +++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index e6a78d470..196e715b6 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -50,6 +50,16 @@ static size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength return itemLength; } +// Get color from arguments if possible + +KDColor colorFromOptionalArgumentAtIndex(size_t n_args, const mp_obj_t * args, size_t colorIndex) { + if (n_args > colorIndex) { + return MicroPython::Color::Parse(args[colorIndex]); + } else { + return Palette::nextDataColor(&paletteIndex); + } +} + // Internal functions mp_obj_t modpyplot___init__() { @@ -79,15 +89,15 @@ void modpyplot_flush_used_heap() { } } -/* arrow(x,y,dx,dy) +/* arrow(x,y,dx,dy, color) * x, y, dx, dy scalars * */ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { - assert(n_args == 4); + assert(n_args >= 4); assert(sPlotStore != nullptr); - KDColor color = Palette::nextDataColor(&paletteIndex); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 4); sPlotStore->addSegment(args[0], args[1], mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[0]), args[2]), mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[1]), args[3]), color, true); return mp_const_none; } @@ -143,7 +153,7 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(4, coords); } -/* bar(x, height, width, bottom) +/* bar(x, height, width, bottom, color) * 'x', 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of * scalar. * 'width' default value is 0.8 @@ -184,7 +194,7 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { bItems[0] = mp_obj_new_float(0.0f); } - KDColor color = Palette::nextDataColor(&paletteIndex); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 4); for (size_t i=0; i 1 ? i : 0]; mp_obj_t iW = wItems[wLength > 1 ? i : 0]; @@ -219,7 +229,7 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -/* hist(x, bins) +/* hist(x, bins, color) * 'x' array * 'bins': (default value 10) * - int (number of bins) @@ -298,25 +308,26 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { binIndex++; } - KDColor color = Palette::nextDataColor(&paletteIndex); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); for (size_t i=0; iaddRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); } return mp_const_none; } -/* scatter(x, y) +/* scatter(x, y, color) * - x, y: list * - x, y: scalar * */ -mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { +mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); mp_obj_t * xItems, * yItems; - size_t length = extractArgumentsAndCheckEqualSize(x, y, &xItems, &yItems); + assert(n_args >= 2); + size_t length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); - KDColor color = Palette::nextDataColor(&paletteIndex); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); for (size_t i=0; iaddDot(xItems[i], yItems[i], color); } @@ -324,7 +335,7 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { return mp_const_none; } -/* plot(x, y) plots the curve (x, y) +/* plot(x, y) plots the curve (x, y, color) * plot(y) plots the curve x as index array ([0,1,2...],y) * */ @@ -342,11 +353,11 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { xItems[i] = mp_obj_new_float((float)i); } } else { - assert(n_args == 2); + assert(n_args >= 2); length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); } - KDColor color = Palette::nextDataColor(&paletteIndex); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); for (int i=0; i<(int)length-1; i++) { sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false); } diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index 8ab760f73..a32e0905e 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -10,6 +10,6 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); +mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index 1f4c3152b..78b7f5d2f 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -1,13 +1,13 @@ #include "modpyplot.h" STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 5, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 5, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 2, modpyplot_hist); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 2, modpyplot_plot); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 3, modpyplot_hist); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 3, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_scatter_obj, 2, 3, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); diff --git a/python/test/matplotlib.cpp b/python/test/matplotlib.cpp index b673d63ca..60b642ff0 100644 --- a/python/test/matplotlib.cpp +++ b/python/test/matplotlib.cpp @@ -35,6 +35,7 @@ QUIZ_CASE(python_matplotlib_pyplot_arrow) { TestExecutionEnvironment env = init_environement(); assert_command_execution_succeeds(env, "from matplotlib.pyplot import *"); assert_command_execution_succeeds(env, "arrow(2,3,4,5)"); + assert_command_execution_succeeds(env, "arrow(2,3,4,5, \"#FF00FF\")"); assert_command_execution_succeeds(env, "show()"); deinit_environment(); } @@ -59,6 +60,7 @@ QUIZ_CASE(python_matplotlib_pyplot_bar) { assert_command_execution_succeeds(env, "bar([],[])"); assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],2,3)"); assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],[1,2,3],[1,2,3])"); + assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],[1,2,3],[1,2,3], \"orange\")"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "bar([1,2,3],[1,2,3,4],[1,2,3],[1,2,3])"); deinit_environment(); @@ -79,6 +81,7 @@ QUIZ_CASE(python_matplotlib_pyplot_hist) { assert_command_execution_succeeds(env, "hist([2,3,4,5,6],23)"); assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3])"); assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3, 4,5,6,7])"); + assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3, 4,5,6,7], (0,255,0))"); assert_command_execution_succeeds(env, "show()"); deinit_environment(); } @@ -89,6 +92,7 @@ QUIZ_CASE(python_matplotlib_pyplot_plot) { assert_command_execution_succeeds(env, "plot([2,3,4,5,6])"); assert_command_execution_succeeds(env, "plot(2,3)"); assert_command_execution_succeeds(env, "plot([2,3,4,5,6],[3,4,5,6,7])"); + assert_command_execution_succeeds(env, "plot([2,3,4,5,6],[3,4,5,6,7], \"g\")"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "plot([2,3,4,5,6],2)"); deinit_environment(); @@ -99,6 +103,7 @@ QUIZ_CASE(python_matplotlib_pyplot_scatter) { assert_command_execution_succeeds(env, "from matplotlib.pyplot import *"); assert_command_execution_succeeds(env, "scatter(2,3)"); assert_command_execution_succeeds(env, "scatter([2,3,4,5,6],[3,4,5,6,7])"); + assert_command_execution_succeeds(env, "scatter([2,3,4,5,6],[3,4,5,6,7], (0,0,255))"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "scatter([2,3,4,5,6],2)"); deinit_environment(); From e92b56b78e3467a503fc9adad5640378b9c8d552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 18 May 2020 11:12:10 +0200 Subject: [PATCH 320/453] [apps/shared] CurveView: change drawArrow arguments (new definition of arrow shape) --- apps/shared/curve_view.cpp | 11 +++++------ apps/shared/curve_view.h | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index d8776179d..8871064d0 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -449,7 +449,7 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor } -void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength, float angle) const { +void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowWith, float tanAngle) const { /* Let's call the following variables L and l: * * / | @@ -467,13 +467,12 @@ void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float * ----- L ----- * **/ - assert(angle >= 0.0f); + assert(tanAngle >= 0.0f); if (std::fabs(dx) < FLT_EPSILON && std::fabs(dy) < FLT_EPSILON) { // We can't draw an arrow without any orientation return; } - /* We compute the arrow segments in pixels in order to correctly size the - * arrow without depending on the displayed range. + /* We compute the arrow segments in pixels * Warning: the computed values are relative so we need to add/subtract the * pixel position of 0s. */ float x0Pixel = floatToPixel(Axis::Horizontal, 0.0f); @@ -481,8 +480,8 @@ void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float float dxPixel = floatToPixel(Axis::Horizontal, dx) - x0Pixel; float dyPixel = y0Pixel - floatToPixel(Axis::Vertical, dy); float dx2dy2 = std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel); - float L = pixelArrowLength; - float l = angle*L; + float l = pixelArrowWith; + float L = l/tanAngle; float arrow1dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 + l*dyPixel/dx2dy2); float arrow1dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 - l*dxPixel/dx2dy2)); diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 9470aad49..f4ba889a7 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -78,15 +78,15 @@ protected: /* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the * orientation (dx,dy). * The parameters defining the shape of the arrow are the length in pixel of - * the projection of the arrow on the segment -'pixelArrowLength'- and the - * tangent of the angle between the segment and each wing of the arrow called - * 'angle'. + * half the base of the arrow triangle - 'pixelArrowWith' - and the tangent + * of the angle between the segment and each wing of the arrow called + * 'tanAngle'. * * / | * / | - * / L - * / | - * / | + * / l + * / \ | + * / \ angle | * <-------------------------------------------------- * \ * \ @@ -94,12 +94,12 @@ protected: * \ * \ * - * <--- pl ---> + * <--- L ---> * - * pl = pixelArrowLength - * tan(angle) = L/pl + * l = pixelArrowWith + * tanAngle = tan(angle) = l/L */ - void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength = 10, float angle = 0.4f) const; + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowWith = 4, float tanAngle = 0.4f) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; From 0f8f82b94b7d3766e042fa62f35d436cd2ec51dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 09:32:35 +0200 Subject: [PATCH 321/453] [python] matplotlib: Add a parameter to to arrow to set the arrow width --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 12 ++++++++---- python/port/mod/matplotlib/pyplot/plot_store.cpp | 6 +++--- python/port/mod/matplotlib/pyplot/plot_store.h | 6 +++--- python/port/mod/matplotlib/pyplot/plot_view.cpp | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 196e715b6..079a05641 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -89,16 +89,20 @@ void modpyplot_flush_used_heap() { } } -/* arrow(x,y,dx,dy, color) +/* arrow(x,y,dx,dy, head_width, color) * x, y, dx, dy scalars * */ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(n_args >= 4); assert(sPlotStore != nullptr); + mp_obj_t arrowWidth = mp_obj_new_float(0.003); // Default value + if (n_args >= 5) { + arrowWidth = args[4]; + } - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 4); - sPlotStore->addSegment(args[0], args[1], mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[0]), args[2]), mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[1]), args[3]), color, true); + KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 5); + sPlotStore->addSegment(args[0], args[1], mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[0]), args[2]), mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[1]), args[3]), color, arrowWidth); return mp_const_none; } @@ -359,7 +363,7 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); for (int i=0; i<(int)length-1; i++) { - sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false); + sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); } return mp_const_none; diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index de5996894..c34c5c2d3 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -104,12 +104,12 @@ PlotStore::Segment::Segment(mp_obj_t tuple) { m_xEnd = mp_obj_get_float(elements[2]); m_yEnd = mp_obj_get_float(elements[3]); m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); - m_arrow = elements[5] == mp_const_true; + m_arrowWidth = mp_obj_get_float(elements[5]); } -void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge) { +void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth) { mp_obj_t color = mp_obj_new_int(c); - mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowEdge ? mp_const_true : mp_const_false}; + mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowWidth}; checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(6, items); mp_obj_list_append(m_segments, tuple); diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index d74b60cb0..d50f6a170 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -68,18 +68,18 @@ public: float yStart() const { return m_yStart; } float xEnd() const { return m_xEnd; } float yEnd() const { return m_yEnd; } - bool isArrow() const { return m_arrow; } + float arrowWidth() const { return m_arrowWidth; } KDColor color() const { return m_color; } private: float m_xStart; float m_yStart; float m_xEnd; float m_yEnd; - bool m_arrow; + float m_arrowWidth; KDColor m_color; }; - void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge); + void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth = mp_obj_new_float(0.0)); Iterable> segments() { return Iterable>(m_segments); } // Rect diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index 4da55f8cf..ba1d84bb5 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -46,7 +46,7 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen segment.xEnd(), segment.yEnd(), segment.color() ); - if (segment.isArrow()) { + if (segment.arrowWidth() > 0.0f) { float dx = segment.xEnd() - segment.xStart(); float dy = segment.yEnd() - segment.yStart(); drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color()); From c826c53659bd88d003549fba94e8bac3ab6026d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 10:39:45 +0200 Subject: [PATCH 322/453] [apps/shared] CurveView: change drawArrow API to take arrow shape arguments in float instead of coordinates --- apps/shared/curve_view.cpp | 21 +++++++-------------- apps/shared/curve_view.h | 25 ++++++++++++------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 8871064d0..13c33c7d2 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -449,7 +449,7 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor } -void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowWith, float tanAngle) const { +void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWidth, float tanAngle) const { /* Let's call the following variables L and l: * * / | @@ -472,23 +472,16 @@ void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float // We can't draw an arrow without any orientation return; } - /* We compute the arrow segments in pixels - * Warning: the computed values are relative so we need to add/subtract the - * pixel position of 0s. */ - float x0Pixel = floatToPixel(Axis::Horizontal, 0.0f); - float y0Pixel = floatToPixel(Axis::Vertical, 0.0f); - float dxPixel = floatToPixel(Axis::Horizontal, dx) - x0Pixel; - float dyPixel = y0Pixel - floatToPixel(Axis::Vertical, dy); - float dx2dy2 = std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel); - float l = pixelArrowWith; + float l = arrowWidth/2.0f; float L = l/tanAngle; + float dx2dy2 = std::sqrt(dx*dx+dy*dy); - float arrow1dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 + l*dyPixel/dx2dy2); - float arrow1dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 - l*dxPixel/dx2dy2)); + float arrow1dx = L*dx/dx2dy2 + l*dy/dx2dy2; + float arrow1dy = L*dy/dx2dy2 - l*dx/dx2dy2; drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false); - float arrow2dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 - l*dyPixel/dx2dy2); - float arrow2dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 + l*dxPixel/dx2dy2)); + float arrow2dx = L*dx/dx2dy2 - l*dy/dx2dy2; + float arrow2dy = L*dy/dx2dy2 + l*dx/dx2dy2; drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false); } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index f4ba889a7..ae23f1818 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -77,29 +77,28 @@ protected: void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const; /* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the * orientation (dx,dy). - * The parameters defining the shape of the arrow are the length in pixel of - * half the base of the arrow triangle - 'pixelArrowWith' - and the tangent - * of the angle between the segment and each wing of the arrow called - * 'tanAngle'. + * The parameters defining the shape of the arrow are the length of the base + * of the arrow triangle - 'arrowWith' - and the tangent of the angle between + * the segment and each wing of the arrow called 'tanAngle'. * * / | * / | - * / l + * / | * / \ | * / \ angle | - * <-------------------------------------------------- - * \ - * \ - * \ - * \ - * \ + * <----------------------------l--------------------- + * \ | + * \ | + * \ | + * \ | + * \ | * * <--- L ---> * - * l = pixelArrowWith + * l = arrowWith * tanAngle = tan(angle) = l/L */ - void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowWith = 4, float tanAngle = 0.4f) const; + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith = 4, float tanAngle = 0.4f) const; // 0.3639 = tan(20°) void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; From 083f959b7be114e0e2e02680209ddbd8807d6209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 10:40:43 +0200 Subject: [PATCH 323/453] [python] matplotlib: Enable to change the arrow shape via the head_width arg --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index ba1d84bb5..48100bec6 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -49,7 +49,7 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen if (segment.arrowWidth() > 0.0f) { float dx = segment.xEnd() - segment.xStart(); float dy = segment.yEnd() - segment.yStart(); - drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color()); + drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color(), segment.arrowWidth()); } } From 12db7a5093ae4a3d9aaa57c53e25aef924eefb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 10:58:34 +0200 Subject: [PATCH 324/453] [apps/shared] Change default shape of arrow in CurveView (to match matplotlib shape) --- apps/shared/curve_view.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index ae23f1818..4f8da4eff 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -96,9 +96,10 @@ protected: * <--- L ---> * * l = arrowWith - * tanAngle = tan(angle) = l/L + * tanAngle = tan(angle) = l/2L */ - void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith = 4, float tanAngle = 0.4f) const; // 0.3639 = tan(20°) + + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith = 4, float tanAngle = 1.0f/3.0f) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; From 9b7c47a7f03f67175663f68471eb27e8a0d0524a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 11:08:47 +0200 Subject: [PATCH 325/453] [python] matplotlib: arrow can have up to 6 args --- python/port/mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index 78b7f5d2f..c841bf284 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -1,7 +1,7 @@ #include "modpyplot.h" STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 5, modpyplot_arrow); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 6, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 5, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); From 0c9fb57b33878b1b785959c161383da9c38e23a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 11:09:08 +0200 Subject: [PATCH 326/453] [python] matplotlib: check float type of the head_width arg of arrow function --- python/port/mod/matplotlib/pyplot/plot_store.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index c34c5c2d3..023cd3461 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -103,14 +103,14 @@ PlotStore::Segment::Segment(mp_obj_t tuple) { m_yStart = mp_obj_get_float(elements[1]); m_xEnd = mp_obj_get_float(elements[2]); m_yEnd = mp_obj_get_float(elements[3]); - m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); - m_arrowWidth = mp_obj_get_float(elements[5]); + m_arrowWidth = mp_obj_get_float(elements[4]); + m_color = KDColor::RGB16(mp_obj_get_int(elements[5])); } void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth) { mp_obj_t color = mp_obj_new_int(c); - mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowWidth}; - checkFloatType(items, 4); + mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, arrowWidth, color}; + checkFloatType(items, 5); mp_obj_t tuple = mp_obj_new_tuple(6, items); mp_obj_list_append(m_segments, tuple); } From d8666a52d39b32346eebda640576753c12df94bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 11:09:53 +0200 Subject: [PATCH 327/453] [python] matplotlib: fix tests about arrow function --- python/test/matplotlib.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/test/matplotlib.cpp b/python/test/matplotlib.cpp index 60b642ff0..dbb2dde49 100644 --- a/python/test/matplotlib.cpp +++ b/python/test/matplotlib.cpp @@ -35,7 +35,9 @@ QUIZ_CASE(python_matplotlib_pyplot_arrow) { TestExecutionEnvironment env = init_environement(); assert_command_execution_succeeds(env, "from matplotlib.pyplot import *"); assert_command_execution_succeeds(env, "arrow(2,3,4,5)"); - assert_command_execution_succeeds(env, "arrow(2,3,4,5, \"#FF00FF\")"); + assert_command_execution_succeeds(env, "arrow(2,3,4,5, 0.1)"); + assert_command_execution_fails(env, "arrow(2,3,4,5, \"width\")"); + assert_command_execution_succeeds(env, "arrow(2,3,4,5, 0.1, \"#FF00FF\")"); assert_command_execution_succeeds(env, "show()"); deinit_environment(); } From 13d0bcf6762e4b171ffe3b5e6817e2cf2656c746 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 19 May 2020 10:16:38 +0200 Subject: [PATCH 328/453] [matplotlib] Modified isEmpty method for showing axis Added a condition for being considered empty. Allows axis("on") or axis((0,1,2,3)) to display something with show() This behavior is the same as the python module Change-Id: If5f3b07c280ee9ead2bc23d23cbbb4f01da7eae5 --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 18 ++++++++++-------- .../port/mod/matplotlib/pyplot/plot_store.cpp | 7 ++----- python/port/mod/matplotlib/pyplot/plot_store.h | 4 +++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 079a05641..5667d9f38 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -96,6 +96,7 @@ void modpyplot_flush_used_heap() { mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(n_args >= 4); assert(sPlotStore != nullptr); + sPlotStore->setShow(true); mp_obj_t arrowWidth = mp_obj_new_float(0.003); // Default value if (n_args >= 5) { arrowWidth = args[4]; @@ -114,7 +115,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); if (n_args == 1) { mp_obj_t arg = args[0]; if (mp_obj_is_str(arg)) { @@ -168,7 +169,7 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); mp_obj_t * xItems; mp_obj_t * hItems; mp_obj_t * wItems; @@ -223,7 +224,7 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); if (n_args == 0) { // Toggle the grid visibility sPlotStore->setGridRequested(!sPlotStore->gridRequested()); @@ -242,7 +243,7 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); // Sort data to easily get the minimal and maximal value and count bin sizes mp_obj_t * xItems; size_t xLength = extractArgument(args[0], &xItems); @@ -326,7 +327,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; assert(n_args >= 2); size_t length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); @@ -345,7 +346,7 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; size_t length; if (n_args == 1) { @@ -371,7 +372,7 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) { assert(sPlotStore != nullptr); - + sPlotStore->setShow(true); // Input parameter validation mp_obj_get_float(x); mp_obj_get_float(y); @@ -383,10 +384,11 @@ mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) { } mp_obj_t modpyplot_show() { - if (sPlotStore->isEmpty()) { + if (!sPlotStore->show()) { return mp_const_none; } MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); env->displayViewController(sPlotController); + sPlotStore->setShow(false); return mp_const_none; } diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 023cd3461..e600e3150 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -6,7 +6,8 @@ namespace Matplotlib { PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), m_axesRequested(true), m_axesAuto(true), - m_gridRequested(false) + m_gridRequested(false), + m_show(false) { flush(); } @@ -21,10 +22,6 @@ void PlotStore::flush() { m_gridRequested = false; } -bool PlotStore::isEmpty() { - return MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_dots)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_segments)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_rects)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_labels)) == 0; -} - // Iterators template diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index d50f6a170..2dfda039e 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -13,7 +13,6 @@ class PlotStore : public Shared::InteractiveCurveViewRange { public: PlotStore(); void flush(); - bool isEmpty(); // Iterators @@ -123,6 +122,8 @@ public: void setAxesRequested(bool b) { m_axesRequested = b; } bool axesRequested() const { return m_axesRequested; } void setAxesAuto(bool b) { m_axesAuto = b; } + void setShow(bool b) { m_show = b; } + bool show() { return m_show; } void initRange(); void setGridRequested(bool b) { m_gridRequested = b; } @@ -135,6 +136,7 @@ private: bool m_axesRequested; bool m_axesAuto; bool m_gridRequested; + bool m_show; }; } From 7cd0b7e0e0795190699a4924d2ee7ffbf15e4713 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 19 May 2020 11:15:19 +0200 Subject: [PATCH 329/453] [matplotlib] Removed useless initializers in PlotStore constructor Change-Id: Idea0ce07cbc800139539f9d3fb27811920645184 --- python/port/mod/matplotlib/pyplot/plot_store.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index e600e3150..931aa3c29 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -4,9 +4,6 @@ namespace Matplotlib { PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), - m_axesRequested(true), - m_axesAuto(true), - m_gridRequested(false), m_show(false) { flush(); From fe7c4b1a8a8886f1f830f1bf92350c43b7167873 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 19 May 2020 17:48:37 +0200 Subject: [PATCH 330/453] [python/turtle] Added write method Allows user to print strings with the turtle Change-Id: I06a3832f6fa36d29506be10c48a1b2fb34cb69fb --- python/port/mod/turtle/modturtle.cpp | 6 ++++++ python/port/mod/turtle/modturtle.h | 1 + python/port/mod/turtle/modturtle_table.c | 2 ++ python/port/mod/turtle/turtle.cpp | 15 +++++++++++++++ python/port/mod/turtle/turtle.h | 3 +++ 5 files changed, 27 insertions(+) diff --git a/python/port/mod/turtle/modturtle.cpp b/python/port/mod/turtle/modturtle.cpp index 4d48fe17b..b8d4d1de8 100644 --- a/python/port/mod/turtle/modturtle.cpp +++ b/python/port/mod/turtle/modturtle.cpp @@ -193,3 +193,9 @@ mp_obj_t modturtle_hideturtle() { mp_obj_t modturtle_isvisible() { return sTurtle.isVisible() ? mp_const_true : mp_const_false; } + +mp_obj_t modturtle_write(mp_obj_t s) { + const char * string = mp_obj_str_get_str(s); + sTurtle.write(string); + return mp_const_none; +} \ No newline at end of file diff --git a/python/port/mod/turtle/modturtle.h b/python/port/mod/turtle/modturtle.h index 303ea13d4..363a6a47d 100644 --- a/python/port/mod/turtle/modturtle.h +++ b/python/port/mod/turtle/modturtle.h @@ -23,6 +23,7 @@ mp_obj_t modturtle_penup(); mp_obj_t modturtle_isdown(); mp_obj_t modturtle_pensize(size_t n_args, const mp_obj_t *args); mp_obj_t modturtle_isvisible(); +mp_obj_t modturtle_write(mp_obj_t s); mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args); mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args); diff --git a/python/port/mod/turtle/modturtle_table.c b/python/port/mod/turtle/modturtle_table.c index c190cc540..ccadb1de1 100644 --- a/python/port/mod/turtle/modturtle_table.c +++ b/python/port/mod/turtle/modturtle_table.c @@ -25,6 +25,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_reset_obj, modturtle_reset); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_showturtle_obj, modturtle_showturtle); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_hideturtle_obj, modturtle_hideturtle); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_isvisible_obj, modturtle_isvisible); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modturtle_write_obj, modturtle_write); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle___init___obj, modturtle___init__); @@ -74,6 +75,7 @@ STATIC const mp_rom_map_elem_t modturtle_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hideturtle), (mp_obj_t)&modturtle_hideturtle_obj }, { MP_ROM_QSTR(MP_QSTR_ht), (mp_obj_t)&modturtle_hideturtle_obj }, { MP_ROM_QSTR(MP_QSTR_isvisible), (mp_obj_t)&modturtle_isvisible_obj }, + { MP_ROM_QSTR(MP_QSTR_write), (mp_obj_t)&modturtle_write_obj }, }; STATIC MP_DEFINE_CONST_DICT(modturtle_module_globals, modturtle_module_globals_table); diff --git a/python/port/mod/turtle/turtle.cpp b/python/port/mod/turtle/turtle.cpp index 811650c3b..5c506e576 100644 --- a/python/port/mod/turtle/turtle.cpp +++ b/python/port/mod/turtle/turtle.cpp @@ -175,6 +175,21 @@ void Turtle::setVisible(bool visible) { } } +void Turtle::write(const char * string) { + // To prevent overlapping between the text and the turtle, force redraw + m_drawn = false; + MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); + KDContext * ctx = KDIonContext::sharedContext(); + static constexpr KDCoordinate headOffsetLength = 6; + KDCoordinate headOffsetX = headOffsetLength * std::cos(m_heading * k_headingScale); + KDCoordinate headOffsetY = k_invertedYAxisCoefficient * headOffsetLength * std::sin(m_heading * k_headingScale); + KDPoint headOffset(headOffsetX, headOffsetY); + KDPoint head(-k_iconHeadSize, -k_iconHeadSize); + KDPoint stringOffset = KDPoint(0,-k_font->glyphSize().height()); + ctx->drawString(string, position().translatedBy(headOffset).translatedBy(head).translatedBy(stringOffset)); + draw(true); +} + void Turtle::viewDidDisappear() { m_drawn = false; diff --git a/python/port/mod/turtle/turtle.h b/python/port/mod/turtle/turtle.h index 55a1c5e3c..bf0045ee9 100644 --- a/python/port/mod/turtle/turtle.h +++ b/python/port/mod/turtle/turtle.h @@ -78,6 +78,8 @@ public: m_colorMode = colorMode; } + void write(const char * string); + void viewDidDisappear(); private: @@ -91,6 +93,7 @@ private: static constexpr uint8_t k_maxSpeed = 10; static constexpr KDColor k_defaultColor = KDColorBlack; static constexpr uint8_t k_defaultPenSize = 1; + static constexpr const KDFont * k_font = KDFont::LargeFont; enum class PawType : uint8_t { FrontRight = 0, From 472cfc012cc2b05c229548540d3998de0a4e838e Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 20 May 2020 13:55:34 +0200 Subject: [PATCH 331/453] [matplotlib] Added colors to the toolbox in python Change-Id: I3ff3d4fb3552bcb8c375c77651db3b7c44991646 --- apps/code/catalog.de.i18n | 22 ++++++------ apps/code/catalog.en.i18n | 22 ++++++------ apps/code/catalog.es.i18n | 22 ++++++------ apps/code/catalog.fr.i18n | 22 ++++++------ apps/code/catalog.it.i18n | 22 ++++++------ apps/code/catalog.nl.i18n | 22 ++++++------ apps/code/catalog.pt.i18n | 22 ++++++------ apps/code/catalog.universal.i18n | 24 +++++++------- apps/code/python_toolbox.cpp | 57 +++++++++++++++++++------------- 9 files changed, 123 insertions(+), 112 deletions(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index f29a4e305..e280edea8 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -27,6 +27,17 @@ PythonChoice = "Zufallszahl aus der Liste" PythonClear = "Empty the list" PythonCmathFunction = "cmath-Modul-Funktionspräfix" PythonColor = "Definiere eine RGB-Farbe" +PythonColorBlack = "Black color" +PythonColorBlue = "Blue color" +PythonColorBrown = "Brown color" +PythonColorGreen = "Green color" +PythonColorGrey = "Grey color" +PythonColorOrange = "Orange color" +PythonColorPink = "Pink color" +PythonColorPurple = "Purple color" +PythonColorRed = "Red color" +PythonColorWhite = "White color" +PythonColorYellow = "Yellow color" PythonComplex = "a+ib zurückgeben" PythonCopySign = "Return x with the sign of y" PythonCos = "Kosinus" @@ -162,35 +173,24 @@ PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "time module function prefix" PythonTrunc = "x truncated to an integer" PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleColor = "Set the pen color" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" PythonTurtleForward = "Move forward by x pixels" PythonTurtleFunction = "turtle module function prefix" PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" PythonTurtleHeading = "Return the current heading" PythonTurtleHideturtle = "Hide the turtle" PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" PythonTurtlePendown = "Pull the pen down" PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" PythonTurtleReset = "Reset the drawing" PythonTurtleRight = "Turn right by a degrees" PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index fd514a811..24f2399be 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -27,6 +27,17 @@ PythonChoice = "Random number in the list" PythonClear = "Empty the list" PythonCmathFunction = "cmath module function prefix" PythonColor = "Define a rgb color" +PythonColorBlack = "Black color" +PythonColorBlue = "Blue color" +PythonColorBrown = "Brown color" +PythonColorGreen = "Green color" +PythonColorGrey = "Grey color" +PythonColorOrange = "Orange color" +PythonColorPink = "Pink color" +PythonColorPurple = "Purple color" +PythonColorRed = "Red color" +PythonColorWhite = "White color" +PythonColorYellow = "Yellow color" PythonComplex = "Return a+ib" PythonCopySign = "Return x with the sign of y" PythonCos = "Cosine" @@ -162,35 +173,24 @@ PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "time module function prefix" PythonTrunc = "x truncated to an integer" PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleColor = "Set the pen color" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" PythonTurtleForward = "Move forward by x pixels" PythonTurtleFunction = "turtle module function prefix" PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" PythonTurtleHeading = "Return the current heading" PythonTurtleHideturtle = "Hide the turtle" PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" PythonTurtlePendown = "Pull the pen down" PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" PythonTurtleReset = "Reset the drawing" PythonTurtleRight = "Turn right by a degrees" PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index d98508b1c..4e281d393 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -27,6 +27,17 @@ PythonChoice = "Random number in the list" PythonClear = "Empty the list" PythonCmathFunction = "cmath module function prefix" PythonColor = "Define a rgb color" +PythonColorBlack = "Black color" +PythonColorBlue = "Blue color" +PythonColorBrown = "Brown color" +PythonColorGreen = "Green color" +PythonColorGrey = "Grey color" +PythonColorOrange = "Orange color" +PythonColorPink = "Pink color" +PythonColorPurple = "Purple color" +PythonColorRed = "Red color" +PythonColorWhite = "White color" +PythonColorYellow = "Yellow color" PythonComplex = "Return a+ib" PythonCopySign = "Return x with the sign of y" PythonCos = "Cosine" @@ -162,35 +173,24 @@ PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "time module function prefix" PythonTrunc = "x truncated to an integer" PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleColor = "Set the pen color" PythonTurtleColorMode = "Set the color mode to 1.0 or 255" PythonTurtleForward = "Move forward by x pixels" PythonTurtleFunction = "turtle module function prefix" PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" PythonTurtleHeading = "Return the current heading" PythonTurtleHideturtle = "Hide the turtle" PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleLeft = "Turn left by a degrees" -PythonTurtleOrange = "Orange color" PythonTurtlePendown = "Pull the pen down" PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" PythonTurtlePosition = "Return the current (x,y) location" -PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" PythonTurtleReset = "Reset the drawing" PythonTurtleRight = "Turn right by a degrees" PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 72819e6ab..b0a22c8cd 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -27,6 +27,17 @@ PythonChoice = "Nombre aléatoire dans la liste" PythonClear = "Vide la liste" PythonCmathFunction = "Préfixe fonction du module cmath" PythonColor = "Définit une couleur rvb" +PythonColorBlack = "Couleur noire" +PythonColorBlue = "Couleur bleue" +PythonColorBrown = "Couleur marron" +PythonColorGreen = "Couleur verte" +PythonColorGrey = "Couleur grise" +PythonColorOrange = "Couleur orange" +PythonColorPink = "Couleur rose" +PythonColorPurple = "Couleur violette" +PythonColorRed = "Couleur rouge" +PythonColorWhite = "Couleur blanche" +PythonColorYellow = "Couleur jaune" PythonComplex = "Renvoie a+ib" PythonCopySign = "Renvoie x avec le signe de y" PythonCos = "Cosinus" @@ -162,35 +173,24 @@ PythonText = "Affiche un texte en (x,y)" PythonTimeFunction = "Préfixe fonction module time" PythonTrunc = "Troncature entière" PythonTurtleBackward = "Recule de x pixels" -PythonTurtleBlack = "Couleur noire" -PythonTurtleBlue = "Couleur bleue" -PythonTurtleBrown = "Couleur marron" PythonTurtleCircle = "Cercle de rayon r pixels" PythonTurtleColor = "Modifie la couleur du tracé" PythonTurtleColorMode = "Met le mode de couleur à 1.0 ou 255" PythonTurtleForward = "Avance de x pixels" PythonTurtleFunction = "Préfixe fonction du module turtle" PythonTurtleGoto = "Va au point de coordonnées (x,y)" -PythonTurtleGreen = "Couleur verte" -PythonTurtleGrey = "Couleur grise" PythonTurtleHeading = "Renvoie l'orientation actuelle" PythonTurtleHideturtle = "Masque la tortue" PythonTurtleIsdown = "True si le crayon est abaissé" PythonTurtleLeft = "Pivote de a degrés vers la gauche" -PythonTurtleOrange = "Couleur orange" PythonTurtlePendown = "Abaisse le crayon" PythonTurtlePensize = "Taille du tracé en pixels" PythonTurtlePenup = "Relève le crayon" -PythonTurtlePink = "Couleur rose" PythonTurtlePosition = "Renvoie la position (x,y)" -PythonTurtlePurple = "Couleur violette" -PythonTurtleRed = "Couleur rouge" PythonTurtleReset = "Réinitialise le dessin" PythonTurtleRight = "Pivote de a degrés vers la droite" PythonTurtleSetheading = "Met un cap de a degrés" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Affiche la tortue" PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10" -PythonTurtleWhite = "Couleur blanche" -PythonTurtleYellow = "Couleur jaune" PythonUniform = "Nombre décimal dans [a,b]" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 8fa8decfb..01fa70c2f 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -27,6 +27,17 @@ PythonChoice = "Numero aleatorio nella lista" PythonClear = "Svuota la lista" PythonCmathFunction = "Funz. prefissata modulo cmath" PythonColor = "Definisci un colore rvb" +PythonColorBlack = "Colore nero" +PythonColorBlue = "Colore blu" +PythonColorBrown = "Colore marrone" +PythonColorGreen = "Colore verde" +PythonColorGrey = "Colore grigio" +PythonColorOrange = "Colore arancione" +PythonColorPink = "Colore rosa" +PythonColorPurple = "Colore viola" +PythonColorRed = "Colore rosso" +PythonColorWhite = "Colore bianco" +PythonColorYellow = "Colore giallo" PythonComplex = "Restituisce a+ib" PythonCopySign = "Restituisce x con segno di y" PythonCos = "Coseno" @@ -162,35 +173,24 @@ PythonText = "Mostra un testo in (x,y)" PythonTimeFunction = "Prefisso funzione modulo time" PythonTrunc = "Troncamento intero" PythonTurtleBackward = "Indietreggia di x pixels" -PythonTurtleBlack = "Colore nero" -PythonTurtleBlue = "Colore blu" -PythonTurtleBrown = "Colore marrone" PythonTurtleCircle = "Cerchio di raggio r pixel" PythonTurtleColor = "Modifica il colore del tratto" PythonTurtleColorMode = "Imposta la modalità colore a 1.0 o 255" PythonTurtleForward = "Avanza di x pixel" PythonTurtleFunction = "Prefisso funzione modello turtle" PythonTurtleGoto = "Spostati alle coordinate (x,y)" -PythonTurtleGreen = "Colore verde" -PythonTurtleGrey = "Colore grigio" PythonTurtleHeading = "Restituisce l'orientamento attuale" PythonTurtleHideturtle = "Nascondi la tartaruga" PythonTurtleIsdown = "True se la penna è abbassata" PythonTurtleLeft = "Ruota di a gradi a sinistra" -PythonTurtleOrange = "Colore arancione" PythonTurtlePendown = "Abbassa la penna" PythonTurtlePensize = "Dimensione del tratto in pixel" PythonTurtlePenup = "Solleva la penna" -PythonTurtlePink = "Colore rosa" PythonTurtlePosition = "Fornisce posizione corrente (x,y)" -PythonTurtlePurple = "Colore viola" -PythonTurtleRed = "Colore rosso" PythonTurtleReset = "Azzera il disegno" PythonTurtleRight = "Ruota di a gradi a destra" PythonTurtleSetheading = "Imposta l'orientamento per a gradi" PythonTurtleSetposition = "Posiziona la tartaruga" PythonTurtleShowturtle = "Mostra la tartaruga" PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)" -PythonTurtleWhite = "Colore bianco" -PythonTurtleYellow = "Colore giallo" PythonUniform = "Numero decimale tra [a,b]" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index 571e701f5..a681f468d 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -27,6 +27,17 @@ PythonChoice = "Geeft willek. getal van de lijst" PythonClear = "Lijst leegmaken" PythonCmathFunction = "cmath module voorvoegsel" PythonColor = "Definieer een rgb kleur" +PythonColorBlack = "Zwarte kleur" +PythonColorBlue = "Blauwe kleur" +PythonColorBrown = "Bruine kleur" +PythonColorGreen = "Groene kleur" +PythonColorGrey = "Grijze kleur" +PythonColorOrange = "Oranje kleur" +PythonColorPink = "Roze kleur" +PythonColorPurple = "Paarse kleur" +PythonColorRed = "Rode kleur" +PythonColorWhite = "Witte kleur" +PythonColorYellow = "Gele kleur" PythonComplex = "Geeft a+ib" PythonCopySign = "Geeft x met het teken van y" PythonCos = "Cosinus" @@ -162,35 +173,24 @@ PythonText = "Display a text at (x,y) coordinates" PythonTimeFunction = "time module voorvoegsel" PythonTrunc = "x afgeknot tot een integer" PythonTurtleBackward = "Ga achterwaarts met x pixels" -PythonTurtleBlack = "Zwarte kleur" -PythonTurtleBlue = "Blauwe kleur" -PythonTurtleBrown = "Bruine kleur" PythonTurtleCircle = "Cirkel van straal r pixels" PythonTurtleColor = "Stel de kleur van de pen in" PythonTurtleColorMode = "Stel de kleurmodus in op 1.0 of 255" PythonTurtleForward = "Ga voorwaarts met x pixels" PythonTurtleFunction = "turtle module voorvoegsel" PythonTurtleGoto = "Verplaats naar (x,y) coordinaten" -PythonTurtleGreen = "Groene kleur" -PythonTurtleGrey = "Grijze kleur" PythonTurtleHeading = "Ga terug naar de huidige koers" PythonTurtleHideturtle = "Verberg de schildpad" PythonTurtleIsdown = "Geeft True als pen naar beneden is" PythonTurtleLeft = "Ga linksaf met a graden" -PythonTurtleOrange = "Oranje kleur" PythonTurtlePendown = "Zet de pen naar beneden" PythonTurtlePensize = "Stel de lijndikte in op x pixels" PythonTurtlePenup = "Zet de pen omhoog" -PythonTurtlePink = "Roze kleur" PythonTurtlePosition = "Zet huidige (x,y) locatie terug" -PythonTurtlePurple = "Paarse kleur" -PythonTurtleRed = "Rode kleur" PythonTurtleReset = "Reset de tekening" PythonTurtleRight = "Ga rechtsaf met a graden" PythonTurtleSetheading = "Zet de oriëntatie op a graden" PythonTurtleSetposition = "Plaats de schildpad" PythonTurtleShowturtle = "Laat de schildpad zien" PythonTurtleSpeed = "Tekensnelheid tussen 0 and 10" -PythonTurtleWhite = "Witte kleur" -PythonTurtleYellow = "Gele kleur" PythonUniform = "Zwevendekommagetal in [a,b]" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 20b63e96a..3e5160286 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -27,6 +27,17 @@ PythonChoice = "Número aleatório na lista" PythonClear = "Esvaziar a lista" PythonCmathFunction = "Prefixo da função do módulo cmath" PythonColor = "Define uma cor rgb" +PythonColorBlack = "Cor preta" +PythonColorBlue = "Cor azul" +PythonColorBrown = "Cor castanha" +PythonColorGreen = "Cor verde" +PythonColorGrey = "Cor cinzenta" +PythonColorOrange = "Cor laranja" +PythonTurtlePink = "Cor rosa" +PythonColorPurple = "Cor roxa" +PythonColorRed = "Cor vermelha" +PythonColorWhite = "Cor branca" +PythonColorYellow = "Cor amarela" PythonComplex = "Devolve a+ib" PythonCopySign = "Devolve x com o sinal de y" PythonCos = "Cosseno" @@ -162,35 +173,24 @@ PythonText = "Mostrar um texto em (x,y)" PythonTimeFunction = "Prefixo da função do módulo time" PythonTrunc = "x truncado a um número inteiro" PythonTurtleBackward = "Recuar x pixels" -PythonTurtleBlack = "Cor preta" -PythonTurtleBlue = "Cor azul" -PythonTurtleBrown = "Cor castanha" PythonTurtleCircle = "Circunferência de raio r pixels" PythonTurtleColor = "Definir a cor da caneta" PythonTurtleColorMode = "Ajustar o modo de cor para 1.0 ou 255" PythonTurtleForward = "Avançar x pixels" PythonTurtleFunction = "Prefixo da função do módulo turtle" PythonTurtleGoto = "Ir paras as coordenadas (x,y)" -PythonTurtleGreen = "Cor verde" -PythonTurtleGrey = "Cor cinzenta" PythonTurtleHeading = "Voltar para a orientação atual" PythonTurtleHideturtle = "Esconder o turtle" PythonTurtleIsdown = "True se a caneta está pressionada" PythonTurtleLeft = "Vira à esquerda por a graus" -PythonTurtleOrange = "Cor laranja" PythonTurtlePendown = "Puxar a caneta para baixo" PythonTurtlePensize = "Definir a espessura para x pixels" PythonTurtlePenup = "Puxar a caneta para cima" -PythonTurtlePink = "Cor rosa" PythonTurtlePosition = "Devolve a posição atual (x,y)" -PythonTurtlePurple = "Cor roxa" -PythonTurtleRed = "Cor vermelha" PythonTurtleReset = "Reiniciar o desenho" PythonTurtleRight = "Virar à esquerda por a graus" PythonTurtleSetheading = "Definir a orientação por a graus" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Mostrar o turtle" PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10" -PythonTurtleWhite = "Cor branca" -PythonTurtleYellow = "Cor amarela" PythonUniform = "Número decimal em [a,b]" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 1e2ecc96e..e33daf30a 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -29,6 +29,17 @@ PythonCommandClearWithoutArg = ".clear()" PythonCommandCmathFunction = "cmath.function" PythonCommandCmathFunctionWithoutArg = "cmath.\x11" PythonCommandColor = "color(r,g,b)" +PythonCommandColorBlack = "'black'" +PythonCommandColorBlue = "'blue'" +PythonCommandColorBrown = "'brown'" +PythonCommandColorGreen = "'green'" +PythonCommandColorGrey = "'grey'" +PythonCommandColorOrange = "'orange'" +PythonCommandColorPink = "'pink'" +PythonCommandColorPurple = "'purple'" +PythonCommandColorRed = "'red'" +PythonCommandColorWhite = "'white'" +PythonCommandColorYellow = "'yellow'" PythonCommandComplex = "complex(a,b)" PythonCommandConstantPi = "pi" PythonCommandCopySign = "copysign(x,y)" @@ -202,34 +213,23 @@ PythonCommandUniform = "uniform(a,b)" PythonConstantE = "2.718281828459045" PythonConstantPi = "3.141592653589793" PythonTurtleCommandBackward = "backward(x)" -PythonTurtleCommandBlack = "'black'" -PythonTurtleCommandBlue = "'blue'" -PythonTurtleCommandBrown = "'brown'" PythonTurtleCommandCircle = "circle(r)" PythonTurtleCommandColor = "color('c')/color(r,g,b)" PythonTurtleCommandColorWithoutArg = "color(\x11)" PythonTurtleCommandColorMode = "colormode(x)" PythonTurtleCommandForward = "forward(x)" PythonTurtleCommandGoto = "goto(x,y)" -PythonTurtleCommandGreen = "'green'" -PythonTurtleCommandGrey = "'grey'" PythonTurtleCommandHeading = "heading()" PythonTurtleCommandHideturtle = "hideturtle()" PythonTurtleCommandIsdown= "isdown()" PythonTurtleCommandLeft = "left(a)" -PythonTurtleCommandOrange = "'orange'" PythonTurtleCommandPendown = "pendown()" PythonTurtleCommandPensize = "pensize(x)" PythonTurtleCommandPenup = "penup()" -PythonTurtleCommandPink = "'pink'" PythonTurtleCommandPosition = "position()" -PythonTurtleCommandPurple = "'purple'" -PythonTurtleCommandRed = "'red'" PythonTurtleCommandReset = "reset()" PythonTurtleCommandRight = "right(a)" PythonTurtleCommandSetheading = "setheading(a)" PythonTurtleCommandSetposition = "setposition(x,[y])" PythonTurtleCommandShowturtle = "showturtle()" -PythonTurtleCommandSpeed = "speed(x)" -PythonTurtleCommandWhite = "'white'" -PythonTurtleCommandYellow = "'yellow'" +PythonTurtleCommandSpeed = "speed(x)" \ No newline at end of file diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 83f0b462e..80fee874a 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -120,7 +120,18 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false) }; const ToolboxMessageTree TurtleModuleChildren[] = { @@ -146,17 +157,17 @@ const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor, false, I18n::Message::PythonTurtleCommandColorWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColorMode, I18n::Message::PythonTurtleColorMode), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false) }; const ToolboxMessageTree RandomModuleChildren[] = { @@ -278,9 +289,9 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle), @@ -319,8 +330,8 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex), @@ -366,19 +377,19 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMonotonic, I18n::Message::PythonMonotonic, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandOct, I18n::Message::PythonOct), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPendown, I18n::Message::PythonTurtlePendown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPhase, I18n::Message::PythonPhase), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false), @@ -387,7 +398,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStartStop, I18n::Message::PythonRangeStartStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStop, I18n::Message::PythonRangeStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRect, I18n::Message::PythonRect), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound), @@ -411,8 +422,8 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImag, I18n::Message::PythonImag, false, I18n::Message::PythonCommandImagWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReal, I18n::Message::PythonReal, false, I18n::Message::PythonCommandRealWithoutArg) }; From 59bf8bbcf4af69bd1b50fb9d4f5ee4256a13c642 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 20 May 2020 14:18:01 +0200 Subject: [PATCH 332/453] [matplotlib] Added cyan color to the color palette Change-Id: I29476d8148ad98285505adc460b90628573518fa --- escher/include/escher/palette.h | 1 + escher/src/palette.cpp | 1 + python/port/port.cpp | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/escher/include/escher/palette.h b/escher/include/escher/palette.h index ccc965a5d..c50b276b7 100644 --- a/escher/include/escher/palette.h +++ b/escher/include/escher/palette.h @@ -34,6 +34,7 @@ public: constexpr static KDColor Brown = KDColor::RGB24(0x8d7350); constexpr static KDColor Purple = KDColor::RGB24(0x6e2d79); constexpr static KDColor BlueishGrey = KDColor::RGB24(0x919ea4); + constexpr static KDColor Cyan = KDColor::RGB24(0x00ffff); constexpr static KDColor DataColor[] = {Red, Blue, Green, YellowDark, Magenta, Turquoise, Pink, Orange}; constexpr static KDColor DataColorLight[] = {RedLight, BlueLight, GreenLight, YellowLight}; diff --git a/escher/src/palette.cpp b/escher/src/palette.cpp index 9d96af6d7..ac7cd7279 100644 --- a/escher/src/palette.cpp +++ b/escher/src/palette.cpp @@ -28,6 +28,7 @@ constexpr KDColor Palette::Green; constexpr KDColor Palette::GreenLight; constexpr KDColor Palette::Brown; constexpr KDColor Palette::Purple; +constexpr KDColor Palette::Cyan; constexpr KDColor Palette::BlueishGrey; constexpr KDColor Palette::DataColor[]; constexpr KDColor Palette::DataColorLight[]; diff --git a/python/port/port.cpp b/python/port/port.cpp index e4dae7789..bc2ee4113 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -184,7 +184,6 @@ KDColor MicroPython::Color::Parse(mp_obj_t input, Mode mode){ if (mp_obj_is_str(input)) { size_t l; const char * color = mp_obj_str_get_data(input, &l); - // TODO add cyan constexpr NamedColor pairs[] = { NamedColor("blue", KDColorBlue), NamedColor("b", KDColorBlue), @@ -202,7 +201,8 @@ KDColor MicroPython::Color::Parse(mp_obj_t input, Mode mode){ NamedColor("pink", Palette::Pink), NamedColor("orange", Palette::Orange), NamedColor("purple", Palette::Purple), - NamedColor("grey", Palette::GreyDark) + NamedColor("grey", Palette::GreyDark), + NamedColor("cyan", Palette::Cyan) }; for (NamedColor p : pairs) { if (strcmp(p.name(), color) == 0) { From 00291c897402fd92ef03ec5d40190efed2ea4346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 May 2020 16:55:54 +0200 Subject: [PATCH 333/453] [apps/code] Fix var initialisation in variable_box_controller --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index aba82d4a5..c140ca06b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -604,7 +604,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); // This is a trick to get the token position in the text. - const char * tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); + const char * tokenInText = scriptContent; // Keep track of DEF tokens to differentiate between variables and functions bool defToken = false; From 2bea3f3d47cd6e7a1140a07a2e1b142ca645ebd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 May 2020 17:18:12 +0200 Subject: [PATCH 334/453] [apps/code] Fix again VariableBoxController::loadCurrentVariablesInScript --- apps/code/variable_box_controller.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c140ca06b..5431c5ef5 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -626,18 +626,22 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont * This was found from stepping in the code and trying. */ /* TODO: Try to understand what is happening with tokenInText and * remove this trick.*/ - while (*tokenInText == ' ') { - tokenInText++; - } + const char * fixedTokenInText = tokenInText; for (int i = 0; i < 3; i++) { - if (strncmp(tokenInText, name, nameLength) != 0 && tokenInText > scriptContent) { - tokenInText--; + if (strncmp(fixedTokenInText, name, nameLength) != 0 && fixedTokenInText > scriptContent) { + fixedTokenInText--; } else { break; } } - assert(strncmp(tokenInText, name, nameLength) == 0); - addNode(nodeType, origin, tokenInText, nameLength); + if (strncmp(fixedTokenInText, name, nameLength) != 0) { + fixedTokenInText = tokenInText; + while (*fixedTokenInText == ' ') { + fixedTokenInText++; + } + } + assert(strncmp(fixedTokenInText, name, nameLength) == 0); + addNode(nodeType, origin, fixedTokenInText, nameLength); } } From 9d8eb1dbb68bad28870ffa29f1a447460209661f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 May 2020 17:28:12 +0200 Subject: [PATCH 335/453] [apps/code] Fix misnamed i18n --- apps/code/catalog.pt.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 3e5160286..b904e0e4f 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -33,7 +33,7 @@ PythonColorBrown = "Cor castanha" PythonColorGreen = "Cor verde" PythonColorGrey = "Cor cinzenta" PythonColorOrange = "Cor laranja" -PythonTurtlePink = "Cor rosa" +PythonColorPink = "Cor rosa" PythonColorPurple = "Cor roxa" PythonColorRed = "Cor vermelha" PythonColorWhite = "Cor branca" From 5d49f5dca27991fabedc81d7682cb657af7e9464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 May 2020 17:28:46 +0200 Subject: [PATCH 336/453] [apps/code] Fix VariableBoxController::addNodesFromImportMaybe Scenario: write a ascrip "from matplotlib.pyplot0 import *" than open the variable box --- apps/code/variable_box_controller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 5431c5ef5..3f39d0b1d 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -766,6 +766,10 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par if (loadAllSourceContent) { assert(childNodesCount > 0); const char * importationSourceName = importationSourceNameFromNode(parseNode->nodes[0]); + if (importationSourceName == nullptr) { + // For instance, the name is a "dotted name" but not matplotlib.pyplot + return true; + } int numberOfModuleChildren = 0; const ToolboxMessageTree * moduleChildren = nullptr; if (importationSourceIsModule(importationSourceName, &moduleChildren, &numberOfModuleChildren)) { @@ -805,7 +809,7 @@ const char * VariableBoxController::importationSourceNameFromNode(mp_parse_node_ // The importation source is "simple", for instance: from math import * return qstr_str(MP_PARSE_NODE_LEAF_ARG(node)); } - if (MP_PARSE_NODE_IS_STRUCT(node)) { + if (MP_PARSE_NODE_IS_STRUCT(node)) { //TODO replace this with an assert? mp_parse_node_struct_t * nodePNS = (mp_parse_node_struct_t *)node; uint nodeStructKind = MP_PARSE_NODE_STRUCT_KIND(nodePNS); if (nodeStructKind != PN_dotted_name) { From c102bf2e4e5860e2f2903e60db290b9f379f7b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 May 2020 17:44:40 +0200 Subject: [PATCH 337/453] [apps/code] Fix again variable_box_controller Scenario: add the script from matplotlib.pyplot import *\nfrom math import *\n\ng=9.81\n\ndef x(t,v_0,alpha):\n return v_0*cos(alpha)*t\ndef y(t,v_0,alpha,h_0):\n return -0.5*g*t**2+v_0*sin(alpha)*t+h_0\n\ndef vx(v_0,alpha):\n return v_0*cos(alpha)\ndef vy(t,v_0,alpha):\n return -g*t+v_0*sin(alpha)\n\ndef t_max(v_0,alpha,h_0):\n return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g\n\ndef simulation(v_0=15,alpha=pi/4,h_0=2):\n tMax=t_max(v_0,alpha,h_0)\n accuracy=1/10**(floor(log10(tMax))-1)\n T_MAX=floor(tMax*accuracy)+1\n X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]\n Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]\n VX=[vx(v_0,alpha) for t in range(T_MAX)]\n VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]\n for i in range(T_MAX):\n arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)\n grid()\n show()tan(if :\n \n celse:\n )c then autocomplete after the last c. --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 3f39d0b1d..efd79388a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -636,7 +636,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } if (strncmp(fixedTokenInText, name, nameLength) != 0) { fixedTokenInText = tokenInText; - while (*fixedTokenInText == ' ') { + while (*fixedTokenInText == ' ' || *fixedTokenInText == '\n') { fixedTokenInText++; } } From 8b648519038c21fc353d1508bc714c8ed288d6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 25 May 2020 09:55:58 +0200 Subject: [PATCH 338/453] [poincare] Multiplication::shallowBeautify: handle edge case: the expression contains a unit but we can't extract it (2^_min for instance) --- poincare/src/multiplication.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index f8ffdb9e4..90a57d686 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -364,7 +364,12 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu self = deepReduce(reductionContext); // removeUnit has to be called on reduced expression self = removeUnit(&units); - assert(!units.isUninitialized()); + if (units.isUninitialized()) { + // TODO: handle error "Invalid unit" + result = Undefined::Builder(); + goto replace_by_result; + } + ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion(); if (unitConversionMode == ExpressionNode::UnitConversion::Default) { /* Step 2a: Recognize derived units @@ -461,6 +466,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu } } +replace_by_result: self.replaceWithInPlace(result); return result; } From 38443c0e8306cf74cd314f0c46a645cebf808169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 09:49:10 +0200 Subject: [PATCH 339/453] [apps/code] Fix VariableBoxController::empty No scenario, but it seems right to reset m_shortenResultCharCount --- apps/code/variable_box_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index efd79388a..c94ebe470 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -250,6 +250,7 @@ void VariableBoxController::empty() { m_builtinNodesCount = 0; m_currentScriptNodesCount = 0; m_importedNodesCount = 0; + m_shortenResultCharCount = 0; } void VariableBoxController::insertAutocompletionResultAtIndex(int index) { From b466a8711b901ba28a755ced617696defef899b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 09:53:16 +0200 Subject: [PATCH 340/453] [apps/code] Remove dead code --- apps/code/variable_box_controller.cpp | 13 ------------- apps/code/variable_box_controller.h | 1 - 2 files changed, 14 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index c94ebe470..4470cf0be 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -188,19 +188,6 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha loadCurrentVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); } -const char * VariableBoxController::autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses) { - assert(textToAutocompleteLength >= 1); - assert(addParentheses != nullptr); - - // First load variables and functions that complete the textToAutocomplete - loadFunctionsAndVariables(scriptIndex, textToAutocomplete, textToAutocompleteLength); - if (numberOfRows() == 0) { - return nullptr; - } - - return autocompletionAlternativeAtIndex(textToAutocompleteLength, textToInsertLength, addParentheses, 0); -} - const char * VariableBoxController::autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate) { if (numberOfRows() == 0) { return nullptr; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index da00ba389..cb18d2cc3 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -36,7 +36,6 @@ public: /* VariableBoxController */ void setDisplaySubtitles(bool display) { m_displaySubtitles = display; } void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength); - const char * autocompletionForText(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses); const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr); void loadVariablesImportedFromScripts(); void empty(); From 6b558c3328145ae995953e332fa5101240ca7c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 09:59:01 +0200 Subject: [PATCH 341/453] [apps/code] Replace if with assertion --- apps/code/variable_box_controller.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 4470cf0be..d4236663a 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -154,17 +154,11 @@ int VariableBoxController::typeAtLocation(int i, int j) { } void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength) { + assert(scriptIndex >= 0); + // Reset the node counts empty(); - if (scriptIndex < 0) { - /* If not script index is given, the variable box is loaded from console. We - * only want to load imported script variables. */ - assert(textToAutocomplete == nullptr); - loadVariablesImportedFromScripts(); - return; - } - if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { textToAutocompleteLength = strlen(textToAutocomplete); } From 40d98389d4f6fffecee059b8a7bedb866fffbc3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 13:33:03 +0200 Subject: [PATCH 342/453] [apps/code] Cleaner code in VariableBoxController::loadCurrentVariablesInScript --- apps/code/variable_box_controller.cpp | 44 ++++++++------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d4236663a..f112e6ddb 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -582,13 +582,13 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - // 1) Lex the script + // Lex the script _mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); - // This is a trick to get the token position in the text. - const char * tokenInText = scriptContent; // Keep track of DEF tokens to differentiate between variables and functions bool defToken = false; + const char * beginningLine = scriptContent; + size_t beginningLineIndex = 0; while (lex->tok_kind != MP_TOKEN_END) { // Keep only MP_TOKEN_NAME tokens @@ -602,40 +602,22 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont ScriptNode::Type nodeType = defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; const NodeOrigin origin = NodeOrigin::CurrentScript; if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { - /* This is a trick to get the token position in the text, as name and - * nameLength are temporary variables that will be overriden when the - * lexer continues lexing or is destroyed. - * This was found from stepping in the code and trying. */ - /* TODO: Try to understand what is happening with tokenInText and - * remove this trick.*/ - const char * fixedTokenInText = tokenInText; - for (int i = 0; i < 3; i++) { - if (strncmp(fixedTokenInText, name, nameLength) != 0 && fixedTokenInText > scriptContent) { - fixedTokenInText--; - } else { - break; + size_t line = lex->tok_line - 1; // tok_line starts at 1, not 0 + if (beginningLineIndex < line) { + while (beginningLineIndex < line) { + beginningLine = UTF8Helper::CodePointSearch(beginningLine, '\n') + 1; + beginningLineIndex++; + assert(*beginningLine != 0); // We should not get to the end of the text } } - if (strncmp(fixedTokenInText, name, nameLength) != 0) { - fixedTokenInText = tokenInText; - while (*fixedTokenInText == ' ' || *fixedTokenInText == '\n') { - fixedTokenInText++; - } - } - assert(strncmp(fixedTokenInText, name, nameLength) == 0); - addNode(nodeType, origin, fixedTokenInText, nameLength); + assert(beginningLineIndex == line); + const char * tokenInText = beginningLine + lex->tok_column - 1; // tok_column starts at 1, not 0 + assert(strncmp(tokenInText, name, nameLength) == 0); + addNode(nodeType, origin, tokenInText, nameLength); } } defToken = lex->tok_kind == MP_TOKEN_KW_DEF; - - /* This is a trick to get the token position in the text. The -1 was found - * from stepping in the code and trying. */ - tokenInText = (const char *)(((_mp_reader_mem_t*)(lex->reader.data))->cur); - if (lex->tok_kind <= MP_TOKEN_ELLIPSIS || lex->tok_kind >= MP_TOKEN_OP_PLUS) { - tokenInText--; - } - mp_lexer_to_next(lex); } From 5412410723510443834649610614f04edb01d1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 14:05:46 +0200 Subject: [PATCH 343/453] [apps/code] Remove duplicates in the variable box Example script: from turtle import * hideturtle() We had "hideturtle" in the local variables, and "hideturtle()" in the imported. Now we should only have the latter. --- apps/code/variable_box_controller.cpp | 35 +++++++++++++++------------ apps/code/variable_box_controller.h | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index f112e6ddb..8df5473c0 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -269,7 +269,7 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { *strictlyStartsWith = true; } - return nodeNameLengthStartsWithName ? 1 : -1; + return nodeNameLengthStartsWithName ? *(nodeName + nameLength) : - *(nodeName + nodeNameLength) ; } int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { @@ -599,20 +599,23 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont /* If the token autocompletes the text and it is not already in the * variable box, add it. */ - ScriptNode::Type nodeType = defToken ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; const NodeOrigin origin = NodeOrigin::CurrentScript; - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { - size_t line = lex->tok_line - 1; // tok_line starts at 1, not 0 - if (beginningLineIndex < line) { - while (beginningLineIndex < line) { - beginningLine = UTF8Helper::CodePointSearch(beginningLine, '\n') + 1; - beginningLineIndex++; - assert(*beginningLine != 0); // We should not get to the end of the text - } + + // Find the token position in the text + size_t line = lex->tok_line - 1; // tok_line starts at 1, not 0 + if (beginningLineIndex < line) { + while (beginningLineIndex < line) { + beginningLine = UTF8Helper::CodePointSearch(beginningLine, '\n') + 1; + beginningLineIndex++; + assert(*beginningLine != 0); // We should not get to the end of the text } - assert(beginningLineIndex == line); - const char * tokenInText = beginningLine + lex->tok_column - 1; // tok_column starts at 1, not 0 - assert(strncmp(tokenInText, name, nameLength) == 0); + } + assert(beginningLineIndex == line); + const char * tokenInText = beginningLine + lex->tok_column - 1; // tok_column starts at 1, not 0 + assert(strncmp(tokenInText, name, nameLength) == 0); + + ScriptNode::Type nodeType = (defToken || *(tokenInText + nameLength) == '(')? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; + if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { addNode(nodeType, origin, tokenInText, nameLength); } } @@ -887,14 +890,14 @@ bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int t } // Check that node name is not already present in the variable box. - if (contains(nodeName, nodeNameLength)) { + if (contains(nodeName, nodeNameLength, type)) { return false; } return true; } -bool VariableBoxController::contains(const char * name, int nameLength) { +bool VariableBoxController::contains(const char * name, int nameLength, ScriptNode::Type type) { assert(nameLength > 0); bool alreadyInVarBox = false; // This could be faster with dichotomia, but there is no speed problem for now @@ -905,7 +908,7 @@ bool VariableBoxController::contains(const char * name, int nameLength) { for (int i = 0; i < nodesCount; i++) { ScriptNode * matchingNode = nodes + i; int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); - if (comparisonResult == 0) { + if (comparisonResult == 0 || (comparisonResult == '(' && type == ScriptNode::Type::WithParentheses)) { alreadyInVarBox = true; break; } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index cb18d2cc3..2206d49f5 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -99,7 +99,7 @@ private: * already contained in the variable box. */ void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength, ScriptNode::Type type, NodeOrigin origin); - bool contains(const char * name, int nameLength); + bool contains(const char * name, int nameLength, ScriptNode::Type type); void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); VariableBoxEmptyController m_variableBoxEmptyController; ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; From 34a4a3311ae913261e51ca2e808c35b1df65e82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 25 May 2020 16:33:14 +0200 Subject: [PATCH 344/453] [apps/code] Add test on variable_box_controller --- apps/Makefile | 1 + apps/code/Makefile | 20 ++++--- apps/code/test/variable_box_controller.cpp | 70 ++++++++++++++++++++++ apps/shared/Makefile | 2 +- 4 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 apps/code/test/variable_box_controller.cpp diff --git a/apps/Makefile b/apps/Makefile index 6c2bb1e4e..ff6c78f78 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -87,5 +87,6 @@ $(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/python/port/genhdr/qst apps_tests_src = $(app_calculation_test_src) $(app_code_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_settings_test_src) $(app_solver_test_src) apps_tests_src += $(addprefix apps/,\ + alternate_empty_nested_menu_controller.cpp \ global_preferences.cpp \ ) diff --git a/apps/code/Makefile b/apps/code/Makefile index 7a4772d2c..de11dcb4c 100644 --- a/apps/code/Makefile +++ b/apps/code/Makefile @@ -1,10 +1,6 @@ apps += Code::App app_headers += apps/code/app.h -app_code_test_src = $(addprefix apps/code/,\ - script_template.cpp \ -) - app_code_src = $(addprefix apps/code/,\ app.cpp \ console_controller.cpp \ @@ -15,16 +11,24 @@ app_code_src = $(addprefix apps/code/,\ editor_view.cpp \ helpers.cpp \ menu_controller.cpp \ - python_toolbox.cpp \ python_text_area.cpp \ sandbox_controller.cpp \ - script.cpp \ script_name_cell.cpp \ - script_node_cell.cpp \ script_parameter_controller.cpp \ +) + +app_code_test_src = $(addprefix apps/code/,\ + python_toolbox.cpp \ + script.cpp \ + script_node_cell.cpp \ script_store.cpp \ - variable_box_controller.cpp \ + script_template.cpp \ variable_box_empty_controller.cpp \ + variable_box_controller.cpp \ +) + +tests_src += $(addprefix apps/code/test/,\ + variable_box_controller.cpp\ ) app_code_src += $(app_code_test_src) diff --git a/apps/code/test/variable_box_controller.cpp b/apps/code/test/variable_box_controller.cpp new file mode 100644 index 000000000..7ddda610b --- /dev/null +++ b/apps/code/test/variable_box_controller.cpp @@ -0,0 +1,70 @@ +#include +#include "../script_store.h" +#include "../variable_box_controller.h" +#include + +using namespace Code; + +void assert_variables_are(const char * script, const char * nameToComplete, const char * * expectedVariables, int expectedVariablesCount) { + // Clean the store + ScriptStore store; + store.deleteAllScripts(); + + // Add the script + store.addNewScript(); + constexpr int dataBufferSize = 500; + char dataBuffer[dataBufferSize]; + Ion::Storage::Record::Data data = { + .buffer = &dataBuffer, + .size = dataBufferSize + }; + strcpy(dataBuffer, script); + constexpr int scriptIndex = 0; + store.scriptAtIndex(scriptIndex).setValue(data); + + // Load the variable box + VariableBoxController varBox(&store); + + const size_t nameToCompleteLength = strlen(nameToComplete); + varBox.loadFunctionsAndVariables(scriptIndex, nameToComplete, nameToCompleteLength); + + // Compare the variables + int index = 0; // Index to make sure we are not cycling through the results + int textToInsertLength; + bool addParentheses; + for (int i = 0; i < expectedVariablesCount; i++) { + quiz_assert(i == index); + const char * autocompletionI = varBox.autocompletionAlternativeAtIndex( + nameToCompleteLength, + &textToInsertLength, + &addParentheses, + i, + &index); + quiz_assert(i == index); // If false, the autompletion has cycled: there are not as many results as expected + quiz_assert(strncmp(*(expectedVariables + i), autocompletionI - nameToCompleteLength, textToInsertLength + nameToCompleteLength) == 0); + index++; + } + varBox.autocompletionAlternativeAtIndex( + strlen(nameToComplete), + &textToInsertLength, + &addParentheses, + index, + &index); + /* Assert the autocompletion has cycles: otherwise, there are more results + * than expected. */ + quiz_assert(index == 0); +} + +QUIZ_CASE(variable_box_controller) { + const char * expectedVariables[] = { + "froo", + "from", + "frozenset()" + }; + // FIXME This test does not load imported variables for now + assert_variables_are( + "from math import *\nfroo=3", + "fr", + expectedVariables, + sizeof(expectedVariables) / sizeof(const char *)); +} diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 4056c9dbd..4ffcd50df 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -14,6 +14,7 @@ app_shared_test_src = $(addprefix apps/shared/,\ labeled_curve_view.cpp \ memoized_curve_view_range.cpp \ range_1D.cpp \ + toolbox_helpers.cpp \ zoom_and_pan_curve_view_controller.cpp \ zoom_curve_view_controller.cpp \ ) @@ -74,7 +75,6 @@ app_shared_src = $(addprefix apps/shared/,\ text_field_delegate_app.cpp \ text_field_with_extension.cpp \ text_helpers.cpp \ - toolbox_helpers.cpp \ values_controller.cpp \ values_function_parameter_controller.cpp \ values_parameter_controller.cpp \ From 68ff71f72a4f5b47cc99f0ba9e26ecbb58bde74f Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 17:07:55 +0200 Subject: [PATCH 345/453] [matplotlib/modpyplot.cpp] Modified the way to add mp_float To prevent crashes caused by failed casts from char to float, removed optimization. Change-Id: Ia91aafa007538b6c05f7aace5e5962989d313c98 --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 5667d9f38..1a144fbcb 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -103,7 +103,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { } KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 5); - sPlotStore->addSegment(args[0], args[1], mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[0]), args[2]), mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(args[1]), args[3]), color, arrowWidth); + sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); return mp_const_none; } @@ -211,7 +211,7 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { mp_obj_t rectLeft = mp_obj_new_float(iXf - iWf/2.0f); mp_obj_t rectRight = mp_obj_new_float(iXf + iWf/2.0f); mp_obj_t rectBottom = iB; - mp_obj_t rectTop = mp_obj_float_binary_op(MP_BINARY_OP_INPLACE_ADD, mp_obj_get_float(iH), iB); + mp_obj_t rectTop = mp_obj_new_float(mp_obj_get_float(iH) + mp_obj_get_float(iB)); if (mp_obj_get_float(iH) < 0.0) { mp_obj_t temp = rectTop; rectTop = rectBottom; From 985c31920d7523a1b08eed3d252b2db5f51f2dfe Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 17:18:17 +0200 Subject: [PATCH 346/453] [matplotlib/plot_store.cpp] Removed useless function checkFloatType function used to check for an obj type before cast. This is already done by mp_obj_get_float Change-Id: I745bb3066328678ab0b2a2149c8f38a84f26fbd2 --- python/port/mod/matplotlib/pyplot/plot_store.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 931aa3c29..e772d407b 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -56,15 +56,6 @@ T PlotStore::ListIterator::operator*() { return T(m_tuples[m_tupleIndex]); }; -void checkFloatType(mp_obj_t * elements, size_t nbOfElements) { - for (size_t i = 0; i < nbOfElements; i++) { - // TODO: we don't take advantage of the fact that we extracted the value at the sametime... Maybe change the way things are done, build the c objects in addItem instead of allocating them on the python heap? Or use float array in python? - mp_float_t value; - if (!mp_obj_get_float_maybe(elements[i], &value)) { - mp_raise_TypeError("argument should be a number"); - } - } -} // Dot @@ -81,7 +72,6 @@ PlotStore::Dot::Dot(mp_obj_t tuple) { void PlotStore::addDot(mp_obj_t x, mp_obj_t y, KDColor c) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[3] = {x, y, color}; - checkFloatType(items, 2); mp_obj_t tuple = mp_obj_new_tuple(3, items); mp_obj_list_append(m_dots, tuple); } @@ -104,7 +94,6 @@ PlotStore::Segment::Segment(mp_obj_t tuple) { void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, arrowWidth, color}; - checkFloatType(items, 5); mp_obj_t tuple = mp_obj_new_tuple(6, items); mp_obj_list_append(m_segments, tuple); } @@ -126,7 +115,6 @@ PlotStore::Rect::Rect(mp_obj_t tuple) { void PlotStore::addRect(mp_obj_t left, mp_obj_t right, mp_obj_t top, mp_obj_t bottom, KDColor c) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[5] = {left, right, top, bottom, color}; - checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(5, items); mp_obj_list_append(m_rects, tuple); } @@ -145,7 +133,6 @@ PlotStore::Label::Label(mp_obj_t tuple) { void PlotStore::addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string) { mp_obj_t items[3] = {x, y, string}; - checkFloatType(items, 2); if (!mp_obj_is_str(string)) { mp_raise_TypeError("argument should be a string"); } From b3994127c23ec2ab8590a8594912934c4e098008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 25 May 2020 17:20:32 +0200 Subject: [PATCH 347/453] [poincare] Remove false assertion (splitIntoNormalForm can be called by denominator() at reduction - there is no reason that there is no unit at this stage...) --- poincare/src/multiplication.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 90a57d686..8bef55675 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -993,7 +993,6 @@ bool Multiplication::TermHasNumeralExponent(const Expression & e) { } void Multiplication::splitIntoNormalForm(Expression & numerator, Expression & denominator, ExpressionNode::ReductionContext reductionContext) const { - assert(!hasUnit()); Multiplication mNumerator = Multiplication::Builder(); Multiplication mDenominator = Multiplication::Builder(); int numberOfFactorsInNumerator = 0; From ade90db39232926f44d3e0eb0c0d619303da34e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 26 May 2020 10:11:38 +0200 Subject: [PATCH 348/453] [poincare] UnitConvert: implement removeUnit since UnitConvert can be a reduced expression --- poincare/include/poincare/unit_convert.h | 2 +- poincare/src/unit_convert.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/unit_convert.h b/poincare/include/poincare/unit_convert.h index dfa57ae42..3d82eebb5 100644 --- a/poincare/include/poincare/unit_convert.h +++ b/poincare/include/poincare/unit_convert.h @@ -20,7 +20,7 @@ public: Type type() const override { return Type::UnitConvert; } private: - Expression removeUnit(Expression * unit) override { assert(false); return ExpressionNode::removeUnit(unit); } + Expression removeUnit(Expression * unit) override; // Simplification void deepReduceChildren(ExpressionNode::ReductionContext reductionContext) override; Expression shallowBeautify(ReductionContext reductionContext) override; diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index bcf7d39a7..9807c48be 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -13,6 +13,13 @@ namespace Poincare { +Expression UnitConvertNode::removeUnit(Expression * unit) { + /* Warning: removeUnit of a UnitConvert doesn't make much sense but we + * implement a 'dummy' version since UnitConvert still exists among the + * reduced expression. */ + childAtIndex(1)->removeUnit(unit); + return UnitConvert(this).replaceWithUndefinedInPlace(); +} Expression UnitConvertNode::shallowBeautify(ReductionContext reductionContext) { return UnitConvert(this).shallowBeautify(reductionContext); } From d99357fd0d5d7fb0830b47f898b1183023fbb573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 26 May 2020 14:27:11 +0200 Subject: [PATCH 349/453] [poincare] Power: don't escape normal shallowReduce for expression containing matrix of complex form (for instance ConfidenceInterval). This fixes the following bug: input (2_m*confidence(0.2,12))^(-1) --> crashes --- poincare/src/power.cpp | 75 +++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 8f5729bc2..aa0cfddeb 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -434,45 +434,44 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex if (indexType != ExpressionNode::Type::Rational || !static_cast(index).isInteger()) { return replaceWithUndefinedInPlace(); } - if (baseType != ExpressionNode::Type::Matrix) { - return *this; + if (baseType == ExpressionNode::Type::Matrix) { + Matrix matrixBase = static_cast(base); + if (matrixBase.numberOfRows() != matrixBase.numberOfColumns()) { + return replaceWithUndefinedInPlace(); + } + Integer exponent = static_cast(index).signedIntegerNumerator(); + if (exponent.isNegative()) { + index.setSign(ExpressionNode::Sign::Positive, reductionContext); + Expression reducedPositiveExponentMatrix = shallowReduce(reductionContext); + Expression dummyExpression = Undefined::Builder(); + MatrixInverse inv = MatrixInverse::Builder(dummyExpression); + reducedPositiveExponentMatrix.replaceWithInPlace(inv); + inv.replaceChildInPlace(dummyExpression, reducedPositiveExponentMatrix); + return inv.shallowReduce(reductionContext); + } + if (Integer::NaturalOrder(exponent, Integer(k_maxExactPowerMatrix)) <= 0) { + return *this; + } + int exp = exponent.extractedInt(); // Ok, because 0 < exponent < k_maxExactPowerMatrix + if (exp == 0) { + Matrix id = Matrix::CreateIdentity(matrixBase.numberOfRows()); + replaceWithInPlace(id); + return std::move(id); + } + if (exp == 1) { + replaceWithInPlace(matrixBase); + return std::move(matrixBase); + } + Expression result = matrixBase.clone(); + // TODO: implement a quick exponentiation + for (int k = 1; k < exp; k++) { + result = Multiplication::Builder(result, matrixBase.clone()); + result = result.shallowReduce(reductionContext); + } + assert(!result.isUninitialized()); + replaceWithInPlace(result); + return result; } - Matrix matrixBase = static_cast(base); - if (matrixBase.numberOfRows() != matrixBase.numberOfColumns()) { - return replaceWithUndefinedInPlace(); - } - Integer exponent = static_cast(index).signedIntegerNumerator(); - if (exponent.isNegative()) { - index.setSign(ExpressionNode::Sign::Positive, reductionContext); - Expression reducedPositiveExponentMatrix = shallowReduce(reductionContext); - Expression dummyExpression = Undefined::Builder(); - MatrixInverse inv = MatrixInverse::Builder(dummyExpression); - reducedPositiveExponentMatrix.replaceWithInPlace(inv); - inv.replaceChildInPlace(dummyExpression, reducedPositiveExponentMatrix); - return inv.shallowReduce(reductionContext); - } - if (Integer::NaturalOrder(exponent, Integer(k_maxExactPowerMatrix)) > 0) { - return *this; - } - int exp = exponent.extractedInt(); // Ok, because 0 < exponent < k_maxExactPowerMatrix - if (exp == 0) { - Matrix id = Matrix::CreateIdentity(matrixBase.numberOfRows()); - replaceWithInPlace(id); - return std::move(id); - } - if (exp == 1) { - replaceWithInPlace(matrixBase); - return std::move(matrixBase); - } - Expression result = matrixBase.clone(); - // TODO: implement a quick exponentiation - for (int k = 1; k < exp; k++) { - result = Multiplication::Builder(result, matrixBase.clone()); - result = result.shallowReduce(reductionContext); - } - assert(!result.isUninitialized()); - replaceWithInPlace(result); - return result; } Expression power = *this; From 2b53ea748d7261ef083c8d127bb43cb69d615859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 26 May 2020 16:03:42 +0200 Subject: [PATCH 350/453] [apps/code] Typo --- apps/code/python_text_area.h | 2 +- apps/code/variable_box_controller.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h index 5ede682b8..c1a64db5f 100644 --- a/apps/code/python_text_area.h +++ b/apps/code/python_text_area.h @@ -25,7 +25,7 @@ public: bool handleEvent(Ion::Events::Event event) override; bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override; /* autocompletionType returns: - * - EndOfIdentifier if there is currently autocompletion, or if the wursor is + * - EndOfIdentifier if there is currently autocompletion, or if the cursor is * at the end of an identifier, * - MiddleOfIdentifier is the cursor is in the middle of an identifier, * - No identifier otherwise. diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 8df5473c0..94bd131fb 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -378,7 +378,7 @@ void VariableBoxController::insertTextInCaller(const char * text, int textLength void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength) { //TODO Could be great to use strings defined in STATIC const char *const tok_kw[] in python/lexer.c /* The commented values do not work with our current MicroPython but might - * work later, which is chy we keep them. */ + * work later, which is why we keep them. */ static const struct { const char * name; ScriptNode::Type type; } builtinNames[] = { {"False", ScriptNode::Type::WithoutParentheses}, {"None", ScriptNode::Type::WithoutParentheses}, From d82e6de6e8cb1303f6e38564886a340abb091f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 26 May 2020 16:16:24 +0200 Subject: [PATCH 351/453] [apps/code] VariableBoxController: fix NodeNameCompare when nameLength > nodeNameLength --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 94bd131fb..afedcc09b 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -269,7 +269,7 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { *strictlyStartsWith = true; } - return nodeNameLengthStartsWithName ? *(nodeName + nameLength) : - *(nodeName + nodeNameLength) ; + return nodeNameLengthStartsWithName ? *(nodeName + nameLength) : - *(name + nameLength) ; } int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { From 41bb169edd4bf2d306bd351edce1ed519bf122f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 26 May 2020 17:02:13 +0200 Subject: [PATCH 352/453] [apps/variable_box_controller] Auto-import: ignore variable when it is the autocompleted one --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index afedcc09b..09bce9f87 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -615,7 +615,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont assert(strncmp(tokenInText, name, nameLength) == 0); ScriptNode::Type nodeType = (defToken || *(tokenInText + nameLength) == '(')? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { + if (tokenInText != textToAutocomplete && shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { addNode(nodeType, origin, tokenInText, nameLength); } } From 705b1812f1364fcf8ed7b512e80daea1c4c7457f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 27 May 2020 12:21:01 +0200 Subject: [PATCH 353/453] [apps/code] VariableBoxController: fix NodeNameCompare when nameLength > nodeNameLength (step 2) --- apps/code/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 09bce9f87..d61d0de72 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -269,7 +269,7 @@ int VariableBoxController::NodeNameCompare(ScriptNode * node, const char * name, if (strictlyStartsWith != nullptr && nodeNameLengthStartsWithName) { *strictlyStartsWith = true; } - return nodeNameLengthStartsWithName ? *(nodeName + nameLength) : - *(name + nameLength) ; + return nodeNameLengthStartsWithName ? *(nodeName + nameLength) : - *(name + nodeNameLength) ; } int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { From 555617aff3a10bea454899ee1adddd1adc8e08c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 27 May 2020 12:29:14 +0200 Subject: [PATCH 354/453] [apps/code] Factorize VariableBoxController::addNode --- apps/code/variable_box_controller.cpp | 188 +++++++++++++------------- apps/code/variable_box_controller.h | 13 +- 2 files changed, 103 insertions(+), 98 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d61d0de72..436aee6af 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -280,11 +280,15 @@ int VariableBoxController::nodesCountForOrigin(NodeOrigin origin) const { } size_t * VariableBoxController::nodesCountPointerForOrigin(NodeOrigin origin) { - if (origin == NodeOrigin::CurrentScript) { - return &m_currentScriptNodesCount; + switch(origin) { + case NodeOrigin::CurrentScript: + return &m_currentScriptNodesCount; + case NodeOrigin::Builtins: + return &m_builtinNodesCount; + default: + assert(origin == NodeOrigin::Importation); + return &m_importedNodesCount; } - assert(origin == NodeOrigin::Importation); - return &m_importedNodesCount; } ScriptNode * VariableBoxController::nodesForOrigin(NodeOrigin origin) { @@ -500,25 +504,11 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in {qstr_str(MP_QSTR_zip), ScriptNode::Type::WithParentheses} }; assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount); - /* We can leverage on the fact that buitin nodes are stored in alphabetical - * order, so we do not use shouldAddNode. */ for (int i = 0; i < k_totalBuiltinNodesCount; i++) { - ScriptNode node = ScriptNode(builtinNames[i].type, builtinNames[i].name); - - int startsWith = 0; - if (textToAutocomplete != nullptr) { - bool strictlyStartsWith = false; - startsWith = NodeNameCompare(&node, textToAutocomplete, textToAutocompleteLength, &strictlyStartsWith); - if (startsWith == 0) { // The node name and name are equal - startsWith = node.type() == ScriptNode::Type::WithParentheses ? 0 : -1; // We accept the node only if it has parentheses - } else if (strictlyStartsWith) { - startsWith = 0; - } else if (startsWith > 0) { - return; - } - } - if (startsWith == 0) { - m_builtinNodes[m_builtinNodesCount++] = node; + if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, builtinNames[i].type, NodeOrigin::Builtins, builtinNames[i].name)) { + /* We can leverage on the fact that buitin nodes are stored in + * alphabetical order. */ + return; } } } @@ -615,8 +605,8 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont assert(strncmp(tokenInText, name, nameLength) == 0); ScriptNode::Type nodeType = (defToken || *(tokenInText + nameLength) == '(')? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; - if (tokenInText != textToAutocomplete && shouldAddNode(textToAutocomplete, textToAutocompleteLength, name, nameLength, nodeType, origin)) { - addNode(nodeType, origin, tokenInText, nameLength); + if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, nodeType, origin, tokenInText, nameLength)) { + break; } } @@ -657,7 +647,9 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child); structKind = (uint)MP_PARSE_NODE_STRUCT_KIND(child_pns); if (structKind == PN_funcdef || structKind == PN_expr_stmt) { - addImportStructFromScript(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength); + if (addImportStructFromScript(child_pns, structKind, scriptName, textToAutocomplete, textToAutocompleteLength)) { + break; + } } else { addNodesFromImportMaybe(child_pns, textToAutocomplete, textToAutocompleteLength, importFromModules); } @@ -718,7 +710,9 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par return true; } } - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, sourceId); + if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, id, -1, sourceId)) { + break; + } } else if (MP_PARSE_NODE_IS_STRUCT(child)) { // Parsing something like "from math import sin" addNodesFromImportMaybe((mp_parse_node_struct_t *)child, textToAutocomplete, textToAutocompleteLength, importFromModules); @@ -752,7 +746,9 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par assert(numberOfModuleChildren > numberOfNodesToSkip); for (int i = numberOfNodesToSkip; i < numberOfModuleChildren; i++) { const char * name = I18n::translate((moduleChildren + i)->label()); - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text())); + if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, importationSourceName, I18n::translate((moduleChildren + i)->text()))) { + break; + } } } else { //TODO get module variables that are not in the toolbox @@ -845,56 +841,104 @@ const char * structName(mp_parse_node_struct_t * structNode) { return nullptr; } -void VariableBoxController::addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength) { +bool VariableBoxController::addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength) { assert(structKind == PN_funcdef || structKind == PN_expr_stmt); // Find the id child node, which stores the struct's name const char * name = structName(pns); if (name == nullptr) { - return; + return false; } - checkAndAddNode(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, scriptName); + return addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, structKind == PN_funcdef ? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses, NodeOrigin::Importation, name, -1, scriptName); } -void VariableBoxController::checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength, const char * nodeSourceName, const char * description) { +// The returned boolean means we should escape the process +bool VariableBoxController::addNodeIfMatches(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type nodeType, NodeOrigin nodeOrigin, const char * nodeName, int nodeNameLength, const char * nodeSourceName, const char * nodeDescription) { + assert(nodeName != nullptr); if (nodeNameLength < 0) { nodeNameLength = strlen(nodeName); } - if (shouldAddNode(textToAutocomplete, textToAutocompleteLength, nodeName, nodeNameLength, type, origin)) { - // Add the node in alphabetical order - addNode(type, origin, nodeName, nodeNameLength, nodeSourceName, description); - } -} - -bool VariableBoxController::shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * nodeName, int nodeNameLength, ScriptNode::Type type, NodeOrigin origin) { - assert(nodeNameLength > 0); - assert(nodeName != nullptr); - + // Step 1: Check if the node matches the textToAutocomplete /* If the node will go to imported, do not add it if it starts with an * underscore : such identifiers are meant to be private. */ - if (origin == NodeOrigin::Importation && UTF8Helper::CodePointIs(nodeName, '_')) { + if (nodeOrigin == NodeOrigin::Importation && UTF8Helper::CodePointIs(nodeName, '_')) { return false; } + /* If the node is extracted from the current script, escape the current + * autocompleted word. */ + if (nodeOrigin == NodeOrigin::CurrentScript && nodeName == textToAutocomplete) { + return false; + } + bool nodeInLexicographicalOrder = nodeOrigin == NodeOrigin::Builtins; + + ScriptNode node(nodeType, nodeName, nodeNameLength, nodeSourceName, nodeDescription); if (textToAutocomplete != nullptr) { /* Check that nodeName autocompletes the text to autocomplete * - The start of nodeName must be equal to the text to autocomplete */ - if (strncmp(textToAutocomplete, nodeName, textToAutocompleteLength) != 0) { - return false; - } - /* - nodeName should be longer than the text to autocomplete. Beware of the - * case where nodeName is textToAutocompleteLength(), where we want to add - * the node to autocomplete with parentheses. */ - if (nodeNameLength == textToAutocompleteLength && type != ScriptNode::Type::WithParentheses) { - return false; + bool strictlyStartsWith = false; + int cmp = NodeNameCompare(&node, textToAutocomplete, textToAutocompleteLength, &strictlyStartsWith); + if (cmp == 0) { + // We don't accept the node if it has no parentheses + if (node.type() != ScriptNode::Type::WithParentheses) { + return false; + } + } else { + // We don't accept the node if it doesn't start as the textToAutocomplete + if (!strictlyStartsWith) { + if (nodeInLexicographicalOrder && cmp > 0) { + /* Signal to end the nodes scanning because we went past the + * textToAutocomplete in lexicographical order. */ + return true; + } + return false; + } } } - // Check that node name is not already present in the variable box. - if (contains(nodeName, nodeNameLength, type)) { + /* Step 2: Check that node name is not already present in the variable box. + * (No need for builtins as they're the first added.) */ + if (nodeOrigin != NodeOrigin::Builtins && contains(nodeName, nodeNameLength, nodeType)) { return false; } - return true; + // Step 3: Add node + size_t * currentNodeCount = nodesCountPointerForOrigin(nodeOrigin); + if (*currentNodeCount >= MaxNodesCountForOrigin(nodeOrigin)) { + // There is no room to add another node + return true; + } + /* We want to insert the node in lexicographical order, so we look for the + * insertion index. + * Some nodes (builtins) are added in lexicographical order so we start from + * the end of the node list to avoid scanning all list at each insertion. */ + ScriptNode * nodes = nodesForOrigin(nodeOrigin); + size_t insertionIndex = *currentNodeCount; + if (*currentNodeCount != 0) { + while (insertionIndex > 0) { + ScriptNode * node = nodes + insertionIndex - 1; + int nameComparison = NodeNameCompare(node, nodeName, nodeNameLength); + assert(nameComparison != 0); // We already checked that the name is not present already + if (nameComparison < 0) { + break; + } + insertionIndex--; + } + + // Shift all the following nodes + for (size_t i = *currentNodeCount; i > insertionIndex; i--) { + nodes[i] = nodes[i - 1]; + } + } + + // Check if the node source name fits, if not, do not use it + if (!ScriptNodeCell::CanDisplayNameAndSource(nodeNameLength, nodeSourceName)) { + nodeSourceName = nullptr; + } + // Add the node + nodes[insertionIndex] = ScriptNode(nodeType, nodeName, nodeNameLength, nodeSourceName, nodeDescription); + // Increase the node count + *currentNodeCount = *currentNodeCount + 1; + return false; } bool VariableBoxController::contains(const char * name, int nameLength, ScriptNode::Type type) { @@ -923,42 +967,4 @@ bool VariableBoxController::contains(const char * name, int nameLength, ScriptNo return alreadyInVarBox; } -void VariableBoxController::addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName, const char * description) { - assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - size_t * currentNodeCount = nodesCountPointerForOrigin(origin); - if (*currentNodeCount >= MaxNodesCountForOrigin(origin)) { - // There is no room to add another node - return; - } - /* We want to insert the node in alphabetical order, so we look for the - * insertion index. */ - ScriptNode * nodes = nodesForOrigin(origin); - size_t insertionIndex = 0; - if (*currentNodeCount != 0) { - while (insertionIndex < *currentNodeCount) { - ScriptNode * node = nodes + insertionIndex; - int nameComparison = NodeNameCompare(node, name, nameLength); - assert(nameComparison != 0); // We already checked that the name is not present already - if (nameComparison > 0) { - break; - } - insertionIndex++; - } - - // Shift all the following nodes - for (size_t i = *currentNodeCount; i > insertionIndex; i--) { - nodes[i] = nodes[i - 1]; - } - } - - // Check if the node source name fits, if not, do not use it - if (!ScriptNodeCell::CanDisplayNameAndSource(nameLength, nodeSourceName)) { - nodeSourceName = nullptr; - } - // Add the node - nodes[insertionIndex] = ScriptNode(type, name, nameLength, nodeSourceName, description); - // Increase the node count - *currentNodeCount = *currentNodeCount + 1; -} - } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 2206d49f5..e57b3c385 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -67,8 +67,7 @@ private: // Nodes and nodes count static size_t MaxNodesCountForOrigin(NodeOrigin origin) { - assert(origin == NodeOrigin::CurrentScript || origin == NodeOrigin::Importation); - return k_maxScriptNodesCount; + return origin == NodeOrigin::Builtins ? k_totalBuiltinNodesCount : k_maxScriptNodesCount; } int nodesCountForOrigin(NodeOrigin origin) const; size_t * nodesCountPointerForOrigin(NodeOrigin origin); @@ -94,13 +93,13 @@ private: const char * importationSourceNameFromNode(mp_parse_node_t & node); bool importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren = nullptr, int * numberOfModuleChildren = nullptr); bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript = nullptr); - void addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength); + bool addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength); /* Add a node if it completes the text to autocomplete and if it is not - * already contained in the variable box. */ - void checkAndAddNode(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); - bool shouldAddNode(const char * textToAutocomplete, int textToAutocompleteLength, const char * name, int nameLength, ScriptNode::Type type, NodeOrigin origin); + * already contained in the variable box. The returned boolean means we + * should escape the node scanning process (due to the lexicographical order + * or full node table). */ + bool addNodeIfMatches(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr); bool contains(const char * name, int nameLength, ScriptNode::Type type); - void addNode(ScriptNode::Type type, NodeOrigin origin, const char * name, int nameLength, const char * nodeSourceName = nullptr, const char * description = nullptr); VariableBoxEmptyController m_variableBoxEmptyController; ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From 41da4f2bd5b25e2d1fe0e8b5f05b1aabb05131c3 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 11:28:40 +0200 Subject: [PATCH 355/453] [matplotlib/modpyplot] Adding keyword argument support for arrow function Arrow function can now take into account the following keywords arguements : - head_width - color Change-Id: I205dcd5776d53a4efcbf1e6da4edf29d8e399cab --- python/port/genhdr/qstrdefs.in.h | 1 + .../port/mod/matplotlib/pyplot/modpyplot.cpp | 30 ++++++++++++++----- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- .../mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 71a87feee..19b007e12 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -384,6 +384,7 @@ Q(axis) Q(bar) Q(grid) Q(grid) +Q(head_width) Q(hist) Q(plot) Q(matplotlib) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 1a144fbcb..7685611f0 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -50,7 +50,18 @@ static size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength return itemLength; } +// Get color from keyword arguments if possible + +KDColor colorFromKeywordArgument(mp_map_elem_t * elemColor) { + if (elemColor != nullptr) { + return MicroPython::Color::Parse(elemColor->value); + } else { + return Palette::nextDataColor(&paletteIndex); + } +} + // Get color from arguments if possible +// TODO DELETE AFTER REPLACEMENT KDColor colorFromOptionalArgumentAtIndex(size_t n_args, const mp_obj_t * args, size_t colorIndex) { if (n_args > colorIndex) { @@ -89,20 +100,25 @@ void modpyplot_flush_used_heap() { } } -/* arrow(x,y,dx,dy, head_width, color) +/* arrow(x,y,dx,dy, KW : head_width, color) * x, y, dx, dy scalars * */ -mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { +mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(n_args >= 4); assert(sPlotStore != nullptr); sPlotStore->setShow(true); - mp_obj_t arrowWidth = mp_obj_new_float(0.003); // Default value - if (n_args >= 5) { - arrowWidth = args[4]; - } - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 5); + mp_map_elem_t * elem; + // Setting arrow width + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_head_width), MP_MAP_LOOKUP); + mp_obj_t arrowWidth = (elem == nullptr) ? mp_obj_new_float(0.003) : elem->value; + + // Setting arrow color + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + KDColor color = colorFromKeywordArgument(elem); + + // Adding the object to the plot sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); return mp_const_none; } diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index a32e0905e..d28e8f4e1 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -4,7 +4,7 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); void modpyplot_flush_used_heap(); -mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); +mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index c841bf284..3a398a05c 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -1,7 +1,7 @@ #include "modpyplot.h" STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 6, modpyplot_arrow); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_arrow_obj, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 5, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); From 0e3684e137dcee0f64c0a29fe621b6e8281c75e4 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 14:22:52 +0200 Subject: [PATCH 356/453] [matplotlib/modpyplot.cpp] Adding keyword arguments support for bar function bar function can now take into account the following keywords arguments : - color Change-Id: Iefa68cff59986d89c37cfecd7e3750f03c33ca59 --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 11 ++++++----- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- python/port/mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 7685611f0..805edce29 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -174,16 +174,14 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(4, coords); } -/* bar(x, height, width, bottom, color) +/* bar(x, height, width, bottom, KW :color) * 'x', 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of * scalar. * 'width' default value is 0.8 * 'bottom' default value is None * */ -// TODO: accept keyword args? - -mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { +mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); sPlotStore->setShow(true); mp_obj_t * xItems; @@ -215,7 +213,10 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { bItems[0] = mp_obj_new_float(0.0f); } - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 4); + // Setting bar color + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + KDColor color = colorFromKeywordArgument(elem); + for (size_t i=0; i 1 ? i : 0]; mp_obj_t iW = wItems[wLength > 1 ? i : 0]; diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index d28e8f4e1..6e5c2f466 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -6,7 +6,7 @@ void modpyplot_flush_used_heap(); mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args); +mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index 3a398a05c..52dd41364 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -3,7 +3,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_arrow_obj, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 5, modpyplot_bar); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_bar_obj, 2, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 3, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 3, modpyplot_plot); From 5daaa2c050f1fdbf2fb4f9aa7b34a4d67d3be950 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 14:31:40 +0200 Subject: [PATCH 357/453] [matplotlib/modpyplot.cpp] Adding keyword arguments support for hist function hist function can now take into account the following keyword arguments : - color Change-Id: I69eca6555d892db958d2bd002f438a40908b2d9d --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 9 ++++++--- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- python/port/mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 805edce29..2e27fe0ac 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -251,14 +251,14 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -/* hist(x, bins, color) +/* hist(x, bins KW : color) * 'x' array * 'bins': (default value 10) * - int (number of bins) * - sequence of bins * */ -mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { +mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) { assert(sPlotStore != nullptr); sPlotStore->setShow(true); // Sort data to easily get the minimal and maximal value and count bin sizes @@ -330,7 +330,10 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { binIndex++; } - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); + // Setting hist color + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + KDColor color = colorFromKeywordArgument(elem); + for (size_t i=0; iaddRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); } diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index 6e5c2f466..49a2c9a61 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -8,7 +8,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args); +mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index 52dd41364..d5c25232f 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -5,7 +5,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_arrow_obj, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_bar_obj, 2, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 3, modpyplot_hist); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_hist_obj, 1, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 3, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_scatter_obj, 2, 3, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); From b26d448573918c7b5072e96aba1100b345c66175 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 14:35:52 +0200 Subject: [PATCH 358/453] [matplotlib/modpyplot.cpp] Adding keyword arguments support for scatter function scatter function can now take into account the following keywords arguments : - color Change-Id: Iaea5a7a46d25e3efe2214368334ce859900d6ae6 --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 9 ++++++--- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- python/port/mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 2e27fe0ac..723da4306 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -340,19 +340,22 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) return mp_const_none; } -/* scatter(x, y, color) +/* scatter(x, y, KW : color) * - x, y: list * - x, y: scalar * */ -mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args) { +mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; assert(n_args >= 2); size_t length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); + // Setting scatter color + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + KDColor color = colorFromKeywordArgument(elem); + for (size_t i=0; iaddDot(xItems[i], yItems[i], color); } diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index 49a2c9a61..4f3009dbf 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -10,6 +10,6 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args); +mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index d5c25232f..7f9c55357 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -7,7 +7,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_bar_obj, 2, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_hist_obj, 1, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 3, modpyplot_plot); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_scatter_obj, 2, 3, modpyplot_scatter); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_scatter_obj, 2, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); From c39b432dd65a1110d247307a92834bb4c238aa31 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 14:38:58 +0200 Subject: [PATCH 359/453] [matplotlib/modpyplot.cpp] Adding keyword arguments support for plot function plot function can now take into account the following keywords arguments : - color Change-Id: I29b82ba25fa68ec4d8e1797112f133440dee22a0 --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 9 ++++++--- python/port/mod/matplotlib/pyplot/modpyplot.h | 2 +- python/port/mod/matplotlib/pyplot/modpyplot_table.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 723da4306..ce707e123 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -363,11 +363,11 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg return mp_const_none; } -/* plot(x, y) plots the curve (x, y, color) +/* plot(x, y) plots the curve (x, y, KW : color) * plot(y) plots the curve x as index array ([0,1,2...],y) * */ -mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { +mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { assert(sPlotStore != nullptr); sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; @@ -385,7 +385,10 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); } - KDColor color = colorFromOptionalArgumentAtIndex(n_args, args, 2); + // Setting plot color + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + KDColor color = colorFromKeywordArgument(elem); + for (int i=0; i<(int)length-1; i++) { sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); } diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h index 4f3009dbf..77615a3e3 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.h +++ b/python/port/mod/matplotlib/pyplot/modpyplot.h @@ -9,7 +9,7 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); -mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args); +mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c index 7f9c55357..893b334e4 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot_table.c +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -6,7 +6,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_a STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_bar_obj, 2, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_hist_obj, 1, modpyplot_hist); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 3, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_plot_obj, 1, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(modpyplot_scatter_obj, 2, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); From 68e3208799127f223d913c93b5ef3f74bda94598 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 14:43:50 +0200 Subject: [PATCH 360/453] [matplotlib/modpyplot.cpp] Removed function previously used for setting colors Change-Id: I76bb489d5a5b78162873f68c5e3cca8cebb77aba --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index ce707e123..a327ac0db 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -60,17 +60,6 @@ KDColor colorFromKeywordArgument(mp_map_elem_t * elemColor) { } } -// Get color from arguments if possible -// TODO DELETE AFTER REPLACEMENT - -KDColor colorFromOptionalArgumentAtIndex(size_t n_args, const mp_obj_t * args, size_t colorIndex) { - if (n_args > colorIndex) { - return MicroPython::Color::Parse(args[colorIndex]); - } else { - return Palette::nextDataColor(&paletteIndex); - } -} - // Internal functions mp_obj_t modpyplot___init__() { From d6e32594b8325f6b9cf491523a7047a88f003612 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 16:04:38 +0200 Subject: [PATCH 361/453] [test/matplotlib.cpp][modpyplot.cpp] Changed matplotlib tests Modified the tests for pyplot module and added error raisers to module functions Change-Id: I164feafaf562f16d646841c1f9dfbbe32e6a763b --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 16 ++++++++++++++++ python/test/matplotlib.cpp | 12 +++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index a327ac0db..df087c2b4 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -98,6 +98,10 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) assert(sPlotStore != nullptr); sPlotStore->setShow(true); + if (n_args > 4) { + mp_raise_TypeError("arrow() takes 4 positional arguments"); + } + mp_map_elem_t * elem; // Setting arrow width elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_head_width), MP_MAP_LOOKUP); @@ -172,6 +176,9 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); + if (n_args > 4) { + mp_raise_TypeError("bar() takes 4 positional arguments"); + } sPlotStore->setShow(true); mp_obj_t * xItems; mp_obj_t * hItems; @@ -248,6 +255,9 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { * */ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) { + if (n_args > 3) { + mp_raise_TypeError("hist() takes 3 positional arguments"); + } assert(sPlotStore != nullptr); sPlotStore->setShow(true); // Sort data to easily get the minimal and maximal value and count bin sizes @@ -336,6 +346,9 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); + if (n_args > 2) { + mp_raise_TypeError("scatter() takes 2 positional arguments"); + } sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; assert(n_args >= 2); @@ -358,6 +371,9 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { assert(sPlotStore != nullptr); + if (n_args > 2) { + mp_raise_TypeError("plot() takes 2 positional arguments"); + } sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; size_t length; diff --git a/python/test/matplotlib.cpp b/python/test/matplotlib.cpp index dbb2dde49..99bc61f5c 100644 --- a/python/test/matplotlib.cpp +++ b/python/test/matplotlib.cpp @@ -35,9 +35,11 @@ QUIZ_CASE(python_matplotlib_pyplot_arrow) { TestExecutionEnvironment env = init_environement(); assert_command_execution_succeeds(env, "from matplotlib.pyplot import *"); assert_command_execution_succeeds(env, "arrow(2,3,4,5)"); - assert_command_execution_succeeds(env, "arrow(2,3,4,5, 0.1)"); + assert_command_execution_fails(env, "arrow(2,3,4,5, 0.1)"); assert_command_execution_fails(env, "arrow(2,3,4,5, \"width\")"); - assert_command_execution_succeeds(env, "arrow(2,3,4,5, 0.1, \"#FF00FF\")"); + assert_command_execution_fails(env, "arrow(2,3,4,5, 0.1, \"#FF00FF\")"); + assert_command_execution_succeeds(env, "arrow(2,3,4,5,head_width=0.3)"); + assert_command_execution_succeeds(env, "arrow(2,3,4,5,color=\"red\")"); assert_command_execution_succeeds(env, "show()"); deinit_environment(); } @@ -62,7 +64,7 @@ QUIZ_CASE(python_matplotlib_pyplot_bar) { assert_command_execution_succeeds(env, "bar([],[])"); assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],2,3)"); assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],[1,2,3],[1,2,3])"); - assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],[1,2,3],[1,2,3], \"orange\")"); + assert_command_execution_succeeds(env, "bar([1,2,3],[1,2,3],[1,2,3],[1,2,3], color=\"orange\")"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "bar([1,2,3],[1,2,3,4],[1,2,3],[1,2,3])"); deinit_environment(); @@ -94,7 +96,7 @@ QUIZ_CASE(python_matplotlib_pyplot_plot) { assert_command_execution_succeeds(env, "plot([2,3,4,5,6])"); assert_command_execution_succeeds(env, "plot(2,3)"); assert_command_execution_succeeds(env, "plot([2,3,4,5,6],[3,4,5,6,7])"); - assert_command_execution_succeeds(env, "plot([2,3,4,5,6],[3,4,5,6,7], \"g\")"); + assert_command_execution_succeeds(env, "plot([2,3,4,5,6],[3,4,5,6,7], color=\"g\")"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "plot([2,3,4,5,6],2)"); deinit_environment(); @@ -105,7 +107,7 @@ QUIZ_CASE(python_matplotlib_pyplot_scatter) { assert_command_execution_succeeds(env, "from matplotlib.pyplot import *"); assert_command_execution_succeeds(env, "scatter(2,3)"); assert_command_execution_succeeds(env, "scatter([2,3,4,5,6],[3,4,5,6,7])"); - assert_command_execution_succeeds(env, "scatter([2,3,4,5,6],[3,4,5,6,7], (0,0,255))"); + assert_command_execution_succeeds(env, "scatter([2,3,4,5,6],[3,4,5,6,7], color=(0,0,255))"); assert_command_execution_succeeds(env, "show()"); assert_command_execution_fails(env, "scatter([2,3,4,5,6],2)"); deinit_environment(); From e5976984a20a7099db4bf6cd3a0363d5adcb3eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 27 May 2020 15:39:56 +0200 Subject: [PATCH 362/453] [poincare/poincare] Fix typo --- poincare/src/power.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index aa0cfddeb..1e3f00342 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -449,7 +449,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex inv.replaceChildInPlace(dummyExpression, reducedPositiveExponentMatrix); return inv.shallowReduce(reductionContext); } - if (Integer::NaturalOrder(exponent, Integer(k_maxExactPowerMatrix)) <= 0) { + if (Integer::NaturalOrder(exponent, Integer(k_maxExactPowerMatrix)) > 0) { return *this; } int exp = exponent.extractedInt(); // Ok, because 0 < exponent < k_maxExactPowerMatrix From 2f4c59b881565e893a61a36b6294d74651b15497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 27 May 2020 16:18:08 +0200 Subject: [PATCH 363/453] [apps/code] VariableBoxController::addNodeIfMatches: factorize the checking for node unicity and the insertion index computation --- apps/code/variable_box_controller.cpp | 98 ++++++++++++--------------- apps/code/variable_box_controller.h | 1 - 2 files changed, 45 insertions(+), 54 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 436aee6af..a6d372764 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -858,6 +858,8 @@ bool VariableBoxController::addNodeIfMatches(const char * textToAutocomplete, in nodeNameLength = strlen(nodeName); } // Step 1: Check if the node matches the textToAutocomplete + + // Step 1.1: Few escape cases /* If the node will go to imported, do not add it if it starts with an * underscore : such identifiers are meant to be private. */ if (nodeOrigin == NodeOrigin::Importation && UTF8Helper::CodePointIs(nodeName, '_')) { @@ -872,6 +874,7 @@ bool VariableBoxController::addNodeIfMatches(const char * textToAutocomplete, in ScriptNode node(nodeType, nodeName, nodeNameLength, nodeSourceName, nodeDescription); + // Step 1.2: check if textToAutocomplete matches the node if (textToAutocomplete != nullptr) { /* Check that nodeName autocompletes the text to autocomplete * - The start of nodeName must be equal to the text to autocomplete */ @@ -895,76 +898,65 @@ bool VariableBoxController::addNodeIfMatches(const char * textToAutocomplete, in } } - /* Step 2: Check that node name is not already present in the variable box. - * (No need for builtins as they're the first added.) */ - if (nodeOrigin != NodeOrigin::Builtins && contains(nodeName, nodeNameLength, nodeType)) { - return false; - } + // Step 2: Add Node - // Step 3: Add node + // Step 2.1: don't overflow the node list size_t * currentNodeCount = nodesCountPointerForOrigin(nodeOrigin); + ScriptNode * nodes = nodesForOrigin(nodeOrigin); if (*currentNodeCount >= MaxNodesCountForOrigin(nodeOrigin)) { // There is no room to add another node return true; } - /* We want to insert the node in lexicographical order, so we look for the - * insertion index. - * Some nodes (builtins) are added in lexicographical order so we start from - * the end of the node list to avoid scanning all list at each insertion. */ - ScriptNode * nodes = nodesForOrigin(nodeOrigin); - size_t insertionIndex = *currentNodeCount; - if (*currentNodeCount != 0) { - while (insertionIndex > 0) { - ScriptNode * node = nodes + insertionIndex - 1; - int nameComparison = NodeNameCompare(node, nodeName, nodeNameLength); - assert(nameComparison != 0); // We already checked that the name is not present already - if (nameComparison < 0) { - break; - } - insertionIndex--; - } - // Shift all the following nodes - for (size_t i = *currentNodeCount; i > insertionIndex; i--) { - nodes[i] = nodes[i - 1]; + // Step 2.2: find where to add the node (and check that it doesn't exist yet) + size_t insertionIndex = *currentNodeCount; + if (nodeOrigin == NodeOrigin::Builtins) { + /* For builtin nodes, we don't need to check whether the node was already + * added because they're added first in lexicographical order. Plus, we + * want to add it at the end of list to respect the lexicographical order. */ + assert(nodeInLexicographicalOrder); + } else { + // Look where to add + bool alreadyInVarBox = false; + // This could be faster with dichotomia, but there is no speed problem for now + NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; + for (NodeOrigin origin : origins) { + const int nodesCount = nodesCountForOrigin(origin); + ScriptNode * nodes = nodesForOrigin(origin); + for (int i = 0; i < nodesCount; i++) { + ScriptNode * matchingNode = nodes + i; + int comparisonResult = NodeNameCompare(matchingNode, nodeName, nodeNameLength); + if (comparisonResult == 0 || (comparisonResult == '(' && nodeType == ScriptNode::Type::WithParentheses)) { + alreadyInVarBox = true; + break; + } + if (comparisonResult > 0) { + if (nodeOrigin == origin) { + insertionIndex = i; + } + break; + } + } + if (alreadyInVarBox) { + return false; + } } } - // Check if the node source name fits, if not, do not use it + // Step 2.3: Shift all the following nodes + for (size_t i = *currentNodeCount; i > insertionIndex; i--) { + nodes[i] = nodes[i - 1]; + } + + // Step 2.4: Check if the node source name fits, if not, do not use it if (!ScriptNodeCell::CanDisplayNameAndSource(nodeNameLength, nodeSourceName)) { nodeSourceName = nullptr; } - // Add the node + // Step 2.5: Add the node nodes[insertionIndex] = ScriptNode(nodeType, nodeName, nodeNameLength, nodeSourceName, nodeDescription); // Increase the node count *currentNodeCount = *currentNodeCount + 1; return false; } -bool VariableBoxController::contains(const char * name, int nameLength, ScriptNode::Type type) { - assert(nameLength > 0); - bool alreadyInVarBox = false; - // This could be faster with dichotomia, but there is no speed problem for now - NodeOrigin origins[] = {NodeOrigin::CurrentScript, NodeOrigin::Builtins, NodeOrigin::Importation}; - for (NodeOrigin origin : origins) { - const int nodesCount = nodesCountForOrigin(origin); - ScriptNode * nodes = nodesForOrigin(origin); - for (int i = 0; i < nodesCount; i++) { - ScriptNode * matchingNode = nodes + i; - int comparisonResult = NodeNameCompare(matchingNode, name, nameLength); - if (comparisonResult == 0 || (comparisonResult == '(' && type == ScriptNode::Type::WithParentheses)) { - alreadyInVarBox = true; - break; - } - if (comparisonResult > 0) { - break; - } - } - if (alreadyInVarBox) { - break; - } - } - return alreadyInVarBox; -} - } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index e57b3c385..7d01da32f 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -99,7 +99,6 @@ private: * should escape the node scanning process (due to the lexicographical order * or full node table). */ bool addNodeIfMatches(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr); - bool contains(const char * name, int nameLength, ScriptNode::Type type); VariableBoxEmptyController m_variableBoxEmptyController; ScriptNode m_currentScriptNodes[k_maxScriptNodesCount]; ScriptNode m_builtinNodes[k_totalBuiltinNodesCount]; From 02b7ed3e27ec5666988c9ea6dbbf9d07e4362c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 09:57:50 +0200 Subject: [PATCH 364/453] [poincare/test] Add test for commit 02a1246 --- poincare/test/approximation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index ee3d66795..ebd0ea712 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -229,6 +229,9 @@ QUIZ_CASE(poincare_approximation_function) { assert_expression_approximates_to("abs(-1)", "1"); assert_expression_approximates_to("abs(-1)", "1"); + assert_expression_approximates_to("abs(-2.3ᴇ-39)", "2.3ᴇ-39", Degree, Cartesian, 5); + assert_expression_approximates_to("abs(-2.3ᴇ-39)", "2.3ᴇ-39"); + assert_expression_approximates_to("abs(3+2𝐢)", "3.605551"); assert_expression_approximates_to("abs(3+2𝐢)", "3.605551275464"); From e6b87be75ec26198ecd7496becdadec06dbccbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 11:39:48 +0200 Subject: [PATCH 365/453] [apps/i18n] Fix some i18n Did not fit or missed a space --- apps/code/catalog.it.i18n | 2 +- apps/code/catalog.pt.i18n | 2 +- apps/settings/base.nl.i18n | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 01fa70c2f..fd87c729d 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -175,7 +175,7 @@ PythonTrunc = "Troncamento intero" PythonTurtleBackward = "Indietreggia di x pixels" PythonTurtleCircle = "Cerchio di raggio r pixel" PythonTurtleColor = "Modifica il colore del tratto" -PythonTurtleColorMode = "Imposta la modalità colore a 1.0 o 255" +PythonTurtleColorMode = "Imposta modalità colore a 1.0 o 255" PythonTurtleForward = "Avanza di x pixel" PythonTurtleFunction = "Prefisso funzione modello turtle" PythonTurtleGoto = "Spostati alle coordinate (x,y)" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index b904e0e4f..cc903f2a3 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -175,7 +175,7 @@ PythonTrunc = "x truncado a um número inteiro" PythonTurtleBackward = "Recuar x pixels" PythonTurtleCircle = "Circunferência de raio r pixels" PythonTurtleColor = "Definir a cor da caneta" -PythonTurtleColorMode = "Ajustar o modo de cor para 1.0 ou 255" +PythonTurtleColorMode = "Define modo de cor para 1.0 ou 255" PythonTurtleForward = "Avançar x pixels" PythonTurtleFunction = "Prefixo da função do módulo turtle" PythonTurtleGoto = "Ir paras as coordenadas (x,y)" diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n index 94f51de45..9e44db188 100644 --- a/apps/settings/base.nl.i18n +++ b/apps/settings/base.nl.i18n @@ -4,7 +4,7 @@ AngleUnit = "Hoekmaat" DisplayMode = "Resultaat formaat" EditionMode = "Schrijfformaat" EditionLinear = "Lineair " -Edition2D = "Natuurlijk" +Edition2D = "Natuurlijk " ComplexFormat = "Complex formaat" ExamMode = "Examenstand" ExamModeActive = "Herstart examenstand" From 622cbe2e034059fde8876c98b13971e41c3e7d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 13:04:49 +0200 Subject: [PATCH 366/453] [apps/code] Fix auticompletion of color from Turtle It added color(|)/color(,,) instead of just color(|) --- apps/code/catalog.universal.i18n | 3 +-- apps/code/python_toolbox.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index e33daf30a..1f3d1a084 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -214,8 +214,7 @@ PythonConstantE = "2.718281828459045" PythonConstantPi = "3.141592653589793" PythonTurtleCommandBackward = "backward(x)" PythonTurtleCommandCircle = "circle(r)" -PythonTurtleCommandColor = "color('c')/color(r,g,b)" -PythonTurtleCommandColorWithoutArg = "color(\x11)" +PythonTurtleCommandColor = "color('c')" PythonTurtleCommandColorMode = "colormode(x)" PythonTurtleCommandForward = "forward(x)" PythonTurtleCommandGoto = "goto(x,y)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 80fee874a..4610872e9 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -155,7 +155,7 @@ const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor, false, I18n::Message::PythonTurtleCommandColorWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColorMode, I18n::Message::PythonTurtleColorMode), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false), From 6819041c1db25786d8c0050e780d63651fbf7bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 13:07:12 +0200 Subject: [PATCH 367/453] [apps/code] Remove TODOs --- apps/code/script.h | 2 +- apps/code/variable_box_controller.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/script.h b/apps/code/script.h index f58d4b428..faa408877 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -20,7 +20,7 @@ private: static constexpr int k_maxNumberOfDefaultScriptNames = 99; static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max - static constexpr size_t k_autoImportationStatusSize = 1; //TODO LEA use only 1 byte for both status flags + static constexpr size_t k_autoImportationStatusSize = 1; // TODO use only 1 byte for both status flags static constexpr size_t k_currentImportationStatusSize = 1; public: static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index 7d01da32f..d9c681c24 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -43,7 +43,7 @@ public: private: constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom - constexpr static size_t k_maxScriptNodesCount = 32; //TODO LEA + constexpr static size_t k_maxScriptNodesCount = 32; // Chosen without particular reasons constexpr static int k_totalBuiltinNodesCount = 107; constexpr static uint8_t k_scriptOriginsCount = 3; constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable From 1635f6132be471cfc04075c348eee162608792ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 14:59:30 +0200 Subject: [PATCH 368/453] [apps/code] Fix circular importation in the variable box Scenario (crashed only on the calculator): script1.py from script2 import * a=1 script2.py from script1 import * b=2 --- apps/code/console_controller.cpp | 2 +- apps/code/script.cpp | 35 +++++++++++++++++++++++---- apps/code/script.h | 31 ++++++++++++++++++++---- apps/code/script_store.cpp | 4 +-- apps/code/variable_box_controller.cpp | 27 +++++++++++++++------ apps/code/variable_box_controller.h | 2 +- 6 files changed, 80 insertions(+), 21 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 0a90ef9d2..16a5e4400 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -52,6 +52,7 @@ bool ConsoleController::loadPythonEnvironment() { m_pythonDelegate->initPythonWithUser(this); MicroPython::registerScriptProvider(m_scriptStore); m_importScriptsWhenViewAppears = m_autoImportScripts; + m_scriptStore->clearFetchInformation(); } return true; } @@ -60,7 +61,6 @@ void ConsoleController::unloadPythonEnvironment() { if (!m_pythonDelegate->isPythonUser(nullptr)) { m_consoleStore.startNewSession(); m_pythonDelegate->deinitPython(); - m_scriptStore->clearFetchInformation(); } } diff --git a/apps/code/script.cpp b/apps/code/script.cpp index f74e4e367..6615eed4a 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -84,16 +84,41 @@ const char * Script::content() const { } bool Script::contentFetchedFromConsole() const { - assert(!isNull()); - Data d = value(); - return (((char *)d.buffer)[k_autoImportationStatusSize] == 1); + return fetchedStatus() == FetchedStatus::FromConsole; } -void Script::setContentFetchedFromConsole(bool fetch) { +bool Script::contentFetchedForVariableBox() const { + return fetchedStatus() == FetchedStatus::ForVariableBox; +} + +void Script::setContentFetchedFromConsole() { + setFetchedStatus(FetchedStatus::FromConsole); +} + +void Script::setContentFetchedForVariableBox() { + setFetchedStatus(FetchedStatus::ForVariableBox); +} + +void Script::resetContentFetchedStatus() { + setFetchedStatus(FetchedStatus::None); +} + +Script::FetchedStatus Script::fetchedStatus() const { assert(!isNull()); Data d = value(); - ((char *)d.buffer)[k_autoImportationStatusSize] = fetch; + uint8_t status = const_cast(static_cast(d.buffer))[k_autoImportationStatusSize]; + assert(status == static_cast(FetchedStatus::None) + || status == static_cast(FetchedStatus::FromConsole) + || status == static_cast(FetchedStatus::ForVariableBox)); + return static_cast(status); +} + +void Script::setFetchedStatus(FetchedStatus status) { + assert(!isNull()); + Data d = value(); + const_cast(static_cast(d.buffer))[k_autoImportationStatusSize] = static_cast(status); setValue(d); } + } diff --git a/apps/code/script.h b/apps/code/script.h index faa408877..b5b1cadf6 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -5,14 +5,21 @@ namespace Code { -/* Record: | Size | Name | Body | - * Script: | | | AutoImportationStatus | ContentFetchedFromConsoleStatus | Content | +/* Record: | Size | Name | Body | + * Script: | | | AutoImportationStatus | FetchedStatus | Content | * * AutoImportationStatus is 1 if the script should be auto imported when the * console opens. * - * ContentFetchedFromConsoleStatus is 1 if hte console has currently imported - * this script. This is used to import the right variables in the variable box. */ + * FetchedStatus has two purposes: + * - It is used to detect which scripts are imported in the console, so we can + * retrieve the correct variables afterwards in the variable box. When a + * script has been imported, its fetchedStatus value is + * FetchedStatus::FromConsole. + * - It is used to prevent circular importation problems, such as scriptA + * importing scriptB, which imports scriptA. Once we get the variables from a + * script to put them in the variable box, we switch the status to + * FetchedStatus::ForVariableBox and won't reload it afterwards. */ class Script : public Ion::Storage::Record { private: @@ -22,6 +29,7 @@ private: static constexpr size_t k_autoImportationStatusSize = 1; // TODO use only 1 byte for both status flags static constexpr size_t k_currentImportationStatusSize = 1; + public: static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; /* 6 = strlen("script") @@ -32,12 +40,25 @@ public: static bool nameCompliant(const char * name); static constexpr size_t InformationSize() { return k_autoImportationStatusSize + k_currentImportationStatusSize; } + Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {} bool autoImportationStatus() const; void toggleAutoimportationStatus(); const char * content() const; bool contentFetchedFromConsole() const; - void setContentFetchedFromConsole(bool fetch); + bool contentFetchedForVariableBox() const; + void setContentFetchedFromConsole(); + void setContentFetchedForVariableBox(); + void resetContentFetchedStatus(); +private: + /* Fetched status */ + enum class FetchedStatus : uint8_t { + None = 0, + FromConsole = 1, + ForVariableBox = 2 + }; + FetchedStatus fetchedStatus() const; + void setFetchedStatus(FetchedStatus status); }; } diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 80fdb523d..c6b232f13 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -31,7 +31,7 @@ const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) return nullptr; } if (markAsFetched) { - script.setContentFetchedFromConsole(true); + script.setContentFetchedFromConsole(); } return script.content(); } @@ -40,7 +40,7 @@ void ScriptStore::clearFetchInformation() { // TODO optimize fetches const int scriptsCount = numberOfScripts(); for (int i = 0; i < scriptsCount; i++) { - scriptAtIndex(i).setContentFetchedFromConsole(false); + scriptAtIndex(i).resetContentFetchedStatus(); } } diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index a6d372764..d884abe32 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -158,7 +158,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha // Reset the node counts empty(); - + m_scriptStore->clearFetchInformation(); if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { textToAutocompleteLength = strlen(textToAutocomplete); } @@ -176,6 +176,14 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha loadBuiltinNodes(textToAutocomplete, textToAutocompleteLength); Script script = m_scriptStore->scriptAtIndex(scriptIndex); assert(!script.isNull()); + + /* Handle the FetchedStatus: we will import the current script variables in + * loadCurrentVariablesInScript, so we do not want to import those variables + * before, if any imported script also imported the current script. */ + assert(!script.contentFetchedFromConsole() && !script.contentFetchedForVariableBox()); + script.setContentFetchedForVariableBox(); + + // Load the imported and current variables const char * scriptContent = script.content(); assert(scriptContent != nullptr); loadImportedVariablesInScript(scriptContent, textToAutocomplete, textToAutocompleteLength); @@ -222,7 +230,7 @@ void VariableBoxController::loadVariablesImportedFromScripts() { for (int i = 0; i < scriptsCount; i++) { Script script = m_scriptStore->scriptAtIndex(i); if (script.contentFetchedFromConsole()) { - loadGlobalAndImportedVariablesInScriptAsImported(script.fullName(), script.content(), nullptr, -1, false); + loadGlobalAndImportedVariablesInScriptAsImported(script, nullptr, -1, false); } } } @@ -619,10 +627,15 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } } -void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { +void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { + if (script.contentFetchedForVariableBox()) { + // We already fetched these script variables + return; + } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - + const char * scriptName = script.fullName(); + const char * scriptContent = script.content(); mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false); mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_parse_node_t pn = parseTree.root; @@ -660,6 +673,8 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(con mp_parse_tree_clear(&parseTree); nlr_pop(); } + // Mark that we already fetched these script variables + script.setContentFetchedForVariableBox(); } bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { @@ -758,9 +773,7 @@ bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * par Script importedScript; const char * scriptFullName; if (importationSourceIsScript(importationSourceName, &scriptFullName, &importedScript)) { - const char * scriptContent = importedScript.content(); - assert(scriptContent != nullptr); - loadGlobalAndImportedVariablesInScriptAsImported(scriptFullName, scriptContent, textToAutocomplete, textToAutocompleteLength); + loadGlobalAndImportedVariablesInScriptAsImported(importedScript, textToAutocomplete, textToAutocompleteLength); } } } diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h index d9c681c24..f8968b41b 100644 --- a/apps/code/variable_box_controller.h +++ b/apps/code/variable_box_controller.h @@ -87,7 +87,7 @@ private: void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength); void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength); - void loadGlobalAndImportedVariablesInScriptAsImported(const char * scriptName, const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true); + void loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true); // Returns true if this was an import structure bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true); const char * importationSourceNameFromNode(mp_parse_node_t & node); From 163a14d9b9f77c24bd2824dce4a39bb6fed368ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 15:40:41 +0200 Subject: [PATCH 369/453] [apps/exam_mode] Dutch exam mode available when language is EN/NL --- apps/exam_mode_configuration_official.cpp | 5 ++++- apps/shared.nl.i18n | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/exam_mode_configuration_official.cpp b/apps/exam_mode_configuration_official.cpp index 860b2f65c..7640d21e6 100644 --- a/apps/exam_mode_configuration_official.cpp +++ b/apps/exam_mode_configuration_official.cpp @@ -6,7 +6,10 @@ constexpr Shared::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[2] = {Shared::SettingsMessageTree(I18n::Message::ActivateExamMode), Shared::SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; int ExamModeConfiguration::numberOfAvailableExamMode() { - if (GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + if ((GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN + && GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::NL) + || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) + { return 1; } return 2; diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index 00a69365f..f8f1acd98 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -1,6 +1,6 @@ ActivateDeactivate = "Zet aan/uit" -ActivateExamMode = "Examenstand activeren" -ActivateDutchExamMode = "Nederlandse examenstand activeren" +ActivateExamMode = "Internationale examenst." +ActivateDutchExamMode = "Nederlandse examenstand" ActiveExamModeMessage1 = "Al je gegevens worden " ActiveExamModeMessage2 = "gewist wanneer je de " ActiveExamModeMessage3 = "examenstand activeert." From 8ceb3680477e61506d9e93168620abc676bb217f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 28 May 2020 16:13:48 +0200 Subject: [PATCH 370/453] [poincare] Adding a number before orphan unit is done at beautification instead of at reducing (revert previous commit) This fixes the following bug: input log(0*f(_t)) --> crash due to an infinite loop where we remove/add 1 before the multiplication --- poincare/include/poincare/unit.h | 2 ++ poincare/src/multiplication.cpp | 4 ---- poincare/src/power.cpp | 15 ++++++++++----- poincare/src/unit.cpp | 19 +++++++++++++++---- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index d286d4bc6..5990c6320 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -166,6 +166,7 @@ public: // Simplification Expression shallowReduce(ReductionContext reductionContext) override; + Expression shallowBeautify(ReductionContext reductionContext) override; LayoutShape leftLayoutShape() const override { return LayoutShape::OneLetter; } // TODO const Dimension * dimension() const { return m_dimension; } @@ -777,6 +778,7 @@ public: // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); + Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); static void ChooseBestRepresentativeAndPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, true, reductionContext); } static void ChooseBestPrefixForValue(Expression * units, double * value, ExpressionNode::ReductionContext reductionContext) { return ChooseBestMultipleForValue(units, value, false, reductionContext); } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 8bef55675..ff11d453d 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -695,10 +695,6 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext if (hasUnit()) { // Do not expand Multiplication in presence of units shouldExpand = false; - // Make sure a Multiplication is not made of (Power of) Units only - if (!c.isNumber()) { - addChildAtIndexInPlace(Rational::Builder(1), 0, numberOfChildren()); - } } else if (c.type() != ExpressionNode::Type::Rational) { } else if (static_cast(c).isZero()) { // Check that other children don't match inf or unit diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 1e3f00342..4ab6fb07f 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -382,7 +383,6 @@ Expression Power::removeUnit(Expression * unit) { assert(child.isRationalOne()); assert(childUnit.type() == ExpressionNode::Type::Unit); Power p = *this; - Expression result = child; replaceWithInPlace(child); p.replaceChildAtIndexInPlace(0, childUnit); *unit = p; @@ -417,10 +417,6 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex // The exponent must be an Integer return replaceWithUndefinedInPlace(); } - if (parent().isUninitialized() && base.type() == ExpressionNode::Type::Unit) { - // A Power of Unit must not be orphan - return Multiplication::Builder(Rational::Builder(1), *this); - } } } @@ -1001,6 +997,15 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont replaceWithInPlace(result); return result; } + + // Step 4: Force Float(1) in front of an orphan Power of Unit + if (parent().isUninitialized() && childAtIndex(0).type() == ExpressionNode::Type::Unit) { + Multiplication m = Multiplication::Builder(Float::Builder(1.0)); + replaceWithInPlace(m); + m.addChildAtIndexInPlace(*this, 1, 1); + return std::move(m); + } + return *this; } diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index e67ec6f10..3941fb7ca 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -222,6 +222,10 @@ Expression UnitNode::shallowReduce(ReductionContext reductionContext) { return Unit(this).shallowReduce(reductionContext); } +Expression UnitNode::shallowBeautify(ReductionContext reductionContext) { + return Unit(this).shallowBeautify(reductionContext); +} + constexpr const Unit::Prefix Unit::PicoPrefix, Unit::NanoPrefix, @@ -317,14 +321,21 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext Expression multiplier = Power::Builder(Rational::Builder(10), Rational::Builder(prefixMultiplier)).shallowReduce(reductionContext); result = Multiplication::Builder(multiplier, result).shallowReduce(reductionContext); } - if (parent().isUninitialized() && result.type() == ExpressionNode::Type::Unit) { - // A Unit must not be orphan - result = Multiplication::Builder(Rational::Builder(1), result); - } replaceWithInPlace(result); return result; } +Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { + // Force Float(1) in front of an orphan Unit + if (parent().isUninitialized()) { + Multiplication m = Multiplication::Builder(Float::Builder(1.0)); + replaceWithInPlace(m); + m.addChildAtIndexInPlace(*this, 1, 1); + return std::move(m); + } + return *this; +} + void Unit::ChooseBestMultipleForValue(Expression * units, double * value, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext) { // Identify the first Unit factor and its exponent Expression firstFactor = *units; From 6c54fb4ebc55a6836002b1ef01627d4167df60da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 28 May 2020 17:18:05 +0200 Subject: [PATCH 371/453] [apps/code] Add 'write' to the toolbox (in Turtle module and catalog) --- apps/code/catalog.de.i18n | 1 + apps/code/catalog.en.i18n | 1 + apps/code/catalog.es.i18n | 1 + apps/code/catalog.fr.i18n | 1 + apps/code/catalog.it.i18n | 1 + apps/code/catalog.nl.i18n | 1 + apps/code/catalog.pt.i18n | 1 + apps/code/catalog.universal.i18n | 3 ++- apps/code/python_toolbox.cpp | 2 ++ 9 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index e280edea8..465fc8a06 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" +PythonTurtleWrite = "Display a text" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 24f2399be..e158cda8b 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" +PythonTurtleWrite = "Display a text" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 4e281d393..8503f7ed7 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Show the turtle" PythonTurtleSpeed = "Drawing speed between 0 and 10" +PythonTurtleWrite = "Display a text" PythonUniform = "Floating point number in [a,b]" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index b0a22c8cd..8a263636c 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Met un cap de a degrés" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Affiche la tortue" PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10" +PythonTurtleWrite = "Affiche un texte" PythonUniform = "Nombre décimal dans [a,b]" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index fd87c729d..893feb525 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Imposta l'orientamento per a gradi" PythonTurtleSetposition = "Posiziona la tartaruga" PythonTurtleShowturtle = "Mostra la tartaruga" PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)" +PythonTurtleWrite = "Mostra un testo" PythonUniform = "Numero decimale tra [a,b]" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index a681f468d..843d9b3ab 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Zet de oriëntatie op a graden" PythonTurtleSetposition = "Plaats de schildpad" PythonTurtleShowturtle = "Laat de schildpad zien" PythonTurtleSpeed = "Tekensnelheid tussen 0 and 10" +PythonTurtleWrite = "Display a text" PythonUniform = "Zwevendekommagetal in [a,b]" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index cc903f2a3..7d11881ef 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -193,4 +193,5 @@ PythonTurtleSetheading = "Definir a orientação por a graus" PythonTurtleSetposition = "Positionne la tortue" PythonTurtleShowturtle = "Mostrar o turtle" PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10" +PythonTurtleWrite = "Mostrar um texto" PythonUniform = "Número decimal em [a,b]" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 1f3d1a084..12a5b394a 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -231,4 +231,5 @@ PythonTurtleCommandRight = "right(a)" PythonTurtleCommandSetheading = "setheading(a)" PythonTurtleCommandSetposition = "setposition(x,[y])" PythonTurtleCommandShowturtle = "showturtle()" -PythonTurtleCommandSpeed = "speed(x)" \ No newline at end of file +PythonTurtleCommandSpeed = "speed(x)" +PythonTurtleCommandWrite = "write(\"text\")" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 4610872e9..aecd3bfbc 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -152,6 +152,7 @@ const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false), @@ -423,6 +424,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImag, I18n::Message::PythonImag, false, I18n::Message::PythonCommandImagWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReal, I18n::Message::PythonReal, false, I18n::Message::PythonCommandRealWithoutArg) From 66ba9851088210dd0e6f8a7ce5974859e4fa7323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 28 May 2020 17:19:48 +0200 Subject: [PATCH 372/453] [apps/code] In toolbox: plot(x,y) --> plot(x,y,color) --- apps/code/catalog.universal.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 12a5b394a..f6910c4ed 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -165,7 +165,7 @@ PythonCommandModf = "modf(x)" PythonCommandMonotonic = "monotonic()" PythonCommandOct = "oct(x)" PythonCommandPhase = "phase(z)" -PythonCommandPlot = "plot(x,y)" +PythonCommandPlot = "plot(x,y,color)" PythonCommandPolar = "polar(z)" PythonCommandPop = "list.pop()" PythonCommandPopWithoutArg = ".pop()" From e24de79a9e8f4cf8c422f3bca4c3d3bc28dc1f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 28 May 2020 17:29:15 +0200 Subject: [PATCH 373/453] [apps/calculation] HistoryController: avoid dereferencing nullptr --- apps/calculation/history_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 6e437fce0..a9bbc1e1e 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -162,7 +162,7 @@ void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int } else { HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell()); SubviewType nextSelectedSubviewType = selectedSubviewType(); - if (!selectedCell->displaysSingleLine()) { + if (selectedCell && !selectedCell->displaysSingleLine()) { nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output; } setSelectedSubviewType(nextSelectedSubviewType, false, previousSelectedCellX, previousSelectedCellY); From 8412087cc8de1c66294ec623693b1fc7f2c6ccfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 May 2020 17:58:52 +0200 Subject: [PATCH 374/453] [apps/calculaiton] Fix cursor bug Scenario: 1 EXE MATRIX MATRIX Down Down 1 Up Up -> it crashed --- apps/calculation/history_view_cell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 239529aff..3dff139a8 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -204,7 +204,7 @@ void HistoryViewCell::computeSubviewFrames(KDCoordinate frameWidth, KDCoordinate KDCoordinate inputY = k_margin; KDCoordinate outputY = k_margin; - if (m_calculationSingleLine) { + if (m_calculationSingleLine && !m_inputView.layout().isUninitialized()) { KDCoordinate inputBaseline = m_inputView.layout().baseline(); KDCoordinate outputBaseline = m_scrollableOutputView.baseline(); KDCoordinate baselineDifference = outputBaseline - inputBaseline; From fbeb5ed982a12a419f9d3fe9c0f6497926dbca81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 29 May 2020 17:50:21 +0200 Subject: [PATCH 375/453] [apps/controller] All code regarding Dutch exam mode is in ExamModeConfiguration --- apps/home/controller.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index 65b072ee7..b2f779d1a 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -2,6 +2,8 @@ #include "app.h" #include "../apps_container.h" #include "../global_preferences.h" +#include "../exam_mode_configuration.h" + extern "C" { #include } @@ -59,7 +61,7 @@ bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { AppsContainer * container = AppsContainer::sharedAppsContainer(); ::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch && selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp) { + if (ExamModeConfiguration::appIsForbiddenInExamMode(selectedSnapshot->descriptor()->name(), GlobalPreferences::sharedGlobalPreferences()->examMode())) { App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2); } else { bool switched = container->switchTo(selectedSnapshot); From 90fb9b4ea20b837bd5bd397b9c780f066f9ae0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 1 Jun 2020 11:36:03 +0200 Subject: [PATCH 376/453] [apps/calculation] Hide calculations involving units in Dutch exam mode --- apps/calculation/calculation_store.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index f6028d79a..fbac03577 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "../exam_mode_configuration.h" #include using namespace Poincare; @@ -98,6 +99,10 @@ ExpiringPointer CalculationStore::push(const char * text, Context * constexpr static int numberOfOutputs = Calculation::k_numberOfExpressions - 1; Expression outputs[numberOfOutputs] = {Expression(), Expression(), Expression()}; PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode()) && outputs[1].hasUnit()) { + // Hide results with units on units if required by the exam mode configuration + outputs[1] = Undefined::Builder(); + } outputs[2] = outputs[1]; int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits; for (int i = 0; i < numberOfOutputs; i++) { From 7b150deaeb5220051329dbb22729ad65507217fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 1 Jun 2020 11:36:54 +0200 Subject: [PATCH 377/453] [apps/calculation] Hide additional outputs for Dutch exam mode --- apps/calculation/calculation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index ca69ca7ce..ba3d46532 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -231,6 +231,9 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual( } Calculation::AdditionalInformationType Calculation::additionalInformationType(Context * context) { + if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode())) { + return AdditionalInformationType::None; + } Preferences * preferences = Preferences::sharedPreferences(); Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText); Expression i = input(); From 06dc97152c9d0812dc96ce68c5a3219c45300f67 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 25 May 2020 17:32:41 +0200 Subject: [PATCH 378/453] [matplotlib/modpyplot.cpp] Added support for keyword argument c, a shortcut for color Change-Id: I89227a73fca6fd50ae190107fc23c3c7acadc6db (cherry picked from commit bc642c2d8d105ed609cf8b4d86800879645afd7e) --- python/port/genhdr/qstrdefs.in.h | 1 + .../port/mod/matplotlib/pyplot/modpyplot.cpp | 24 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 19b007e12..fa1aa21b7 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -382,6 +382,7 @@ Q(set_pixel) Q(arrow) Q(axis) Q(bar) +Q(c) Q(grid) Q(grid) Q(head_width) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index df087c2b4..d9e0c0e66 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -108,8 +108,12 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) mp_obj_t arrowWidth = (elem == nullptr) ? mp_obj_new_float(0.003) : elem->value; // Setting arrow color + // color keyword elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); + // c keyword + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); + color = colorFromKeywordArgument(elem); // Adding the object to the plot sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); @@ -210,8 +214,12 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { } // Setting bar color + // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); + // c keyword + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); + color = colorFromKeywordArgument(elem); for (size_t i=0; i 1 ? i : 0]; @@ -330,8 +338,12 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) } // Setting hist color + // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); + // c keyword + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); + color = colorFromKeywordArgument(elem); for (size_t i=0; iaddRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); @@ -355,8 +367,12 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg size_t length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); // Setting scatter color - mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + // c keyword + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); + // color keyword + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + color = colorFromKeywordArgument(elem); for (size_t i=0; iaddDot(xItems[i], yItems[i], color); @@ -391,8 +407,12 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { } // Setting plot color - mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + // c keyword + mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); + // color keyword + elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + color = colorFromKeywordArgument(elem); for (int i=0; i<(int)length-1; i++) { sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); From 4b88521e14b905aaa899d502611f0d174866083d Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Tue, 26 May 2020 09:45:54 +0200 Subject: [PATCH 379/453] [matplotlib/modpyplot.cpp] Removing c keyword from some functions to match pyplot spec Change-Id: I53fa8c9edc8bcfdfb9c36797b41a1c36494e2c74 (cherry picked from commit 42b245ed97d6fa3394316888489660f4f76f0a78) --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index d9e0c0e66..6607fc6b1 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -111,9 +111,6 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) // color keyword elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); - // c keyword - elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); - color = colorFromKeywordArgument(elem); // Adding the object to the plot sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); @@ -217,9 +214,6 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); - // c keyword - elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); - color = colorFromKeywordArgument(elem); for (size_t i=0; i 1 ? i : 0]; @@ -341,9 +335,6 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); KDColor color = colorFromKeywordArgument(elem); - // c keyword - elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); - color = colorFromKeywordArgument(elem); for (size_t i=0; iaddRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); From e1a356fe889d4a5e918c453f880eb6f04f5550c2 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Tue, 26 May 2020 10:27:12 +0200 Subject: [PATCH 380/453] [matplotlib/modpyplot.cpp] Added support for third parameter color in plot function It is now possible to specify the color of the plot through a third positional argument in the plot function. However, is a keyword (color or c) is then used, it will override the previous color command. Change-Id: I5a73ddb322e650db486de568e4a56b4752751cfb (cherry picked from commit e6cc196cca405e5a4f8058a6af917aa0e7962b8a) --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 6607fc6b1..c3512e500 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -52,11 +52,13 @@ static size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength // Get color from keyword arguments if possible -KDColor colorFromKeywordArgument(mp_map_elem_t * elemColor) { +bool colorFromKeywordArgument(mp_map_elem_t * elemColor, KDColor * color) { if (elemColor != nullptr) { - return MicroPython::Color::Parse(elemColor->value); + *color = MicroPython::Color::Parse(elemColor->value); + return true; } else { - return Palette::nextDataColor(&paletteIndex); + *color = Palette::nextDataColor(&paletteIndex); + return false; } } @@ -108,9 +110,10 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) mp_obj_t arrowWidth = (elem == nullptr) ? mp_obj_new_float(0.003) : elem->value; // Setting arrow color + KDColor color; // color keyword elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); - KDColor color = colorFromKeywordArgument(elem); + colorFromKeywordArgument(elem, &color); // Adding the object to the plot sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); @@ -212,8 +215,10 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { // Setting bar color // color keyword + KDColor color; + // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); - KDColor color = colorFromKeywordArgument(elem); + colorFromKeywordArgument(elem, &color); for (size_t i=0; i 1 ? i : 0]; @@ -333,8 +338,10 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) // Setting hist color // color keyword + KDColor color; + // color keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); - KDColor color = colorFromKeywordArgument(elem); + colorFromKeywordArgument(elem, &color); for (size_t i=0; iaddRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); @@ -358,12 +365,14 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg size_t length = extractArgumentsAndCheckEqualSize(args[0], args[1], &xItems, &yItems); // Setting scatter color + // color keyword + KDColor color; // c keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); - KDColor color = colorFromKeywordArgument(elem); + colorFromKeywordArgument(elem, &color); // color keyword elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); - color = colorFromKeywordArgument(elem); + colorFromKeywordArgument(elem, &color); for (size_t i=0; iaddDot(xItems[i], yItems[i], color); @@ -378,9 +387,6 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { assert(sPlotStore != nullptr); - if (n_args > 2) { - mp_raise_TypeError("plot() takes 2 positional arguments"); - } sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; size_t length; @@ -398,12 +404,18 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { } // Setting plot color + KDColor color; + bool isUserSet = false; // c keyword mp_map_elem_t * elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_c), MP_MAP_LOOKUP); - KDColor color = colorFromKeywordArgument(elem); + isUserSet = colorFromKeywordArgument(elem, &color); // color keyword elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); - color = colorFromKeywordArgument(elem); + isUserSet = isUserSet | colorFromKeywordArgument(elem, &color); + // Eventual third positional argument + if (!isUserSet && n_args >= 3) { + color = MicroPython::Color::Parse(args[2]); + } for (int i=0; i<(int)length-1; i++) { sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); From aec25eb8d417ef88130e5e89b1883f56f68efd76 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Tue, 26 May 2020 10:48:40 +0200 Subject: [PATCH 381/453] [matplotlib/modpyplot.cpp] Modified the error messages due to too many arguments Change-Id: I48a8283a0c6311a52df152cbce3b0c824b46454b (cherry picked from commit 94b90533c751c10dadb8e6144e613ed4839f09c4) --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index c3512e500..58fd54ac4 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -101,7 +101,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) sPlotStore->setShow(true); if (n_args > 4) { - mp_raise_TypeError("arrow() takes 4 positional arguments"); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,"arrow() takes 4 positional arguments but %d were given",n_args)); } mp_map_elem_t * elem; @@ -180,8 +180,8 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); - if (n_args > 4) { - mp_raise_TypeError("bar() takes 4 positional arguments"); +if (n_args > 4) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,"bar() takes from 2 to 4 positional arguments but %d were given",n_args)); } sPlotStore->setShow(true); mp_obj_t * xItems; @@ -262,8 +262,8 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { * */ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) { - if (n_args > 3) { - mp_raise_TypeError("hist() takes 3 positional arguments"); + if (n_args > 2) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,"hist() takes from 1 to 2 positional arguments but %d were given",n_args)); } assert(sPlotStore != nullptr); sPlotStore->setShow(true); @@ -357,7 +357,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { assert(sPlotStore != nullptr); if (n_args > 2) { - mp_raise_TypeError("scatter() takes 2 positional arguments"); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,"scatter() takes 2 positional arguments but %d were given",n_args)); } sPlotStore->setShow(true); mp_obj_t * xItems, * yItems; @@ -388,6 +388,9 @@ mp_obj_t modpyplot_scatter(size_t n_args, const mp_obj_t *args, mp_map_t* kw_arg mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args,mp_map_t* kw_args) { assert(sPlotStore != nullptr); sPlotStore->setShow(true); + if (n_args > 3) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,"plot() takes 3 positional arguments but %d were given",n_args)); + } mp_obj_t * xItems, * yItems; size_t length; if (n_args == 1) { From 1b2750c2472d3221611869fc9080d1bc83e92f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 10:36:18 +0200 Subject: [PATCH 382/453] [python] matplotlib: add assertions to ensure authorized access to args[i] --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 58fd54ac4..8551af593 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -96,7 +96,6 @@ void modpyplot_flush_used_heap() { * */ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) { - assert(n_args >= 4); assert(sPlotStore != nullptr); sPlotStore->setShow(true); @@ -116,6 +115,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) colorFromKeywordArgument(elem, &color); // Adding the object to the plot + assert(n_args >= 4); sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0]) + mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1]) + mp_obj_get_float(args[3])), color, arrowWidth); return mp_const_none; } @@ -189,6 +189,8 @@ if (n_args > 4) { mp_obj_t * wItems; mp_obj_t * bItems; + assert(n_args >= 2); + // x arg size_t xLength = extractArgument(args[0], &xItems); @@ -249,6 +251,7 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { // Toggle the grid visibility sPlotStore->setGridRequested(!sPlotStore->gridRequested()); } else { + assert(n_args >= 1); sPlotStore->setGridRequested(mp_obj_is_true(args[0])); } return mp_const_none; @@ -269,6 +272,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args ) sPlotStore->setShow(true); // Sort data to easily get the minimal and maximal value and count bin sizes mp_obj_t * xItems; + assert(n_args >= 1); size_t xLength = extractArgument(args[0], &xItems); if (xLength == 0) { return mp_const_none; From 4b20c691741f9e7e7cb06dfd591e1b9a93569573 Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Thu, 28 May 2020 13:43:15 +0200 Subject: [PATCH 383/453] [python/modturtle.cpp] Added support for float parameter in colormode() The function can now accept the value 1.0 in addition to 1 Change-Id: I9a7021076844784ca997fc618253524089cbe855 (cherry picked from commit c69e1542ecc9a7e474a3f1e92cc97f644bf4b701) --- python/port/mod/turtle/modturtle.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/port/mod/turtle/modturtle.cpp b/python/port/mod/turtle/modturtle.cpp index b8d4d1de8..e08aa4dbd 100644 --- a/python/port/mod/turtle/modturtle.cpp +++ b/python/port/mod/turtle/modturtle.cpp @@ -168,8 +168,16 @@ mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) { mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args) { if(n_args == 0){ return mp_obj_new_int_from_uint(static_cast(sTurtle.colorMode())); - } else{ - int colorMode = mp_obj_get_int(args[0]); + } else { + // To accept both colormode(1) and colormode(1.0) we try to get args[0] as both int and float + mp_float_t decimalOne = mp_obj_get_float(args[0]); + int colorMode; + // But only 1 is accepted as float, 255 must be int + if (decimalOne == 1.0) { + colorMode = static_cast(MicroPython::Color::Mode::MaxIntensity1); + } else { + colorMode = mp_obj_get_int(args[0]); + } if (colorMode != static_cast(MicroPython::Color::Mode::MaxIntensity1) && colorMode != static_cast(MicroPython::Color::Mode::MaxIntensity255)) { mp_raise_ValueError("Colormode can be 1 or 255"); From 55ae258653fbee6e46f953d29351807b14780f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jun 2020 11:29:36 +0200 Subject: [PATCH 384/453] [poincare/test] Add failing matrix/power simplification test --- poincare/test/simplification.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 309deabbb..ba034593b 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -901,6 +901,9 @@ QUIZ_CASE(poincare_simplification_matrix) { assert_parsed_expression_simplify_to("cos(3a)*abs(transpose(a))", "cos(3×confidence(cos(2)/25,3))×abs(transpose(confidence(cos(2)/25,3)))"); assert_parsed_expression_simplify_to("abs(transpose(a))*cos(3a)", "abs(transpose(confidence(cos(2)/25,3)))×cos(3×confidence(cos(2)/25,3))"); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); + + // Mix + assert_parsed_expression_simplify_to("1/identity(2)^500", "1/[[1,0][0,1]]^500"); } QUIZ_CASE(poincare_simplification_functions_of_matrices) { From 0c040a7db6f0fa35f4127f019e3cfc8eec0b59b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jun 2020 11:39:37 +0200 Subject: [PATCH 385/453] [poincare/power] Fix infinite loop in reduction Fix the broken simplification test 1/identity(2)^500 --- poincare/src/power.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 4ab6fb07f..525e9a89f 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -439,6 +439,12 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex if (exponent.isNegative()) { index.setSign(ExpressionNode::Sign::Positive, reductionContext); Expression reducedPositiveExponentMatrix = shallowReduce(reductionContext); + if (reducedPositiveExponentMatrix.type() == ExpressionNode::Type::Power) { + /* The shallowReduce did not work, stop here so we do not get in an + * infinite loop. */ + static_cast(reducedPositiveExponentMatrix).childAtIndex(1).setSign(ExpressionNode::Sign::Negative, reductionContext); + return reducedPositiveExponentMatrix; + } Expression dummyExpression = Undefined::Builder(); MatrixInverse inv = MatrixInverse::Builder(dummyExpression); reducedPositiveExponentMatrix.replaceWithInPlace(inv); From a9fbcf99b278138039f157a8eac02de51d47fb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jun 2020 11:41:17 +0200 Subject: [PATCH 386/453] [poincare/test] Add failing test about multiplication simplification The result should be 0*[[1,0][0,1]]^500, or, maybe later, [[0,0][0,0]] --- poincare/test/simplification.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index ba034593b..3c07a9d33 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -192,6 +192,7 @@ QUIZ_CASE(poincare_simplification_multiplication) { assert_parsed_expression_simplify_to("[[1,2+𝐢][3,4][5,6]]×[[1,2+𝐢,3,4][5,6+𝐢,7,8]]", "[[11+5×𝐢,13+9×𝐢,17+7×𝐢,20+8×𝐢][23,30+7×𝐢,37,44][35,46+11×𝐢,57,68]]"); assert_parsed_expression_simplify_to("[[1,2][3,4]]×[[1,3][5,6]]×[[2,3][4,6]]", "[[82,123][178,267]]"); assert_parsed_expression_simplify_to("π×confidence(π/5,3)[[1,2]]", "π×confidence(π/5,3)×[[1,2]]"); + assert_parsed_expression_simplify_to("0*[[1,0][0,1]]^500", "0*[[1,0][0,1]]^500"); } QUIZ_CASE(poincare_simplification_units) { From 420dd0476635ba1de02522e0a282f0f2e63decbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 12:17:08 +0200 Subject: [PATCH 387/453] [apps/shared][python/port] CurveView::drawArrow uses pixel computation instead of float computation to avoid precision errors, by default the arrow size is decided in pixels. --- apps/shared/curve_view.cpp | 64 +++++++++++++++---- apps/shared/curve_view.h | 13 ++-- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 4 +- .../port/mod/matplotlib/pyplot/plot_store.h | 2 +- .../port/mod/matplotlib/pyplot/plot_view.cpp | 2 +- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 13c33c7d2..9feec4648 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -133,6 +133,22 @@ float CurveView::floatToPixel(Axis axis, float f) const { } } +float CurveView::floatLengthToPixelLength(Axis axis, float f) const { + float dist = floatToPixel(axis, f) - floatToPixel(axis, 0.0f); + return axis == Axis::Vertical ? - dist : dist; +} + +float CurveView::floatLengthToPixelLength(float dx, float dy) const { + float dxPixel = floatLengthToPixelLength(Axis::Horizontal, dx); + float dyPixel = floatLengthToPixelLength(Axis::Vertical, dy); + return std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel); +} + +float CurveView::pixelLengthToFloatLength(Axis axis, float f) const { + f = axis == Axis::Vertical ? -f : f; + return pixelToFloat(axis, floatToPixel(axis, 0.0f) + f); +} + void CurveView::drawGridLines(KDContext * ctx, KDRect rect, Axis axis, float step, KDColor boldColor, KDColor lightColor) const { Axis otherAxis = (axis == Axis::Horizontal) ? Axis::Vertical : Axis::Horizontal; /* We translate the pixel coordinates into floats, adding/subtracting 1 to @@ -449,7 +465,27 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor } -void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWidth, float tanAngle) const { +void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith, float tanAngle) const { + /* TODO: all computations are done in pixels because doing them in float + * values led to approximation error (?). But this leads to useless back and + * forth between float and pixels. Find a proper way to handle approximation + * errors (if this was the problem). */ + + assert(tanAngle >= 0.0f); + if (std::fabs(dx) < FLT_EPSILON && std::fabs(dy) < FLT_EPSILON) { + // We can't draw an arrow without any orientation + return; + } + + // Turn arrowWith in pixel length + float pixelArrowWith = 8.0f; // default value in pixels + if (arrowWith > 0.0f) { + float dxdy = std::sqrt(dx*dx+dy*dy); + float dxArrow = arrowWith*dx/dxdy; + float dyArrow = arrowWith*dy/dxdy; + pixelArrowWith = floatLengthToPixelLength(dxArrow, dyArrow); + } + /* Let's call the following variables L and l: * * / | @@ -466,22 +502,22 @@ void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float * * ----- L ----- * - **/ - assert(tanAngle >= 0.0f); - if (std::fabs(dx) < FLT_EPSILON && std::fabs(dy) < FLT_EPSILON) { - // We can't draw an arrow without any orientation - return; - } - float l = arrowWidth/2.0f; - float L = l/tanAngle; - float dx2dy2 = std::sqrt(dx*dx+dy*dy); + */ - float arrow1dx = L*dx/dx2dy2 + l*dy/dx2dy2; - float arrow1dy = L*dy/dx2dy2 - l*dx/dx2dy2; + float l = pixelArrowWith/2.0; + float L = l/tanAngle; + + // We compute the arrow segments in pixels + float dxPixel = floatLengthToPixelLength(Axis::Horizontal, dx); + float dyPixel = floatLengthToPixelLength(Axis::Vertical, dy); + float dx2dy2Pixel = floatLengthToPixelLength(dx, dy); + + float arrow1dx = pixelLengthToFloatLength(Axis::Horizontal, L*dxPixel/dx2dy2Pixel + l*dyPixel/dx2dy2Pixel); + float arrow1dy = pixelLengthToFloatLength(Axis::Vertical, L*dyPixel/dx2dy2Pixel - l*dxPixel/dx2dy2Pixel); drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false); - float arrow2dx = L*dx/dx2dy2 - l*dy/dx2dy2; - float arrow2dy = L*dy/dx2dy2 + l*dx/dx2dy2; + float arrow2dx = pixelLengthToFloatLength(Axis::Horizontal, L*dxPixel/dx2dy2Pixel - l*dyPixel/dx2dy2Pixel); + float arrow2dy = pixelLengthToFloatLength(Axis::Vertical, L*dyPixel/dx2dy2Pixel + l*dxPixel/dx2dy2Pixel); drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false); } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 4f8da4eff..d87af23d6 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -57,6 +57,9 @@ protected: constexpr static int k_externRectMargin = 2; float pixelToFloat(Axis axis, KDCoordinate p) const; float floatToPixel(Axis axis, float f) const; + float floatLengthToPixelLength(Axis axis, float f) const; + float pixelLengthToFloatLength(Axis axis, float f) const; + float floatLengthToPixelLength(float dx, float dy) const; void drawLine(KDContext * ctx, KDRect rect, Axis axis, float coordinate, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const { return drawHorizontalOrVerticalSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color, @@ -77,9 +80,9 @@ protected: void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const; /* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the * orientation (dx,dy). - * The parameters defining the shape of the arrow are the length of the base - * of the arrow triangle - 'arrowWith' - and the tangent of the angle between - * the segment and each wing of the arrow called 'tanAngle'. + * The parameters defining the shape of the arrow are the length of + * the base of the arrow triangle - 'pixelArrowWith' - and the tangent of the + * angle between the segment and each wing of the arrow called 'tanAngle'. * * / | * / | @@ -95,11 +98,11 @@ protected: * * <--- L ---> * - * l = arrowWith + * l = pixelArrowWith * tanAngle = tan(angle) = l/2L */ - void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith = 4, float tanAngle = 1.0f/3.0f) const; + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith, float tanAngle = 1.0f/3.0f) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 8551af593..c81eeb7bf 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -106,7 +106,9 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args, mp_map_t* kw_args) mp_map_elem_t * elem; // Setting arrow width elem = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_head_width), MP_MAP_LOOKUP); - mp_obj_t arrowWidth = (elem == nullptr) ? mp_obj_new_float(0.003) : elem->value; + /* Default head_width is 0.0f because we want a default width in pixel + * coordinates which is handled by CurveView::drawArrow. */ + mp_obj_t arrowWidth = (elem == nullptr) ? mp_obj_new_float(0.0f) : elem->value; // Setting arrow color KDColor color; diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index 2dfda039e..6009bbf76 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -78,7 +78,7 @@ public: KDColor m_color; }; - void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth = mp_obj_new_float(0.0)); + void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, mp_obj_t arrowWidth = mp_obj_new_float(NAN)); Iterable> segments() { return Iterable>(m_segments); } // Rect diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index 48100bec6..274e3b132 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -46,7 +46,7 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen segment.xEnd(), segment.yEnd(), segment.color() ); - if (segment.arrowWidth() > 0.0f) { + if (!std::isnan(segment.arrowWidth())) { float dx = segment.xEnd() - segment.xStart(); float dy = segment.yEnd() - segment.yStart(); drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color(), segment.arrowWidth()); From 4b83da21b7990616a2cb8e22aef49440798e8b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 14:34:31 +0200 Subject: [PATCH 388/453] [poincare] Fix Multiplication between 0 and a unreduced matrix: it should not be equal to 0 but to Matrix(0) --- poincare/src/multiplication.cpp | 2 +- poincare/test/simplification.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index ff11d453d..4f7c254e3 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -698,7 +698,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext } else if (c.type() != ExpressionNode::Type::Rational) { } else if (static_cast(c).isZero()) { // Check that other children don't match inf or unit - if (!recursivelyMatches(IsInfinity, context)) { + if (!recursivelyMatches([](const Expression e, Context * context) { return IsInfinity(e, context) || IsMatrix(e, context); }, context)) { replaceWithInPlace(c); return c; } diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 3c07a9d33..cda277afc 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -192,7 +192,7 @@ QUIZ_CASE(poincare_simplification_multiplication) { assert_parsed_expression_simplify_to("[[1,2+𝐢][3,4][5,6]]×[[1,2+𝐢,3,4][5,6+𝐢,7,8]]", "[[11+5×𝐢,13+9×𝐢,17+7×𝐢,20+8×𝐢][23,30+7×𝐢,37,44][35,46+11×𝐢,57,68]]"); assert_parsed_expression_simplify_to("[[1,2][3,4]]×[[1,3][5,6]]×[[2,3][4,6]]", "[[82,123][178,267]]"); assert_parsed_expression_simplify_to("π×confidence(π/5,3)[[1,2]]", "π×confidence(π/5,3)×[[1,2]]"); - assert_parsed_expression_simplify_to("0*[[1,0][0,1]]^500", "0*[[1,0][0,1]]^500"); + assert_parsed_expression_simplify_to("0*[[1,0][0,1]]^500", "0×[[1,0][0,1]]^500"); } QUIZ_CASE(poincare_simplification_units) { From fc238f639a72ddf2754ca868c800dec9969b4bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 14:35:31 +0200 Subject: [PATCH 389/453] [python] Fix test on matplotlib --- python/test/matplotlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/test/matplotlib.cpp b/python/test/matplotlib.cpp index 99bc61f5c..3ba0bd6df 100644 --- a/python/test/matplotlib.cpp +++ b/python/test/matplotlib.cpp @@ -85,7 +85,7 @@ QUIZ_CASE(python_matplotlib_pyplot_hist) { assert_command_execution_succeeds(env, "hist([2,3,4,5,6],23)"); assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3])"); assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3, 4,5,6,7])"); - assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3, 4,5,6,7], (0,255,0))"); + assert_command_execution_succeeds(env, "hist([2,3,4,5,6],[0,2,3, 4,5,6,7], color=(0,255,0))"); assert_command_execution_succeeds(env, "show()"); deinit_environment(); } From 2ebad3062c5dc9490e86e240cdee674c84e1b595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 18:05:42 +0200 Subject: [PATCH 390/453] [apps/code] Test: strcpy isn't available on the device --- apps/code/test/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/test/variable_box_controller.cpp b/apps/code/test/variable_box_controller.cpp index 7ddda610b..82b4fd613 100644 --- a/apps/code/test/variable_box_controller.cpp +++ b/apps/code/test/variable_box_controller.cpp @@ -18,7 +18,7 @@ void assert_variables_are(const char * script, const char * nameToComplete, cons .buffer = &dataBuffer, .size = dataBufferSize }; - strcpy(dataBuffer, script); + strlcpy(dataBuffer, script, dataBufferSize); constexpr int scriptIndex = 0; store.scriptAtIndex(scriptIndex).setValue(data); From 72e342e1b1d8d29edea2775ba6a17bd873a78280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jun 2020 11:54:40 +0200 Subject: [PATCH 391/453] [apps/curve_view] Fix drawArrow Compute everything in pixels + fix glitch when zooming on the tip of arrow(0,0,2,3) --- apps/shared/curve_view.cpp | 56 +++++++++++++++++++++----------------- apps/shared/curve_view.h | 2 +- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 9feec4648..56832003b 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -465,60 +465,66 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor } -void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith, float tanAngle) const { - /* TODO: all computations are done in pixels because doing them in float - * values led to approximation error (?). But this leads to useless back and - * forth between float and pixels. Find a proper way to handle approximation - * errors (if this was the problem). */ - +void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWidth, float tanAngle) const { assert(tanAngle >= 0.0f); if (std::fabs(dx) < FLT_EPSILON && std::fabs(dy) < FLT_EPSILON) { // We can't draw an arrow without any orientation return; } - // Turn arrowWith in pixel length - float pixelArrowWith = 8.0f; // default value in pixels - if (arrowWith > 0.0f) { - float dxdy = std::sqrt(dx*dx+dy*dy); - float dxArrow = arrowWith*dx/dxdy; - float dyArrow = arrowWith*dy/dxdy; - pixelArrowWith = floatLengthToPixelLength(dxArrow, dyArrow); + // Translate arrowWidth in pixel length + float pixelArrowWidth = 8.0f; // default value in pixels + if (arrowWidth > 0.0f) { + float dxdyFloat = std::sqrt(dx * dx + dy * dy); + float dxArrowFloat = arrowWidth * std::fabs(dy) / dxdyFloat; + float dyArrowFloat = arrowWidth * std::fabs(dx) / dxdyFloat; + pixelArrowWidth = floatLengthToPixelLength(dxArrowFloat, dyArrowFloat); + assert(pixelArrowWidth > 0.0f); } /* Let's call the following variables L and l: * - * / | + * /arrow2 | * / | * / l * / | - * / | - * <-------------------------------------------------- + * / B | + * <---------+---------------------------------------- * \ * \ * \ * \ - * \ + * \arrow1 * * ----- L ----- * */ - float l = pixelArrowWith/2.0; - float L = l/tanAngle; + float lPixel = pixelArrowWidth / 2.0; + float LPixel = lPixel / tanAngle; + + float xPixel = floatToPixel(Axis::Horizontal, x); + float yPixel = floatToPixel(Axis::Vertical, y); // We compute the arrow segments in pixels float dxPixel = floatLengthToPixelLength(Axis::Horizontal, dx); float dyPixel = floatLengthToPixelLength(Axis::Vertical, dy); float dx2dy2Pixel = floatLengthToPixelLength(dx, dy); - float arrow1dx = pixelLengthToFloatLength(Axis::Horizontal, L*dxPixel/dx2dy2Pixel + l*dyPixel/dx2dy2Pixel); - float arrow1dy = pixelLengthToFloatLength(Axis::Vertical, L*dyPixel/dx2dy2Pixel - l*dxPixel/dx2dy2Pixel); - drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false); + // Point B is the orthogonal projection of the arrow tips on the arrow body + float bxPixel = xPixel - LPixel * dxPixel / dx2dy2Pixel; + float byPixel = yPixel + LPixel * dyPixel / dx2dy2Pixel; - float arrow2dx = pixelLengthToFloatLength(Axis::Horizontal, L*dxPixel/dx2dy2Pixel - l*dyPixel/dx2dy2Pixel); - float arrow2dy = pixelLengthToFloatLength(Axis::Vertical, L*dyPixel/dx2dy2Pixel + l*dxPixel/dx2dy2Pixel); - drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false); + float dxArrowPixel = - lPixel * dyPixel / dx2dy2Pixel; + float dyArrowPixel = lPixel * dxPixel / dx2dy2Pixel; + + float arrow1xPixel = bxPixel + dxArrowPixel; + float arrow1yPixel = byPixel - dyArrowPixel; + float arrow2xPixel = bxPixel - dxArrowPixel; + float arrow2yPixel = byPixel + dyArrowPixel; + + straightJoinDots(ctx, rect, xPixel, yPixel, arrow1xPixel, arrow1yPixel, color, true); + straightJoinDots(ctx, rect, xPixel, yPixel, arrow2xPixel, arrow2yPixel, color, true); } void CurveView::drawGrid(KDContext * ctx, KDRect rect) const { diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index d87af23d6..8a7b13c4f 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -102,7 +102,7 @@ protected: * tanAngle = tan(angle) = l/2L */ - void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWith, float tanAngle = 1.0f/3.0f) const; + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, float arrowWidth, float tanAngle = 1.0f/3.0f) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; From 49e4abb9648de47be3d5abc83efadca39c701556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jun 2020 11:58:20 +0200 Subject: [PATCH 392/453] [poincare/multiplication] Fix comment --- poincare/src/multiplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 4f7c254e3..0f6e806d8 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -697,7 +697,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext shouldExpand = false; } else if (c.type() != ExpressionNode::Type::Rational) { } else if (static_cast(c).isZero()) { - // Check that other children don't match inf or unit + // Check that other children don't match inf or matrix if (!recursivelyMatches([](const Expression e, Context * context) { return IsInfinity(e, context) || IsMatrix(e, context); }, context)) { replaceWithInPlace(c); return c; From 6abc3b8c994099f238e82bc295e482972ffd49f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 4 Jun 2020 13:14:06 +0200 Subject: [PATCH 393/453] [poincare] Enable to set POINCARE_TREE_LOG from environment variable --- poincare/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/Makefile b/poincare/Makefile index 1cf6c7752..bac81600c 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -189,5 +189,5 @@ POINCARE_TREE_LOG ?= 1 endif ifdef POINCARE_TREE_LOG -SFLAGS += -DPOINCARE_TREE_LOG=1 +SFLAGS += -DPOINCARE_TREE_LOG=$(POINCARE_TREE_LOG) endif From 9556ae3aa4dac9d02080b2895e1a36892937067b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 4 Jun 2020 14:51:09 +0200 Subject: [PATCH 394/453] [poincare] Unit: comparison can rely on the pointer addresses only when the object are ordered in a table. Otherwise, the compiler is free to order them as it wants. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the test on the device: 10_m^2→_mm×_km simplifies to 10×_km×_mm --- poincare/include/poincare/unit.h | 2 +- poincare/src/unit.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 5990c6320..cb1e5d946 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -421,7 +421,7 @@ public: Representative::Prefixable::Yes, NegativePrefixes), }; - // TODO: find a better way to find defines these pointers + // TODO: find a better way to define these pointers static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative and so on might require to be fixed if the TimeRepresentatives table was changed."); static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; static const Representative constexpr * MinuteRepresentative = &TimeRepresentatives[1]; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 3941fb7ca..d87346ef9 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -179,10 +179,12 @@ int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascendi } assert(type() == e->type()); const UnitNode * eNode = static_cast(e); + // This works because dimensions are ordered in a table const ptrdiff_t dimdiff = eNode->dimension() - m_dimension; if (dimdiff != 0) { return dimdiff; } + // This works because reprensentatives are ordered in a table const ptrdiff_t repdiff = eNode->representative() - m_representative; if (repdiff != 0) { /* We order representatives in the reverse order as how they're stored in @@ -190,7 +192,7 @@ int UnitNode::simplificationOrderSameType(const ExpressionNode * e, bool ascendi * year + month + days + hours + minutes + seconds. */ return -repdiff; } - const ptrdiff_t prediff = eNode->prefix() - m_prefix; + const ptrdiff_t prediff = eNode->prefix()->exponent() - m_prefix->exponent(); return prediff; } From 2630d0dee206b52f36f81a0525f205d089af3343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 4 Jun 2020 14:54:15 +0200 Subject: [PATCH 395/453] [poincare] Change approximation test to work on the device implementation of libm (hypotf is not as accurate on the device) --- poincare/test/approximation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index ebd0ea712..b48a45200 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -919,7 +919,11 @@ QUIZ_CASE(poincare_approximation_complex_format) { // Overflow assert_expression_approximates_to("-2ᴇ20+2ᴇ20×𝐢", "-2ᴇ20+2ᴇ20×𝐢", Radian, Cartesian); - assert_expression_approximates_to("-2ᴇ20+2ᴇ20×𝐢", "2.828427ᴇ20×ℯ^\u00122.356194×𝐢\u0013", Radian, Polar); + /* TODO: this test fails on the device because libm hypotf (which is called + * eventually by std::abs) is not accurate enough. We might change the + * embedded libm? */ + //assert_expression_approximates_to("-2ᴇ20+2ᴇ20×𝐢", "2.828427ᴇ20×ℯ^\u00122.356194×𝐢\u0013", Radian, Polar); + assert_expression_approximates_to("-2ᴇ10+2ᴇ10×𝐢", "2.828427ᴇ10×ℯ^\u00122.356194×𝐢\u0013", Radian, Polar); assert_expression_approximates_to("1ᴇ155-1ᴇ155×𝐢", "1ᴇ155-1ᴇ155×𝐢", Radian, Cartesian); assert_expression_approximates_to("1ᴇ155-1ᴇ155×𝐢", "1.41421356237ᴇ155×ℯ^\u0012-0.785398163397×𝐢\u0013", Radian, Polar,12); assert_expression_approximates_to("-2ᴇ100+2ᴇ100×𝐢", Undefined::Name()); From 97ffab1fc2e5ca7459d88b1bfdc8dac94342d8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 3 Jun 2020 17:34:26 +0200 Subject: [PATCH 396/453] build: Version 14.0.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index a879199da..bd8babf3c 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 13.0.0 +EPSILON_VERSION ?= 14.0.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0 From 7699dc9929f58881a6533e22920fed813bd69876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jun 2020 10:31:33 +0200 Subject: [PATCH 397/453] [apps/on_boarding] Fix too long i18n --- apps/on_boarding/base.it.i18n | 6 +++--- apps/on_boarding/base.pt.i18n | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/on_boarding/base.it.i18n b/apps/on_boarding/base.it.i18n index 1ea96faea..33ff2bd3c 100644 --- a/apps/on_boarding/base.it.i18n +++ b/apps/on_boarding/base.it.i18n @@ -4,9 +4,9 @@ UpdateMessage2 = "per la vostra calcolatrice." UpdateMessage3 = "Connettetevi dal vostro computer" UpdateMessage4 = "www.numworks.com/update" BetaVersion = "VERSIONE BETA" -BetaVersionMessage1 = "Il vostro dispositivo dispone di una versione beta" -BetaVersionMessage2 = "del software. È possibile che compaiano" -BetaVersionMessage3 = "alcuni bugs." +BetaVersionMessage1 = "Il vostro dispositivo dispone" +BetaVersionMessage2 = "di una versione beta del software." +BetaVersionMessage3 = "Possono comparire alcuni bugs." BetaVersionMessage4 = "Per comunicarci un riscontro" BetaVersionMessage5 = "potete scriverci a" BetaVersionMessage6 = "contact@numworks.com" diff --git a/apps/on_boarding/base.pt.i18n b/apps/on_boarding/base.pt.i18n index c99440636..bd16512a0 100644 --- a/apps/on_boarding/base.pt.i18n +++ b/apps/on_boarding/base.pt.i18n @@ -4,8 +4,8 @@ UpdateMessage2 = "para a sua calculadora." UpdateMessage3 = "Navegue na nossa página no seu computador" UpdateMessage4 = "www.numworks.com/update" BetaVersion = "BETA VERSION" -BetaVersionMessage1 = "" -BetaVersionMessage2 = "O seu dispositivo está a executar um software beta." +BetaVersionMessage1 = "O seu dispositivo está a executar" +BetaVersionMessage2 = "um software beta." BetaVersionMessage3 = "Pode encontrar bugs ou falhas." BetaVersionMessage4 = "" BetaVersionMessage5 = "Por favor envie-nos o seu feedback para" From d53a16eb914bc2308744e3773e2f84089bb888ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jun 2020 11:02:39 +0200 Subject: [PATCH 398/453] [ion/storage] Add TODO --- ion/src/shared/storage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ion/src/shared/storage.cpp b/ion/src/shared/storage.cpp index 95a9fd29d..56fc333ea 100644 --- a/ion/src/shared/storage.cpp +++ b/ion/src/shared/storage.cpp @@ -377,6 +377,9 @@ Storage::Record::Data Storage::valueOfRecord(const Record record) { Storage::Record::ErrorStatus Storage::setValueOfRecord(Record record, Record::Data data) { char * p = pointerOfRecord(record); + /* TODO: if data.buffer == p, assert that size hasn't change and do not do any + * memcopy, but still notify the delegate. Beware of scripts and the accordion + * routine.*/ if (p != nullptr) { record_size_t previousRecordSize = sizeOfRecordStarting(p); const char * fullName = fullNameOfRecordStarting(p); From 9a1ff2bd33c1185a6417f61f613c5c9ae9bf0fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jun 2020 11:28:12 +0200 Subject: [PATCH 399/453] [apps/code] Status at the beginning of a script is one byte long This saves space + avoids clashes with the NumWorks Workshop when exchanging scripts --- apps/code/editor_controller.cpp | 4 ++-- apps/code/script.cpp | 16 ++++++++++------ apps/code/script.h | 19 ++++++++++++++----- apps/code/script_store.cpp | 2 +- apps/code/script_template.cpp | 10 +++++----- apps/code/script_template.h | 2 +- 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index 2c003df88..bee8bb5d9 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -37,7 +37,7 @@ void EditorController::setScript(Script script, int scriptIndex) { * */ size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script); - m_editorView.setText(const_cast(m_script.content()), newScriptSize - Script::InformationSize()); + m_editorView.setText(const_cast(m_script.content()), newScriptSize - Script::StatusSize()); } void EditorController::willExitApp() { @@ -156,7 +156,7 @@ void EditorController::cleanStorageEmptySpace() { Ion::Storage::Record::Data scriptValue = m_script.value(); Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( m_script, - scriptValue.size - Script::InformationSize() - (strlen(m_script.content()) + 1)); // TODO optimize number of script fetches + scriptValue.size - Script::StatusSize() - (strlen(m_script.content()) + 1)); // TODO optimize number of script fetches } diff --git a/apps/code/script.cpp b/apps/code/script.cpp index 6615eed4a..bee1db59f 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -68,19 +68,19 @@ bool Script::nameCompliant(const char * name) { bool Script::autoImportationStatus() const { assert(!isNull()); Data d = value(); - return (((char *)d.buffer)[0] == 1); + return (*statusFromData(d) & k_autoImportationStatusMask) == 1; } void Script::toggleAutoimportationStatus() { assert(!isNull()); Data d = value(); - ((char *)d.buffer)[0] = (((char *)d.buffer)[0] == 1 ? 0 : 1); + *statusFromData(d) ^= k_autoImportationStatusMask; setValue(d); } const char * Script::content() const { Data d = value(); - return ((const char *)d.buffer) + InformationSize(); + return ((const char *)d.buffer) + StatusSize(); } bool Script::contentFetchedFromConsole() const { @@ -106,19 +106,23 @@ void Script::resetContentFetchedStatus() { Script::FetchedStatus Script::fetchedStatus() const { assert(!isNull()); Data d = value(); - uint8_t status = const_cast(static_cast(d.buffer))[k_autoImportationStatusSize]; + uint8_t status = (*statusFromData(d)) >> k_fetchedStatusOffset; assert(status == static_cast(FetchedStatus::None) || status == static_cast(FetchedStatus::FromConsole) || status == static_cast(FetchedStatus::ForVariableBox)); return static_cast(status); } -void Script::setFetchedStatus(FetchedStatus status) { +void Script::setFetchedStatus(FetchedStatus fetchedStatus) { assert(!isNull()); Data d = value(); - const_cast(static_cast(d.buffer))[k_autoImportationStatusSize] = static_cast(status); + uint8_t * status = statusFromData(d); + *status = ((*status) & ~k_fetchedStatusMask) | (static_cast(fetchedStatus) << k_fetchedStatusOffset); //TODO Create and use a bit operations library setValue(d); } +uint8_t * Script::statusFromData(Data d) const { + return const_cast(static_cast(d.buffer)); +} } diff --git a/apps/code/script.h b/apps/code/script.h index b5b1cadf6..fbbb66267 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -5,8 +5,12 @@ namespace Code { -/* Record: | Size | Name | Body | - * Script: | | | AutoImportationStatus | FetchedStatus | Content | +/* Record: | Size | Name | Body | + * Script: | | | Status | Content | + * + * Status is a byte long: xxxxxxxx + * ^^ ^ + * FetchedStatus AutoImportationStatus * * AutoImportationStatus is 1 if the script should be auto imported when the * console opens. @@ -27,8 +31,8 @@ private: static constexpr int k_maxNumberOfDefaultScriptNames = 99; static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max - static constexpr size_t k_autoImportationStatusSize = 1; // TODO use only 1 byte for both status flags - static constexpr size_t k_currentImportationStatusSize = 1; + // See the comment at the beginning of the file + static constexpr size_t k_statusSize = 1; public: static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; @@ -38,7 +42,7 @@ public: static bool DefaultName(char buffer[], size_t bufferSize); static bool nameCompliant(const char * name); - static constexpr size_t InformationSize() { return k_autoImportationStatusSize + k_currentImportationStatusSize; } + static constexpr size_t StatusSize() { return k_statusSize; } Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {} @@ -51,6 +55,10 @@ public: void setContentFetchedForVariableBox(); void resetContentFetchedStatus(); private: + static constexpr uint8_t k_autoImportationStatusMask = 0b1; + static constexpr uint8_t k_fetchedStatusBits = 0b11; + static constexpr uint8_t k_fetchedStatusOffset = 6; + static constexpr uint8_t k_fetchedStatusMask = k_fetchedStatusBits << k_fetchedStatusOffset; /* Fetched status */ enum class FetchedStatus : uint8_t { None = 0, @@ -59,6 +67,7 @@ private: }; FetchedStatus fetchedStatus() const; void setFetchedStatus(FetchedStatus status); + uint8_t * statusFromData(Data d) const; }; } diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index c6b232f13..3062eb01c 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -45,7 +45,7 @@ void ScriptStore::clearFetchInformation() { } Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) { - size_t valueSize = Script::InformationSize() + strlen(scriptTemplate->content()) + 1; // (auto importation status + content fetched status) + scriptcontent size + null-terminating char + size_t valueSize = Script::StatusSize() + strlen(scriptTemplate->content()) + 1; // (auto importation status + content fetched status) + scriptcontent size + null-terminating char assert(Script::nameCompliant(scriptTemplate->name())); Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithFullName(scriptTemplate->name(), scriptTemplate->value(), valueSize); assert(err != Script::ErrorStatus::NonCompliantName); diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index d2d4c9d7a..971b44496 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -2,10 +2,10 @@ namespace Code { -constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01\x00" R"(from math import * +constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import * )"); -constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01\x00" R"(from math import * +constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"(from math import * from turtle import * def squares(angle=0.5): reset() @@ -20,7 +20,7 @@ def squares(angle=0.5): L=L-L*sin(angle*pi/180) hideturtle())"); -constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01\x00" R"(# This script draws a Mandelbrot fractal set +constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set # N_iteration: degree of precision import kandinsky def mandelbrot(N_iteration): @@ -40,7 +40,7 @@ def mandelbrot(N_iteration): # Draw a pixel colored in 'col' at position (x,y) kandinsky.set_pixel(x,y,col))"); -constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01\x00" R"(from math import * +constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import * # roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0 def roots(a,b,c): delta = b*b-4*a*c @@ -53,7 +53,7 @@ def roots(a,b,c): else: return None)"); -constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01\x00" R"(from matplotlib.pyplot import * +constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import * from math import * g=9.81 diff --git a/apps/code/script_template.h b/apps/code/script_template.h index 02a53f87d..ec32e7052 100644 --- a/apps/code/script_template.h +++ b/apps/code/script_template.h @@ -14,7 +14,7 @@ public: static const ScriptTemplate * Polynomial(); static const ScriptTemplate * Parabola(); const char * name() const { return m_name; } - const char * content() const { return m_value + Script::InformationSize(); } + const char * content() const { return m_value + Script::StatusSize(); } const char * value() const { return m_value; } private: const char * m_name; From 84e8ac5bece2f72f59d2e89ed88a7f9cad81d2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jun 2020 15:58:28 +0200 Subject: [PATCH 400/453] [apps/calculation/i18n] Fix typo --- apps/calculation/base.it.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/base.it.i18n b/apps/calculation/base.it.i18n index 351858f44..6544c6622 100644 --- a/apps/calculation/base.it.i18n +++ b/apps/calculation/base.it.i18n @@ -1,6 +1,6 @@ CalculApp = "Calcolo" CalculAppCapital = "CALCOLO" -AdditionalResults = "Ulteriori risultati" +AdditionalResults = "Risultati complementari" DecimalBase = "Decimale" HexadecimalBase = "Esadecimale" BinaryBase = "Binario" From 9bd411f40557ea9473f348a46ac90e9f615171a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jun 2020 17:10:02 +0200 Subject: [PATCH 401/453] [apps/solver] Add test about failing equation resolution --- apps/solver/test/equation_store.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/solver/test/equation_store.cpp b/apps/solver/test/equation_store.cpp index 11952f66a..5a5534a6f 100644 --- a/apps/solver/test/equation_store.cpp +++ b/apps/solver/test/equation_store.cpp @@ -170,6 +170,9 @@ QUIZ_CASE(equation_and_symbolic_computation) { assert_solves_to({"c+d=5", "c-d=1"}, {"c=3", "d=2"}); + set("e", "8_g"); + assert_solves_to({"e+1=0"}, {"e=-1"}); + unset("a"); unset("b"); unset("c"); From 213d3d322d83a9bc925928946c6e199a5d334059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jun 2020 17:11:59 +0200 Subject: [PATCH 402/453] [apps/solver] Fix symbol replacement in equation solving If the symbol replacement led to an undefined reduce equation, we did not realize we could try without replacing the symbol. --- apps/solver/equation_store.cpp | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index a490f4ad7..bdd4b59b6 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -124,7 +124,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool assert(replaceFunctionsButNotSymbols != nullptr); *replaceFunctionsButNotSymbols = false; Error e = privateExactSolve(context, false); - if (e == Error::NoError && numberOfSolutions() == 0 && m_numberOfUserVariables > 0) { + if (m_numberOfUserVariables > 0 && (e != Error::NoError || numberOfSolutions() == 0)) { *replaceFunctionsButNotSymbols = true; e = privateExactSolve(context, true); } @@ -136,11 +136,26 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex m_userVariablesUsed = !replaceFunctionsButNotSymbols; - // Step 0. Get unknown variables + // Step 1. Get unknown and user-defined variables m_variables[0][0] = 0; int numberOfVariables = 0; + + // TODO we look twice for variables but not the same, is there a way to not do the same work twice? + m_userVariables[0][0] = 0; + m_numberOfUserVariables = 0; + for (int i = 0; i < numberOfDefinedModels(); i++) { - const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context, replaceFunctionsButNotSymbols); + Shared::ExpiringPointer eq = modelForRecord(definedRecordAtIndex(i)); + + /* Start by looking for user variables, so that if we escape afterwards, we + * know if it might be due to a user variable. */ + if (m_numberOfUserVariables < Expression::k_maxNumberOfVariables) { + const Expression eWithSymbols = eq->standardForm(context, true); + int varCount = eWithSymbols.getVariables(context, [](const char * symbol, Poincare::Context * context) { return context->expressionTypeForIdentifier(symbol, strlen(symbol)) == Poincare::Context::SymbolAbstractType::Symbol; }, (char *)m_userVariables, Poincare::SymbolAbstract::k_maxNameSize, m_numberOfUserVariables); + m_numberOfUserVariables = varCount < 0 ? Expression::k_maxNumberOfVariables : varCount; + } + + const Expression e = eq->standardForm(context, replaceFunctionsButNotSymbols); // The standard form is memoized so there is no double computation even if replaceFunctionsButNotSymbols is true. if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined) { return Error::EquationUndefined; } @@ -156,21 +171,6 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex assert(numberOfVariables >= 0); } - // Step 1. Get user defined variables - // TODO used previously fetched variables? - m_userVariables[0][0] = 0; - m_numberOfUserVariables = 0; - for (int i = 0; i < numberOfDefinedModels(); i++) { - const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context, true); - assert(!e.isUninitialized() && e.type() != ExpressionNode::Type::Undefined && e.type() != ExpressionNode::Type::Unreal); - int varCount = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return context->expressionTypeForIdentifier(symbol, strlen(symbol)) == Poincare::Context::SymbolAbstractType::Symbol; }, (char *)m_userVariables, Poincare::SymbolAbstract::k_maxNameSize, m_numberOfUserVariables); - if (varCount < 0) { - m_numberOfUserVariables = Expression::k_maxNumberOfVariables; - break; - } - m_numberOfUserVariables = varCount; - } - // Step 2. Linear System? /* Create matrix coefficients and vector constants as: From 1ccb55a16e132bffa7d246591d20c9a261d673d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jun 2020 15:12:13 +0200 Subject: [PATCH 403/453] [apps/code] Fix script importation status Scenario: Execute the script parabola.py, open the variable box, select any leaf, enter, open the variable box again -> no variables are loaded anymore --- apps/code/console_controller.cpp | 2 +- apps/code/script.cpp | 48 +++++++++------------- apps/code/script.h | 57 +++++++++++++-------------- apps/code/script_store.cpp | 14 +++++-- apps/code/script_store.h | 3 +- apps/code/variable_box_controller.cpp | 13 +++--- python/port/port.h | 1 - 7 files changed, 67 insertions(+), 71 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 16a5e4400..2169cb0ba 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -52,7 +52,7 @@ bool ConsoleController::loadPythonEnvironment() { m_pythonDelegate->initPythonWithUser(this); MicroPython::registerScriptProvider(m_scriptStore); m_importScriptsWhenViewAppears = m_autoImportScripts; - m_scriptStore->clearFetchInformation(); + m_scriptStore->clearConsoleFetchInformation(); } return true; } diff --git a/apps/code/script.cpp b/apps/code/script.cpp index bee1db59f..4b39b3452 100644 --- a/apps/code/script.cpp +++ b/apps/code/script.cpp @@ -65,16 +65,18 @@ bool Script::nameCompliant(const char * name) { return false; } +uint8_t * StatusFromData(Script::Data d) { + return const_cast(static_cast(d.buffer)); +} + bool Script::autoImportationStatus() const { - assert(!isNull()); - Data d = value(); - return (*statusFromData(d) & k_autoImportationStatusMask) == 1; + return getStatutBit(k_autoImportationStatusMask); } void Script::toggleAutoimportationStatus() { assert(!isNull()); Data d = value(); - *statusFromData(d) ^= k_autoImportationStatusMask; + *StatusFromData(d) ^= k_autoImportationStatusMask; setValue(d); } @@ -83,46 +85,34 @@ const char * Script::content() const { return ((const char *)d.buffer) + StatusSize(); } -bool Script::contentFetchedFromConsole() const { - return fetchedStatus() == FetchedStatus::FromConsole; +bool Script::fetchedFromConsole() const { + return getStatutBit(k_fetchedFromConsoleMask); } -bool Script::contentFetchedForVariableBox() const { - return fetchedStatus() == FetchedStatus::ForVariableBox; +void Script::setFetchedFromConsole(bool fetched) { + setStatutBit(k_fetchedFromConsoleMask, k_fetchedFromConsoleOffset, fetched); } -void Script::setContentFetchedFromConsole() { - setFetchedStatus(FetchedStatus::FromConsole); +bool Script::fetchedForVariableBox() const { + return getStatutBit(k_fetchedForVariableBoxMask); } -void Script::setContentFetchedForVariableBox() { - setFetchedStatus(FetchedStatus::ForVariableBox); +void Script::setFetchedForVariableBox(bool fetched) { + setStatutBit(k_fetchedForVariableBoxMask, k_fetchedForVariableBoxOffset, fetched); } -void Script::resetContentFetchedStatus() { - setFetchedStatus(FetchedStatus::None); -} - -Script::FetchedStatus Script::fetchedStatus() const { +bool Script::getStatutBit(uint8_t mask) const { assert(!isNull()); Data d = value(); - uint8_t status = (*statusFromData(d)) >> k_fetchedStatusOffset; - assert(status == static_cast(FetchedStatus::None) - || status == static_cast(FetchedStatus::FromConsole) - || status == static_cast(FetchedStatus::ForVariableBox)); - return static_cast(status); + return ((*StatusFromData(d)) & mask) != 0; } -void Script::setFetchedStatus(FetchedStatus fetchedStatus) { +void Script::setStatutBit(uint8_t mask, uint8_t offset, bool statusBit) { assert(!isNull()); Data d = value(); - uint8_t * status = statusFromData(d); - *status = ((*status) & ~k_fetchedStatusMask) | (static_cast(fetchedStatus) << k_fetchedStatusOffset); //TODO Create and use a bit operations library + uint8_t * status = StatusFromData(d); + *status = ((*status) & ~mask) | (static_cast(statusBit) << offset); //TODO Create and use a bit operations library setValue(d); } -uint8_t * Script::statusFromData(Data d) const { - return const_cast(static_cast(d.buffer)); -} - } diff --git a/apps/code/script.h b/apps/code/script.h index fbbb66267..9d2df78c6 100644 --- a/apps/code/script.h +++ b/apps/code/script.h @@ -8,22 +8,22 @@ namespace Code { /* Record: | Size | Name | Body | * Script: | | | Status | Content | * - * Status is a byte long: xxxxxxxx - * ^^ ^ - * FetchedStatus AutoImportationStatus * - * AutoImportationStatus is 1 if the script should be auto imported when the + * |FetchedForVariableBoxBit + * Status is one byte long: xxxxxxxx + * ^ ^ + * FetchedFromConsoleBit AutoImportationBit + * + * AutoImportationBit is 1 if the script should be auto imported when the * console opens. * - * FetchedStatus has two purposes: - * - It is used to detect which scripts are imported in the console, so we can - * retrieve the correct variables afterwards in the variable box. When a - * script has been imported, its fetchedStatus value is - * FetchedStatus::FromConsole. - * - It is used to prevent circular importation problems, such as scriptA - * importing scriptB, which imports scriptA. Once we get the variables from a - * script to put them in the variable box, we switch the status to - * FetchedStatus::ForVariableBox and won't reload it afterwards. */ + * FetchedFromConsoleBit is 1 if its content has been fetched from the console, + * so we can retrieve the correct variables afterwards in the variable box. + * + * FetchedForVariableBoxBit is used to prevent circular importation problems, + * such as scriptA importing scriptB, which imports scriptA. Once we get the + * variables from a script to put them in the variable box, we switch the bit to + * 1 and won't reload it afterwards. */ class Script : public Ion::Storage::Record { private: @@ -49,25 +49,22 @@ public: bool autoImportationStatus() const; void toggleAutoimportationStatus(); const char * content() const; - bool contentFetchedFromConsole() const; - bool contentFetchedForVariableBox() const; - void setContentFetchedFromConsole(); - void setContentFetchedForVariableBox(); - void resetContentFetchedStatus(); + + /* Fetched status */ + bool fetchedFromConsole() const; + void setFetchedFromConsole(bool fetched); + bool fetchedForVariableBox() const; + void setFetchedForVariableBox(bool fetched); + private: static constexpr uint8_t k_autoImportationStatusMask = 0b1; - static constexpr uint8_t k_fetchedStatusBits = 0b11; - static constexpr uint8_t k_fetchedStatusOffset = 6; - static constexpr uint8_t k_fetchedStatusMask = k_fetchedStatusBits << k_fetchedStatusOffset; - /* Fetched status */ - enum class FetchedStatus : uint8_t { - None = 0, - FromConsole = 1, - ForVariableBox = 2 - }; - FetchedStatus fetchedStatus() const; - void setFetchedStatus(FetchedStatus status); - uint8_t * statusFromData(Data d) const; + static constexpr uint8_t k_fetchedForVariableBoxOffset = 7; + static constexpr uint8_t k_fetchedFromConsoleOffset = 6; + static constexpr uint8_t k_fetchedForVariableBoxMask = 0b1 << k_fetchedForVariableBoxOffset; + static constexpr uint8_t k_fetchedFromConsoleMask = 0b1 << k_fetchedFromConsoleOffset; + + bool getStatutBit(uint8_t offset) const; + void setStatutBit(uint8_t mask, uint8_t offset, bool value); }; } diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 3062eb01c..ebc358827 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -31,16 +31,24 @@ const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) return nullptr; } if (markAsFetched) { - script.setContentFetchedFromConsole(); + script.setFetchedFromConsole(true); } return script.content(); } -void ScriptStore::clearFetchInformation() { +void ScriptStore::clearVariableBoxFetchInformation() { // TODO optimize fetches const int scriptsCount = numberOfScripts(); for (int i = 0; i < scriptsCount; i++) { - scriptAtIndex(i).resetContentFetchedStatus(); + scriptAtIndex(i).setFetchedForVariableBox(false); + } +} + +void ScriptStore::clearConsoleFetchInformation() { + // TODO optimize fetches + const int scriptsCount = numberOfScripts(); + for (int i = 0; i < scriptsCount; i++) { + scriptAtIndex(i).setFetchedFromConsole(false); } } diff --git a/apps/code/script_store.h b/apps/code/script_store.h index 3b3cf9a9c..ad9b59ff7 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -40,7 +40,8 @@ public: /* MicroPython::ScriptProvider */ const char * contentOfScript(const char * name, bool markAsFetched) override; - void clearFetchInformation() override; + void clearVariableBoxFetchInformation(); + void clearConsoleFetchInformation(); Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate); private: diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index d884abe32..57fa989e6 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -158,7 +158,7 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha // Reset the node counts empty(); - m_scriptStore->clearFetchInformation(); + if (textToAutocomplete != nullptr && textToAutocompleteLength < 0) { textToAutocompleteLength = strlen(textToAutocomplete); } @@ -180,8 +180,8 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha /* Handle the FetchedStatus: we will import the current script variables in * loadCurrentVariablesInScript, so we do not want to import those variables * before, if any imported script also imported the current script. */ - assert(!script.contentFetchedFromConsole() && !script.contentFetchedForVariableBox()); - script.setContentFetchedForVariableBox(); + assert(!script.fetchedFromConsole() && !script.fetchedForVariableBox()); + script.setFetchedForVariableBox(true); // Load the imported and current variables const char * scriptContent = script.content(); @@ -229,7 +229,7 @@ void VariableBoxController::loadVariablesImportedFromScripts() { const int scriptsCount = m_scriptStore->numberOfScripts(); for (int i = 0; i < scriptsCount; i++) { Script script = m_scriptStore->scriptAtIndex(i); - if (script.contentFetchedFromConsole()) { + if (script.fetchedFromConsole()) { loadGlobalAndImportedVariablesInScriptAsImported(script, nullptr, -1, false); } } @@ -240,6 +240,7 @@ void VariableBoxController::empty() { m_currentScriptNodesCount = 0; m_importedNodesCount = 0; m_shortenResultCharCount = 0; + m_scriptStore->clearVariableBoxFetchInformation(); } void VariableBoxController::insertAutocompletionResultAtIndex(int index) { @@ -628,7 +629,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { - if (script.contentFetchedForVariableBox()) { + if (script.fetchedForVariableBox()) { // We already fetched these script variables return; } @@ -674,7 +675,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Scr nlr_pop(); } // Mark that we already fetched these script variables - script.setContentFetchedForVariableBox(); + script.setFetchedForVariableBox(true); } bool VariableBoxController::addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules) { diff --git a/python/port/port.h b/python/port/port.h index 24a7524bd..75a973887 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -13,7 +13,6 @@ namespace MicroPython { class ScriptProvider { public: virtual const char * contentOfScript(const char * name, bool markAsFetched) = 0; - virtual void clearFetchInformation() = 0; }; class ExecutionEnvironment { From d7fb5c256ce03cb7c2422cfb6726ff4db408f98c Mon Sep 17 00:00:00 2001 From: Arthur Camouseigt Date: Mon, 8 Jun 2020 16:27:14 +0200 Subject: [PATCH 404/453] [turtle] Fixed remanent images bug We now erase the turtle before writing text. This way we can redraw it on top of it, preventing overlapping and remanent images. Those scripts are causing issues : goto(-30,50) write('coucou') left(270) goto(30,50) write('oui') ----------- up() goto(-30,50) write('coucou') goto(30,50) write('oui') Change-Id: I01a6e5f8308937b5051165548c2046883da587d2 --- python/port/mod/turtle/turtle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/port/mod/turtle/turtle.cpp b/python/port/mod/turtle/turtle.cpp index 5c506e576..0b8f85c90 100644 --- a/python/port/mod/turtle/turtle.cpp +++ b/python/port/mod/turtle/turtle.cpp @@ -176,8 +176,8 @@ void Turtle::setVisible(bool visible) { } void Turtle::write(const char * string) { - // To prevent overlapping between the text and the turtle, force redraw - m_drawn = false; + // We erase the turtle to redraw it on top of the text + erase(); MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDContext * ctx = KDIonContext::sharedContext(); static constexpr KDCoordinate headOffsetLength = 6; From bee7441444014a7a6c63e5ee62b4bcf1c400462a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jun 2020 10:48:23 +0200 Subject: [PATCH 405/453] [apps/code] Fix an assertion break Scenario: write a script, execute it in the console and open the variable box, go back to edition and trigger autocompletion. --- apps/code/console_controller.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 2169cb0ba..18fcef5c4 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -52,7 +52,6 @@ bool ConsoleController::loadPythonEnvironment() { m_pythonDelegate->initPythonWithUser(this); MicroPython::registerScriptProvider(m_scriptStore); m_importScriptsWhenViewAppears = m_autoImportScripts; - m_scriptStore->clearConsoleFetchInformation(); } return true; } @@ -61,6 +60,10 @@ void ConsoleController::unloadPythonEnvironment() { if (!m_pythonDelegate->isPythonUser(nullptr)) { m_consoleStore.startNewSession(); m_pythonDelegate->deinitPython(); + /* We clean upon unloading and not upon loading, otherwise we break an + * assertion in VariableBoxController::loadFunctionsAndVariables, which + * checks that the script statuses are clean. */ + m_scriptStore->clearConsoleFetchInformation(); } } From 6e6236a651ade51a17300d9a2fddaeea710cb518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jun 2020 11:57:41 +0200 Subject: [PATCH 406/453] [poincare/integer] Integer::isExtractable This factorizes and fixes wrong isExtractable checks --- poincare/include/poincare/integer.h | 7 +++++-- poincare/src/power.cpp | 4 ++-- poincare/src/unit.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 7140ccd80..88bea3c6b 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -125,8 +125,10 @@ public: bool isZero() const { return (numberOfDigits() == 0); }; bool isEven() const { return ((digit(0) & 1) == 0); } - constexpr static int k_maxExtractableInteger = 0x7FFFFFFF; - int extractedInt() const { assert(numberOfDigits() == 0 || (numberOfDigits() <= 1 && digit(0) <= k_maxExtractableInteger)); return numberOfDigits() == 0 ? 0 : (m_negative ? -digit(0) : digit(0)); } + bool isExtractable() const { + return numberOfDigits() == 0 || (numberOfDigits() <= 1 && digit(0) <= k_maxExtractableInteger); + } + int extractedInt() const { assert(isExtractable()); return numberOfDigits() == 0 ? 0 : (m_negative ? -digit(0) : digit(0)); } // Comparison static int NaturalOrder(const Integer & i, const Integer & j); @@ -152,6 +154,7 @@ public: constexpr static int k_maxNumberOfDigits = 32; private: constexpr static int k_maxNumberOfDigitsBase10 = 308; // (2^32)^k_maxNumberOfDigits ~ 1E308 + constexpr static int k_maxExtractableInteger = 0x7FFFFFFF; // Constructors Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative); diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 525e9a89f..d5913e835 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -73,7 +73,7 @@ int PowerNode::polynomialDegree(Context * context, const char * symbolName) cons return -1; } Integer numeratorInt = r->signedNumerator(); - if (Integer::NaturalOrder(numeratorInt, Integer(Integer::k_maxExtractableInteger)) > 0) { + if (!numeratorInt.isExtractable()) { return -1; } op0Deg *= numeratorInt.extractedInt(); @@ -360,7 +360,7 @@ int Power::getPolynomialCoefficients(Context * context, const char * symbolName, return -1; } Integer num = r.unsignedIntegerNumerator(); - if (Integer::NaturalOrder(num, Integer(Integer::k_maxExtractableInteger)) > 0) { + if (!num.isExtractable()) { return -1; } int n = num.extractedInt(); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index d87346ef9..af9f77b4d 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -350,7 +350,7 @@ void Unit::ChooseBestMultipleForValue(Expression * units, double * value, bool t firstFactor = firstFactor.childAtIndex(0); assert(exp.type() == ExpressionNode::Type::Rational && static_cast(exp).isInteger()); Integer expInt = static_cast(exp).signedIntegerNumerator(); - if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) { + if (expInt.isExtractable()) { exponent = expInt.extractedInt(); } else { // The exponent is too large to be extracted, so do not try to use it. From 555db32670c5334df0ddecf05267bd1681400205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 11 Jun 2020 11:36:45 +0200 Subject: [PATCH 407/453] [apps/code] Fix test on variable_box_controller --- apps/code/test/variable_box_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/test/variable_box_controller.cpp b/apps/code/test/variable_box_controller.cpp index 82b4fd613..2c7e4abfc 100644 --- a/apps/code/test/variable_box_controller.cpp +++ b/apps/code/test/variable_box_controller.cpp @@ -63,7 +63,7 @@ QUIZ_CASE(variable_box_controller) { }; // FIXME This test does not load imported variables for now assert_variables_are( - "from math import *\nfroo=3", + "\x01 from math import *\nfroo=3", "fr", expectedVariables, sizeof(expectedVariables) / sizeof(const char *)); From ad86378a5c43b1c678b5b49ed270f09a10be0541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 11 Jun 2020 12:02:17 +0200 Subject: [PATCH 408/453] [poincare] Unit: -_m should be beautified to -1x_m --- poincare/src/unit.cpp | 2 +- poincare/test/simplification.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index af9f77b4d..b5af7b495 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -329,7 +329,7 @@ Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext Expression Unit::shallowBeautify(ExpressionNode::ReductionContext reductionContext) { // Force Float(1) in front of an orphan Unit - if (parent().isUninitialized()) { + if (parent().isUninitialized() || parent().type() == ExpressionNode::Type::Opposite) { Multiplication m = Multiplication::Builder(Float::Builder(1.0)); replaceWithInPlace(m); m.addChildAtIndexInPlace(*this, 1, 1); diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index cda277afc..32094d201 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -204,6 +204,7 @@ QUIZ_CASE(poincare_simplification_units) { assert_parsed_expression_simplify_to("_K", "1×_K"); assert_parsed_expression_simplify_to("_mol", "1×_mol"); assert_parsed_expression_simplify_to("_cd", "1×_cd"); + assert_parsed_expression_simplify_to("-_s", "-1×_s"); /* Inverses of SI base units */ assert_parsed_expression_simplify_to("_s^-1", "1×_s^\u0012-1\u0013"); From a26dc4be79b1c59f8955eebca6fe2e0cc33bfb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 11 Jun 2020 12:02:48 +0200 Subject: [PATCH 409/453] [apps/calculation/additional_outputs] Expression::removeUnit can be called on reduced expression only --- apps/calculation/additional_outputs/unit_list_controller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index 5f15c86a5..3c48787ad 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -80,6 +80,8 @@ void UnitListController::setExpression(Poincare::Expression e) { } if (canChangeUnitPrefix) { Expression newUnits; + // Reduce to be able to removeUnit + PoincareHelpers::Reduce(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User); m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits); double value = Shared::PoincareHelpers::ApproximateToScalar(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext()); ExpressionNode::ReductionContext reductionContext( From dfef134603b8c478ba210ff6b92da298e86da7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 11 Jun 2020 12:03:21 +0200 Subject: [PATCH 410/453] [poincare] typo --- poincare/include/poincare/unit_convert.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/include/poincare/unit_convert.h b/poincare/include/poincare/unit_convert.h index 3d82eebb5..73379fb1c 100644 --- a/poincare/include/poincare/unit_convert.h +++ b/poincare/include/poincare/unit_convert.h @@ -13,7 +13,7 @@ public: size_t size() const override { return sizeof(UnitConvertNode); } #if POINCARE_TREE_LOG void logNodeName(std::ostream & stream) const override { - stream << "UnivtConvert"; + stream << "UnitConvert"; } #endif // ExpressionNode From ff3b756080360341946595977183bac07f09390f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jun 2020 14:12:50 +0200 Subject: [PATCH 411/453] [apps/console] Fix the script console fetch status cleaning unloadPythonEnvironment is not called when leaving the app, only after editing a script, so it did not do what we wanted. --- apps/code/console_controller.cpp | 12 ++++++++---- apps/code/console_controller.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 18fcef5c4..03d965ba7 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -60,10 +60,6 @@ void ConsoleController::unloadPythonEnvironment() { if (!m_pythonDelegate->isPythonUser(nullptr)) { m_consoleStore.startNewSession(); m_pythonDelegate->deinitPython(); - /* We clean upon unloading and not upon loading, otherwise we break an - * assertion in VariableBoxController::loadFunctionsAndVariables, which - * checks that the script statuses are clean. */ - m_scriptStore->clearConsoleFetchInformation(); } } @@ -199,6 +195,14 @@ void ConsoleController::didBecomeFirstResponder() { } } +void ConsoleController::willExitResponderChain(Responder * nextFirstResponder) { + ViewController::willExitResponderChain(nextFirstResponder); + /* We clean when exiting the responder chain and not when entering it, + * otherwise we break an assertion which checks that the script statuses are + * clean in VariableBoxController::loadFunctionsAndVariables. */ + m_scriptStore->clearConsoleFetchInformation(); +} + bool ConsoleController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { if (m_consoleStore.numberOfLines() > 0 && m_selectableTableView.selectedRow() < m_consoleStore.numberOfLines()) { diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index cd3cae701..b91809ee1 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -38,6 +38,7 @@ public: View * view() override { return &m_selectableTableView; } void viewWillAppear() override; void didBecomeFirstResponder() override; + void willExitResponderChain(Responder * nextFirstResponder) override; bool handleEvent(Ion::Events::Event event) override; ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::WantsMaximumSpace; } TELEMETRY_ID("Console"); From d21c9b08803a79e020f4e20a9d1adb3faf13d85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 12 Jun 2020 13:49:32 +0200 Subject: [PATCH 412/453] [poincare] Expression: clean magic numbers --- poincare/src/expression.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index c6f444236..1fb8778c4 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -126,7 +126,7 @@ bool Expression::deepIsMatrix(Context * context) const { } // Scalar expressions ExpressionNode::Type types1[] = {ExpressionNode::Type::BinomialCoefficient, ExpressionNode::Type::Derivative, ExpressionNode::Type::Determinant, ExpressionNode::Type::DivisionQuotient, ExpressionNode::Type::DivisionRemainder, ExpressionNode::Type::Factor, ExpressionNode::Type::GreatCommonDivisor, ExpressionNode::Type::Integral, ExpressionNode::Type::LeastCommonMultiple, ExpressionNode::Type::MatrixTrace, ExpressionNode::Type::NthRoot, ExpressionNode::Type::PermuteCoefficient, ExpressionNode::Type::Randint, ExpressionNode::Type::Round, ExpressionNode::Type::SignFunction, ExpressionNode::Type::SquareRoot}; - if (isOfType(types1, 16)) { + if (isOfType(types1, sizeof(types1)/sizeof(ExpressionNode::Type))) { return false; } // The children were sorted so any expression which is a matrix (deeply) would be at the end @@ -137,7 +137,7 @@ bool Expression::deepIsMatrix(Context * context) const { } // Logarithm, Power, Product, Sum are matrices only if their first child is a matrix ExpressionNode::Type types2[] = {ExpressionNode::Type::Logarithm, ExpressionNode::Type::Power, ExpressionNode::Type::Product, ExpressionNode::Type::Sum}; - if (isOfType(types2, 4)) { + if (isOfType(types2, sizeof(types2)/sizeof(ExpressionNode::Type))) { assert(numberOfChildren() > 0); return childAtIndex(0).deepIsMatrix(context); } From 1ed97500d027ac5d7a2693e19421633c893820e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 12 Jun 2020 14:12:35 +0200 Subject: [PATCH 413/453] [ion] Increase stack in DEBUG=1 to avoid breaking the test due to stack overflow --- ion/src/simulator/shared/main_headless.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/main_headless.cpp b/ion/src/simulator/shared/main_headless.cpp index 15cf095d6..d4e96e181 100644 --- a/ion/src/simulator/shared/main_headless.cpp +++ b/ion/src/simulator/shared/main_headless.cpp @@ -17,7 +17,7 @@ constexpr int kHeapSize = 131072; #ifdef NDEBUG constexpr int kStackSize = 32768; #else -constexpr int kStackSize = 32768*2; // In DEBUG mode, we increase the stack to be able to pass the tests +constexpr int kStackSize = 32768*10; // In DEBUG mode, we increase the stack to be able to pass the tests #endif char heap[kHeapSize]; From 1cae01b12063a26dfc30ef0c44bc0d9e509d7f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 15 Jun 2020 13:09:03 +0200 Subject: [PATCH 414/453] [apps/solver] Equation: handle circularly defined equations --- apps/solver/equation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/solver/equation.cpp b/apps/solver/equation.cpp index ef578eac7..9c72f454e 100644 --- a/apps/solver/equation.cpp +++ b/apps/solver/equation.cpp @@ -21,7 +21,11 @@ bool Equation::containsIComplex(Context * context) const { Expression Equation::Model::standardForm(const Storage::Record * record, Context * context, bool replaceFunctionsButNotSymbols) const { Expression * returnedExpression = replaceFunctionsButNotSymbols ? &m_standardFormWithReplacedFunctionsButNotSymbols : &m_standardFormWithReplacedFunctionsAndSymbols; if (returnedExpression->isUninitialized()) { - const Expression expressionInputWithoutFunctions = Expression::ExpressionWithoutSymbols(expressionClone(record), context, replaceFunctionsButNotSymbols); + Expression expressionInputWithoutFunctions = Expression::ExpressionWithoutSymbols(expressionClone(record), context, replaceFunctionsButNotSymbols); + if (expressionInputWithoutFunctions.isUninitialized()) { + // The expression is circularly-defined + expressionInputWithoutFunctions = Undefined::Builder(); + } EmptyContext emptyContext; Context * contextToUse = replaceFunctionsButNotSymbols ? &emptyContext : context; From 1f0b3770e35543626ceb2fb62785d71f985632fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jun 2020 13:25:07 +0200 Subject: [PATCH 415/453] [apps/code] Fix syntaxic coloration Scenario: +, -, / operators where no longer properly colored during script edition. This was due to the MicroPython update, which changed the lexer tokens order. --- apps/code/python_text_area.cpp | 91 ++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp index 77a6f299b..e89e6005b 100644 --- a/apps/code/python_text_area.cpp +++ b/apps/code/python_text_area.cpp @@ -31,13 +31,96 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) { if (tokenKind == MP_TOKEN_INTEGER || tokenKind == MP_TOKEN_FLOAT_OR_IMAG) { return NumberColor; } + static_assert(MP_TOKEN_ELLIPSIS + 1 == MP_TOKEN_KW_FALSE + && MP_TOKEN_KW_FALSE + 1 == MP_TOKEN_KW_NONE + && MP_TOKEN_KW_NONE + 1 == MP_TOKEN_KW_TRUE + && MP_TOKEN_KW_TRUE + 1 == MP_TOKEN_KW___DEBUG__ + && MP_TOKEN_KW___DEBUG__ + 1 == MP_TOKEN_KW_AND + && MP_TOKEN_KW_AND + 1 == MP_TOKEN_KW_AS + && MP_TOKEN_KW_AS + 1 == MP_TOKEN_KW_ASSERT + /* Here there are keywords that depend on MICROPY_PY_ASYNC_AWAIT, we do + * not test them */ + && MP_TOKEN_KW_BREAK + 1 == MP_TOKEN_KW_CLASS + && MP_TOKEN_KW_CLASS + 1 == MP_TOKEN_KW_CONTINUE + && MP_TOKEN_KW_CONTINUE + 1 == MP_TOKEN_KW_DEF + && MP_TOKEN_KW_DEF + 1 == MP_TOKEN_KW_DEL + && MP_TOKEN_KW_DEL + 1 == MP_TOKEN_KW_ELIF + && MP_TOKEN_KW_ELIF + 1 == MP_TOKEN_KW_ELSE + && MP_TOKEN_KW_ELSE + 1 == MP_TOKEN_KW_EXCEPT + && MP_TOKEN_KW_EXCEPT + 1 == MP_TOKEN_KW_FINALLY + && MP_TOKEN_KW_FINALLY + 1 == MP_TOKEN_KW_FOR + && MP_TOKEN_KW_FOR + 1 == MP_TOKEN_KW_FROM + && MP_TOKEN_KW_FROM + 1 == MP_TOKEN_KW_GLOBAL + && MP_TOKEN_KW_GLOBAL + 1 == MP_TOKEN_KW_IF + && MP_TOKEN_KW_IF + 1 == MP_TOKEN_KW_IMPORT + && MP_TOKEN_KW_IMPORT + 1 == MP_TOKEN_KW_IN + && MP_TOKEN_KW_IN + 1 == MP_TOKEN_KW_IS + && MP_TOKEN_KW_IS + 1 == MP_TOKEN_KW_LAMBDA + && MP_TOKEN_KW_LAMBDA + 1 == MP_TOKEN_KW_NONLOCAL + && MP_TOKEN_KW_NONLOCAL + 1 == MP_TOKEN_KW_NOT + && MP_TOKEN_KW_NOT + 1 == MP_TOKEN_KW_OR + && MP_TOKEN_KW_OR + 1 == MP_TOKEN_KW_PASS + && MP_TOKEN_KW_PASS + 1 == MP_TOKEN_KW_RAISE + && MP_TOKEN_KW_RAISE + 1 == MP_TOKEN_KW_RETURN + && MP_TOKEN_KW_RETURN + 1 == MP_TOKEN_KW_TRY + && MP_TOKEN_KW_TRY + 1 == MP_TOKEN_KW_WHILE + && MP_TOKEN_KW_WHILE + 1 == MP_TOKEN_KW_WITH + && MP_TOKEN_KW_WITH + 1 == MP_TOKEN_KW_YIELD + && MP_TOKEN_KW_YIELD + 1 == MP_TOKEN_OP_TILDE, + "MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too."); if (tokenKind >= MP_TOKEN_KW_FALSE && tokenKind <= MP_TOKEN_KW_YIELD) { return KeywordColor; } - if (tokenKind >= MP_TOKEN_OP_PLUS && tokenKind <= MP_TOKEN_OP_NOT_EQUAL) { - return OperatorColor; - } - if (tokenKind >= MP_TOKEN_DEL_EQUAL && tokenKind <= MP_TOKEN_DEL_MINUS_MORE) { + static_assert(MP_TOKEN_OP_TILDE + 1 == MP_TOKEN_OP_LESS + && MP_TOKEN_OP_LESS + 1 == MP_TOKEN_OP_MORE + && MP_TOKEN_OP_MORE + 1 == MP_TOKEN_OP_DBL_EQUAL + && MP_TOKEN_OP_DBL_EQUAL + 1 == MP_TOKEN_OP_LESS_EQUAL + && MP_TOKEN_OP_LESS_EQUAL + 1 == MP_TOKEN_OP_MORE_EQUAL + && MP_TOKEN_OP_MORE_EQUAL + 1 == MP_TOKEN_OP_NOT_EQUAL + && MP_TOKEN_OP_NOT_EQUAL + 1 == MP_TOKEN_OP_PIPE + && MP_TOKEN_OP_PIPE + 1 == MP_TOKEN_OP_CARET + && MP_TOKEN_OP_CARET + 1 == MP_TOKEN_OP_AMPERSAND + && MP_TOKEN_OP_AMPERSAND + 1 == MP_TOKEN_OP_DBL_LESS + && MP_TOKEN_OP_DBL_LESS + 1 == MP_TOKEN_OP_DBL_MORE + && MP_TOKEN_OP_DBL_MORE + 1 == MP_TOKEN_OP_PLUS + && MP_TOKEN_OP_PLUS + 1 == MP_TOKEN_OP_MINUS + && MP_TOKEN_OP_MINUS + 1 == MP_TOKEN_OP_STAR + && MP_TOKEN_OP_STAR + 1 == MP_TOKEN_OP_AT + && MP_TOKEN_OP_AT + 1 == MP_TOKEN_OP_DBL_SLASH + && MP_TOKEN_OP_DBL_SLASH + 1 == MP_TOKEN_OP_SLASH + && MP_TOKEN_OP_SLASH + 1 == MP_TOKEN_OP_PERCENT + && MP_TOKEN_OP_PERCENT + 1 == MP_TOKEN_OP_DBL_STAR + && MP_TOKEN_OP_DBL_STAR + 1 == MP_TOKEN_DEL_PIPE_EQUAL + && MP_TOKEN_DEL_PIPE_EQUAL + 1 == MP_TOKEN_DEL_CARET_EQUAL + && MP_TOKEN_DEL_CARET_EQUAL + 1 == MP_TOKEN_DEL_AMPERSAND_EQUAL + && MP_TOKEN_DEL_AMPERSAND_EQUAL + 1 == MP_TOKEN_DEL_DBL_LESS_EQUAL + && MP_TOKEN_DEL_DBL_LESS_EQUAL + 1 == MP_TOKEN_DEL_DBL_MORE_EQUAL + && MP_TOKEN_DEL_DBL_MORE_EQUAL + 1 == MP_TOKEN_DEL_PLUS_EQUAL + && MP_TOKEN_DEL_PLUS_EQUAL + 1 == MP_TOKEN_DEL_MINUS_EQUAL + && MP_TOKEN_DEL_MINUS_EQUAL + 1 == MP_TOKEN_DEL_STAR_EQUAL + && MP_TOKEN_DEL_STAR_EQUAL + 1 == MP_TOKEN_DEL_AT_EQUAL + && MP_TOKEN_DEL_AT_EQUAL + 1 == MP_TOKEN_DEL_DBL_SLASH_EQUAL + && MP_TOKEN_DEL_DBL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_SLASH_EQUAL + && MP_TOKEN_DEL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_PERCENT_EQUAL + && MP_TOKEN_DEL_PERCENT_EQUAL + 1 == MP_TOKEN_DEL_DBL_STAR_EQUAL + && MP_TOKEN_DEL_DBL_STAR_EQUAL + 1 == MP_TOKEN_DEL_PAREN_OPEN + && MP_TOKEN_DEL_PAREN_OPEN + 1 == MP_TOKEN_DEL_PAREN_CLOSE + && MP_TOKEN_DEL_PAREN_CLOSE + 1 == MP_TOKEN_DEL_BRACKET_OPEN + && MP_TOKEN_DEL_BRACKET_OPEN + 1 == MP_TOKEN_DEL_BRACKET_CLOSE + && MP_TOKEN_DEL_BRACKET_CLOSE + 1 == MP_TOKEN_DEL_BRACE_OPEN + && MP_TOKEN_DEL_BRACE_OPEN + 1 == MP_TOKEN_DEL_BRACE_CLOSE + && MP_TOKEN_DEL_BRACE_CLOSE + 1 == MP_TOKEN_DEL_COMMA + && MP_TOKEN_DEL_COMMA + 1 == MP_TOKEN_DEL_COLON + && MP_TOKEN_DEL_COLON + 1 == MP_TOKEN_DEL_PERIOD + && MP_TOKEN_DEL_PERIOD + 1 == MP_TOKEN_DEL_SEMICOLON + && MP_TOKEN_DEL_SEMICOLON + 1 == MP_TOKEN_DEL_EQUAL + && MP_TOKEN_DEL_EQUAL + 1 == MP_TOKEN_DEL_MINUS_MORE, + "MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too."); + + if ((tokenKind >= MP_TOKEN_OP_TILDE && tokenKind <= MP_TOKEN_DEL_DBL_STAR_EQUAL) + || tokenKind == MP_TOKEN_DEL_EQUAL + || tokenKind == MP_TOKEN_DEL_MINUS_MORE) + { return OperatorColor; } return DefaultColor; From cf4eaa3d1fc692d03697b87ce53f536171a3967d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jun 2020 15:39:04 +0200 Subject: [PATCH 416/453] [apps/poincare] Use symbolicComputation in recursivelyMatches This fixes a failed assertion for the scenario: [3]->x then, in the Equation app, solve x+1->0 --- apps/calculation/calculation.cpp | 2 +- apps/solver/equation.cpp | 5 ++-- apps/solver/equation_store.cpp | 2 +- poincare/include/poincare/expression.h | 2 +- poincare/include/poincare/expression_node.h | 3 ++- poincare/src/addition.cpp | 4 +-- poincare/src/expression.cpp | 29 ++++++++++++++++----- poincare/src/function.cpp | 3 +++ poincare/src/multiplication.cpp | 4 +-- poincare/src/symbol.cpp | 4 ++- poincare/src/symbol_abstract.cpp | 6 +++-- poincare/test/context.cpp | 4 +-- poincare/test/expression_properties.cpp | 5 ++-- poincare/test/helper.h | 1 + 14 files changed, 49 insertions(+), 25 deletions(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index ba3d46532..7a7a9e425 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -176,7 +176,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { ExpressionNode::Type::PredictionInterval }; return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type)); - }, context, true) + }, context) ) { m_displayOutput = DisplayOutput::ApproximateOnly; diff --git a/apps/solver/equation.cpp b/apps/solver/equation.cpp index 9c72f454e..80d2a4cab 100644 --- a/apps/solver/equation.cpp +++ b/apps/solver/equation.cpp @@ -15,7 +15,7 @@ using namespace Shared; namespace Solver { bool Equation::containsIComplex(Context * context) const { - return expressionClone().recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context, true); + return expressionClone().recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context); } Expression Equation::Model::standardForm(const Storage::Record * record, Context * context, bool replaceFunctionsButNotSymbols) const { @@ -44,8 +44,7 @@ Expression Equation::Model::standardForm(const Storage::Record * record, Context [](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context); }, - contextToUse, - true)) + contextToUse)) { *returnedExpression = Undefined::Builder(); } else if (expressionRed.type() == ExpressionNode::Type::Equal) { diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index bdd4b59b6..867a19d7c 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -156,7 +156,7 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex } const Expression e = eq->standardForm(context, replaceFunctionsButNotSymbols); // The standard form is memoized so there is no double computation even if replaceFunctionsButNotSymbols is true. - if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined) { + if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined || e.recursivelyMatches(Expression::IsMatrix, context, replaceFunctionsButNotSymbols ? ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions : ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition)) { return Error::EquationUndefined; } if (e.type() == ExpressionNode::Type::Unreal) { diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 14def7d80..6bdb4008e 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -151,7 +151,7 @@ public: bool isDivisionOfIntegers() const; bool hasDefinedComplexApproximation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; typedef bool (*ExpressionTest)(const Expression e, Context * context); - bool recursivelyMatches(ExpressionTest test, Context * context, bool replaceSymbols = true) const; + bool recursivelyMatches(ExpressionTest test, Context * context, ExpressionNode::SymbolicComputation replaceSymbols = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) const; typedef bool (*ExpressionTypeTest)(const Expression e, const void * context); bool hasExpression(ExpressionTypeTest test, const void * context) const; // WARNING: this method must be called on reduced (sorted) expressions diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index ef9f6a81a..2d3b33a33 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -128,7 +128,8 @@ public: ReplaceAllSymbolsWithDefinitionsOrUndefined = 0, ReplaceAllDefinedSymbolsWithDefinition = 1, ReplaceDefinedFunctionsWithDefinitions = 2, - ReplaceAllSymbolsWithUndefined = 3 // Used in UnitConvert::shallowReduce + ReplaceAllSymbolsWithUndefined = 3, // Used in UnitConvert::shallowReduce + DoNotReplaceAnySymbol = 4 }; enum class UnitConversion { None = 0, diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 076c054b7..141cf5a5f 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -355,7 +355,7 @@ bool Addition::TermsHaveIdenticalNonNumeralFactors(const Expression & e1, const int numberOfNonNumeralFactors = numberOfNonNumeralFactorsInE1; if (numberOfNonNumeralFactors == 1) { Expression nonNumeralFactor = FirstNonNumeralFactor(e1); - if (nonNumeralFactor.recursivelyMatches(Expression::IsRandom, context, true)) { + if (nonNumeralFactor.recursivelyMatches(Expression::IsRandom, context)) { return false; } return FirstNonNumeralFactor(e1).isIdenticalTo(FirstNonNumeralFactor(e2)); @@ -380,7 +380,7 @@ Expression Addition::factorizeOnCommonDenominator(ExpressionNode::ReductionConte Expression childI = childAtIndex(i); Expression currentDenominator = childI.denominator(reductionContext); if (!currentDenominator.isUninitialized()) { - if (currentDenominator.recursivelyMatches(Expression::IsRandom, reductionContext.context(), true)) { + if (currentDenominator.recursivelyMatches(Expression::IsRandom, reductionContext.context())) { // Remove "random" factors removeChildInPlace(childI, childI.numberOfChildren()); a.addChildAtIndexInPlace(childI, a.numberOfChildren(), a.numberOfChildren()); diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 1fb8778c4..41b9b04bd 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -87,14 +87,29 @@ bool Expression::isRationalOne() const { return type() == ExpressionNode::Type::Rational && convert().isOne(); } -bool Expression::recursivelyMatches(ExpressionTest test, Context * context, bool replaceSymbols) const { +bool Expression::recursivelyMatches(ExpressionTest test, Context * context, ExpressionNode::SymbolicComputation replaceSymbols) const { if (test(*this, context)) { return true; } + + // Handle symbols and functions ExpressionNode::Type t = type(); - if (replaceSymbols && (t == ExpressionNode::Type::Symbol || t == ExpressionNode::Type::Function)) { - return SymbolAbstract::matches(convert(), test, context); + if (t == ExpressionNode::Type::Symbol || t == ExpressionNode::Type::Function) { + assert(replaceSymbols == ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition + || replaceSymbols == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions + || replaceSymbols == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol); // We need only those cases for now + + if (replaceSymbols == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol + || (replaceSymbols == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions + && t == ExpressionNode::Type::Symbol)) + { + return false; + } + assert(replaceSymbols == ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition + || t == ExpressionNode::Type::Function); + return SymbolAbstract::matches(convert(), test, context); } + const int childrenCount = this->numberOfChildren(); for (int i = 0; i < childrenCount; i++) { if (childAtIndex(i).recursivelyMatches(test, context, replaceSymbols)) { @@ -197,7 +212,7 @@ bool containsVariables(const Expression e, char * variables, int maxVariableSize } bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Expression coefficients[], Expression constant[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) const { - assert(!recursivelyMatches(IsMatrix, context, true)); + assert(!recursivelyMatches(IsMatrix, context, symbolicComputation)); // variables is in fact of type char[k_maxNumberOfVariables][maxVariableSize] int index = 0; while (variables[index*maxVariableSize] != 0) { @@ -223,7 +238,7 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex /* degree is supposed to be 0 or 1. Otherwise, it means that equation * is 'undefined' due to the reduction of 0*inf for example. * (ie, x*y*inf = 0) */ - assert(!recursivelyMatches([](const Expression e, Context * context) { return e.isUndefined(); }, context, true)); + assert(!recursivelyMatches([](const Expression e, Context * context) { return e.isUndefined(); }, context)); return false; } /* The equation is can be written: a_1*x+a_0 with a_1 and a_0 x-independent. @@ -473,7 +488,7 @@ int Expression::getPolynomialReducedCoefficients(const char * symbolName, Expres /* Units */ bool Expression::hasUnit() const { - return recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Unit; }, nullptr, false); + return recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Unit; }, nullptr, ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol); } /* Complex */ @@ -494,7 +509,7 @@ Preferences::ComplexFormat Expression::UpdatedComplexFormatWithTextInput(Prefere } Preferences::ComplexFormat Expression::UpdatedComplexFormatWithExpressionInput(Preferences::ComplexFormat complexFormat, const Expression & exp, Context * context) { - if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context, true)) { + if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Constant && static_cast(e).isIComplex(); }, context)) { return Preferences::ComplexFormat::Cartesian; } return complexFormat; diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 6aa0695d6..ae5764af2 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -120,6 +120,9 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon { return replaceWithUndefinedInPlace(); } + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol) { + return *this; + } Expression result = SymbolAbstract::Expand(*this, reductionContext.context(), true, reductionContext.symbolicComputation()); if (result.isUninitialized()) { if (reductionContext.symbolicComputation() != ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined) { diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 0f6e806d8..509e2696f 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -598,7 +598,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext while (i < numberOfChildren()-1) { Expression oi = childAtIndex(i); Expression oi1 = childAtIndex(i+1); - if (oi.recursivelyMatches(Expression::IsRandom, context, true)) { + if (oi.recursivelyMatches(Expression::IsRandom, context)) { // Do not factorize random or randint } else if (TermsHaveIdenticalBase(oi, oi1)) { bool shouldFactorizeBase = true; @@ -715,7 +715,7 @@ Expression Multiplication::privateShallowReduce(ExpressionNode::ReductionContext * reduce expressions such as (x+y)^(-1)*(x+y)(a+b). * If there is a random somewhere, do not expand. */ Expression p = parent(); - bool hasRandom = recursivelyMatches(Expression::IsRandom, context, true); + bool hasRandom = recursivelyMatches(Expression::IsRandom, context); if (shouldExpand && (p.isUninitialized() || p.type() != ExpressionNode::Type::Multiplication) && !hasRandom) diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 3a2a47c50..b1f1f1687 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -151,7 +151,9 @@ bool Symbol::isRegressionSymbol(const char * c, Poincare::Context * context) { } Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionContext) { - if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions) { + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions + || reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol) + { return *this; } if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined) { diff --git a/poincare/src/symbol_abstract.cpp b/poincare/src/symbol_abstract.cpp index 2d8b31f8b..61c679767 100644 --- a/poincare/src/symbol_abstract.cpp +++ b/poincare/src/symbol_abstract.cpp @@ -62,12 +62,14 @@ size_t SymbolAbstract::TruncateExtension(char * dst, const char * src, size_t le bool SymbolAbstract::matches(const SymbolAbstract & symbol, ExpressionTest test, Context * context) { Expression e = SymbolAbstract::Expand(symbol, context, false); - return !e.isUninitialized() && e.recursivelyMatches(test, context, false); + return !e.isUninitialized() && e.recursivelyMatches(test, context, ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol); } Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context * context, bool clone, ExpressionNode::SymbolicComputation symbolicComputation) { bool shouldNotReplaceSymbols = symbolicComputation == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions; - if (symbol.type() == ExpressionNode::Type::Symbol && shouldNotReplaceSymbols) { + if (symbolicComputation == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol + || (symbol.type() == ExpressionNode::Type::Symbol && shouldNotReplaceSymbols)) + { return clone ? symbol.clone() : *const_cast(&symbol); } Expression e = context->expressionForSymbolAbstract(symbol, clone); diff --git a/poincare/test/context.cpp b/poincare/test/context.cpp index 9137d02df..b8b8d64dd 100644 --- a/poincare/test/context.cpp +++ b/poincare/test/context.cpp @@ -205,7 +205,7 @@ QUIZ_CASE(poincare_context_user_variable_properties) { quiz_assert(Symbol::Builder('a').recursivelyMatches(Expression::IsMatrix, &context)); assert_expression_approximates_to("1.2→b", "1.2"); - quiz_assert(Symbol::Builder('b').recursivelyMatches(Expression::IsApproximate, &context, true)); + quiz_assert(Symbol::Builder('b').recursivelyMatches(Expression::IsApproximate, &context)); /* [[x]]→f(x) expression contains a matrix, so its simplification is going * to be interrupted. We thus rather approximate it instead of simplifying it. @@ -214,7 +214,7 @@ QUIZ_CASE(poincare_context_user_variable_properties) { assert_expression_approximates_to("[[x]]→f(x)", "[[undef]]"); quiz_assert(Function::Builder("f", 1, Symbol::Builder('x')).recursivelyMatches(Poincare::Expression::IsMatrix, &context)); assert_expression_approximates_to("0.2*x→g(x)", "undef"); - quiz_assert(Function::Builder("g", 1, Rational::Builder(2)).recursivelyMatches(Expression::IsApproximate, &context, true)); + quiz_assert(Function::Builder("g", 1, Rational::Builder(2)).recursivelyMatches(Expression::IsApproximate, &context)); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index c595aa0d5..90b986427 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -35,12 +35,12 @@ QUIZ_CASE(poincare_properties_is_parametered_expression) { void assert_expression_has_property(const char * expression, Context * context, Expression::ExpressionTest test) { Expression e = parse_expression(expression, context, false); - quiz_assert_print_if_failure(e.recursivelyMatches(test, context, true), expression); + quiz_assert_print_if_failure(e.recursivelyMatches(test, context), expression); } void assert_expression_has_not_property(const char * expression, Context * context, Expression::ExpressionTest test) { Expression e = parse_expression(expression, context, false); - quiz_assert_print_if_failure(!e.recursivelyMatches(test, context, true), expression); + quiz_assert_print_if_failure(!e.recursivelyMatches(test, context), expression); } QUIZ_CASE(poincare_properties_is_approximate) { @@ -360,6 +360,7 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) { const char * coefficient7[] = {"4", 0}; assert_reduced_expression_has_polynomial_coefficient("x+1", "x", coefficient7 ); const char * coefficient8[] = {"2", "1", 0}; + assert_reduced_expression_has_polynomial_coefficient("x+2", "x", coefficient8, Real, Radian, DoNotReplaceAnySymbol); assert_reduced_expression_has_polynomial_coefficient("x+2", "x", coefficient8, Real, Radian, ReplaceDefinedFunctionsWithDefinitions); assert_reduced_expression_has_polynomial_coefficient("f(x)", "x", coefficient4, Cartesian, Radian, ReplaceDefinedFunctionsWithDefinitions); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 229ef4274..6ef23c361 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -12,6 +12,7 @@ constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllDefinedSymbols constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithDefinitionsOrUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined; constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceDefinedFunctionsWithDefinitions = Poincare::ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions; constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined; +constexpr Poincare::ExpressionNode::SymbolicComputation DoNotReplaceAnySymbol = Poincare::ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol; constexpr Poincare::ExpressionNode::UnitConversion NoUnitConversion = Poincare::ExpressionNode::UnitConversion::None; constexpr Poincare::ExpressionNode::UnitConversion DefaultUnitConversion = Poincare::ExpressionNode::UnitConversion::Default; constexpr Poincare::ExpressionNode::UnitConversion InternationalSystemUnitConversion = Poincare::ExpressionNode::UnitConversion::InternationalSystem; From 1045f546332235dc60f08b8100f5d8f645388f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jun 2020 12:08:48 +0200 Subject: [PATCH 417/453] [apps/code] Fix variables loading in the console Scenario: execute a script, open the variable box, select a leaf, reopen the variable box -> it shows empty --- apps/code/console_controller.cpp | 9 +-------- apps/code/console_controller.h | 1 - apps/code/variable_box_controller.cpp | 9 +++++---- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 03d965ba7..db621ec98 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -173,6 +173,7 @@ const char * ConsoleController::inputText(const char * prompt) { void ConsoleController::viewWillAppear() { ViewController::viewWillAppear(); + m_scriptStore->clearConsoleFetchInformation(); loadPythonEnvironment(); if (m_importScriptsWhenViewAppears) { m_importScriptsWhenViewAppears = false; @@ -195,14 +196,6 @@ void ConsoleController::didBecomeFirstResponder() { } } -void ConsoleController::willExitResponderChain(Responder * nextFirstResponder) { - ViewController::willExitResponderChain(nextFirstResponder); - /* We clean when exiting the responder chain and not when entering it, - * otherwise we break an assertion which checks that the script statuses are - * clean in VariableBoxController::loadFunctionsAndVariables. */ - m_scriptStore->clearConsoleFetchInformation(); -} - bool ConsoleController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { if (m_consoleStore.numberOfLines() > 0 && m_selectableTableView.selectedRow() < m_consoleStore.numberOfLines()) { diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index b91809ee1..cd3cae701 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -38,7 +38,6 @@ public: View * view() override { return &m_selectableTableView; } void viewWillAppear() override; void didBecomeFirstResponder() override; - void willExitResponderChain(Responder * nextFirstResponder) override; bool handleEvent(Ion::Events::Event event) override; ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::WantsMaximumSpace; } TELEMETRY_ID("Console"); diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 57fa989e6..75c000edd 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -177,10 +177,11 @@ void VariableBoxController::loadFunctionsAndVariables(int scriptIndex, const cha Script script = m_scriptStore->scriptAtIndex(scriptIndex); assert(!script.isNull()); - /* Handle the FetchedStatus: we will import the current script variables in - * loadCurrentVariablesInScript, so we do not want to import those variables - * before, if any imported script also imported the current script. */ - assert(!script.fetchedFromConsole() && !script.fetchedForVariableBox()); + /* Handle the fetchedForVariableBox status: we will import the current script + * variables in loadCurrentVariablesInScript, so we do not want to import + * those variables before, if any imported script also imported the current + * script. */ + assert(!script.fetchedForVariableBox()); script.setFetchedForVariableBox(true); // Load the imported and current variables From ef210f9cff5e86e8d8e09295e5bdc858380a4f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 19 Jun 2020 10:39:43 +0200 Subject: [PATCH 418/453] build: Version 14.1.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index bd8babf3c..d72699321 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 14.0.0 +EPSILON_VERSION ?= 14.1.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0 From 2d1d3ca944adc0129e8f4cb62c92c8cd6ad5cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 25 Jun 2020 11:31:01 +0200 Subject: [PATCH 419/453] [apps/code] Fix variables loading in the console The two following scenari display empty variable boxes, when there should be loaded variables. 1) Open the console, go back to the scripts menu, go back to the console, open the variable box 2) Open the console, execute mandelbrot, open the variable box --- apps/code/console_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index db621ec98..8bae83090 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -48,6 +48,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe bool ConsoleController::loadPythonEnvironment() { if (!m_pythonDelegate->isPythonUser(this)) { + m_scriptStore->clearConsoleFetchInformation(); emptyOutputAccumulationBuffer(); m_pythonDelegate->initPythonWithUser(this); MicroPython::registerScriptProvider(m_scriptStore); @@ -173,7 +174,6 @@ const char * ConsoleController::inputText(const char * prompt) { void ConsoleController::viewWillAppear() { ViewController::viewWillAppear(); - m_scriptStore->clearConsoleFetchInformation(); loadPythonEnvironment(); if (m_importScriptsWhenViewAppears) { m_importScriptsWhenViewAppears = false; From bac2949a5e9993d4d85c6ef4e858f19da726ec07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 25 Jun 2020 13:46:28 +0200 Subject: [PATCH 420/453] [escher][apps] SelectableTableViewDelegate: add tableViewDidChangeSelectionAndDidScroll method and implement it for Calculation::HistoryController This fixes the following bug: In the calculation application, input 1, OK, 1/2/3/4/5/6/7/8, OK, up, up, left, down, up. The selection failed. --- apps/calculation/history_controller.cpp | 6 ++--- apps/calculation/history_controller.h | 2 +- apps/code/console_controller.cpp | 2 +- apps/code/console_controller.h | 2 +- apps/home/controller.cpp | 27 +++++++++++-------- apps/home/controller.h | 1 + .../list/list_parameter_controller.cpp | 2 +- .../sequence/list/list_parameter_controller.h | 2 +- .../escher/selectable_table_view_delegate.h | 1 + escher/src/selectable_table_view.cpp | 4 +++ 10 files changed, 30 insertions(+), 19 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index a9bbc1e1e..e2cbf20f2 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -40,7 +40,7 @@ void HistoryController::reload() { if (numberOfRows() > 0) { m_selectableTableView.scrollToCell(0, numberOfRows()-1); // Force to reload last added cell (hide the burger and exact output if necessary) - tableViewDidChangeSelection(&m_selectableTableView, 0, numberOfRows()-1); + tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, numberOfRows()-1); } } @@ -128,7 +128,7 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); - tableViewDidChangeSelection(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); + tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); m_selectableTableView.scrollToCell(0, selectedRow()); return true; } @@ -151,7 +151,7 @@ Shared::ExpiringPointer HistoryController::calculationAtIndex(int i return m_calculationStore->calculationAtIndex(storeIndex(i)); } -void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { +void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { if (withinTemporarySelection || previousSelectedCellY == selectedRow()) { return; } diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index 2cb20840a..64d75755c 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -31,7 +31,7 @@ public: void willDisplayCellForIndex(HighlightCell * cell, int index) override; KDCoordinate rowHeight(int j) override; int typeAtLocation(int i, int j) override; - void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; + void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; private: int storeIndex(int i) { return numberOfRows() - i - 1; } Shared::ExpiringPointer calculationAtIndex(int i); diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 8bae83090..de947fa9c 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -285,7 +285,7 @@ void ConsoleController::willDisplayCellAtLocation(HighlightCell * cell, int i, i } } -void ConsoleController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { +void ConsoleController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { if (withinTemporarySelection) { return; } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index cd3cae701..ff79e7b51 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -53,7 +53,7 @@ public: void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; // SelectableTableViewDelegate - void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; + void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; // TextFieldDelegate bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index b2f779d1a..50af28bfb 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -140,7 +140,21 @@ int Controller::numberOfIcons() const { } void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { - AppsContainer * container = AppsContainer::sharedAppsContainer(); + if (withinTemporarySelection) { + return; + } + /* To prevent the selectable table view to select cells that are unvisible, + * we reselect the previous selected cell as soon as the selected cell is + * unvisible. This trick does not create an endless loop as we ensure not to + * stay on a unvisible cell and to initialize the first cell on a visible one + * (so the previous one is always visible). */ + int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1; + if (appIndex >= AppsContainer::sharedAppsContainer()->numberOfApps()) { + t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY); + } +} + +void Controller::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { if (withinTemporarySelection) { return; } @@ -153,16 +167,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo * background complete redrawing but the code is a bit * clumsy. */ if (t->selectedRow() == numberOfRows()-1) { - m_view.reloadBottomRow(this, container->numberOfApps()-1, k_numberOfColumns); - } - /* To prevent the selectable table view to select cells that are unvisible, - * we reselect the previous selected cell as soon as the selected cell is - * unvisible. This trick does not create an endless loop as we ensure not to - * stay on a unvisible cell and to initialize the first cell on a visible one - * (so the previous one is always visible). */ - int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1; - if (appIndex >= container->numberOfApps()) { - t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY); + m_view.reloadBottomRow(this, AppsContainer::sharedAppsContainer()->numberOfApps()-1, k_numberOfColumns); } } diff --git a/apps/home/controller.h b/apps/home/controller.h index 730541718..9fc7fb381 100644 --- a/apps/home/controller.h +++ b/apps/home/controller.h @@ -24,6 +24,7 @@ public: int reusableCellCount() const override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; + void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; private: int numberOfIcons() const; SelectableTableViewDataSource * selectionDataSource() const; diff --git a/apps/sequence/list/list_parameter_controller.cpp b/apps/sequence/list/list_parameter_controller.cpp index b40cab658..ebdd85905 100644 --- a/apps/sequence/list/list_parameter_controller.cpp +++ b/apps/sequence/list/list_parameter_controller.cpp @@ -87,7 +87,7 @@ bool ListParameterController::textFieldDidFinishEditing(TextField * textField, c return true; } -void ListParameterController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { +void ListParameterController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { if (withinTemporarySelection || (previousSelectedCellX == t->selectedColumn() && previousSelectedCellY == t->selectedRow())) { return; } diff --git a/apps/sequence/list/list_parameter_controller.h b/apps/sequence/list/list_parameter_controller.h index 6aaddb713..cc5ddae78 100644 --- a/apps/sequence/list/list_parameter_controller.h +++ b/apps/sequence/list/list_parameter_controller.h @@ -19,7 +19,7 @@ public: bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; - void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; + void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; // ListViewDataSource HighlightCell * reusableCell(int index, int type) override; diff --git a/escher/include/escher/selectable_table_view_delegate.h b/escher/include/escher/selectable_table_view_delegate.h index c7e20ee7b..b94d6b20f 100644 --- a/escher/include/escher/selectable_table_view_delegate.h +++ b/escher/include/escher/selectable_table_view_delegate.h @@ -13,6 +13,7 @@ public: * the previous selected cell. We might implement different course of action * when the selection change is 'real' or within temporary selection. */ virtual void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) {} + virtual void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) {} }; #endif diff --git a/escher/src/selectable_table_view.cpp b/escher/src/selectable_table_view.cpp index bb07591f0..9b4aab505 100644 --- a/escher/src/selectable_table_view.cpp +++ b/escher/src/selectable_table_view.cpp @@ -102,6 +102,10 @@ bool SelectableTableView::selectCellAtLocation(int i, int j, bool setFirstRespon scrollToCell(selectedColumn(), selectedRow()); } + if (m_delegate) { + m_delegate->tableViewDidChangeSelectionAndDidScroll(this, previousX, previousY, withinTemporarySelection); + } + HighlightCell * cell = selectedCell(); if (cell) { // Update first responder From d48f66fdadb8e510317ca6b471034213ca5e1ce1 Mon Sep 17 00:00:00 2001 From: Roberta Rabotti Date: Thu, 11 Jun 2020 16:44:01 +0200 Subject: [PATCH 421/453] [IT]chenges graphs --- apps/graph/base.it.i18n | 4 ++-- apps/sequence/base.it.i18n | 2 +- apps/toolbox.it.i18n | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/graph/base.it.i18n b/apps/graph/base.it.i18n index 99fabd636..656d79726 100644 --- a/apps/graph/base.it.i18n +++ b/apps/graph/base.it.i18n @@ -10,7 +10,7 @@ ParametricType = "Parametrica " IntervalT = "Intervallo t" IntervalTheta = "Intervallo θ" IntervalX = "Intervallo x" -FunctionDomain = "Area di tracciamento" +FunctionDomain = "Int. tracciamento" FunctionColor = "Colore della funzione" NoFunction = "Nessuna funzione" NoActivatedFunction = "Nessuna funzione attivata" @@ -19,7 +19,7 @@ Compute = "Calcolare" Zeros = "Zeri" Tangent = "Tangente" Intersection = "Intersezione" -Preimage = "Immagine" +Preimage = "Controimmagine" SelectLowerBound = "Scegliere il limite inferiore" SelectUpperBound = "Scegliere il limite superiore" NoMaximumFound = "Nessun massimo trovato" diff --git a/apps/sequence/base.it.i18n b/apps/sequence/base.it.i18n index 40e6bd81c..d9ddac4a1 100644 --- a/apps/sequence/base.it.i18n +++ b/apps/sequence/base.it.i18n @@ -4,7 +4,7 @@ SequenceTab = "Successioni" AddSequence = "Aggiungi successione" ChooseSequenceType = "Scegliere il tipo di successione" SequenceType = "Tipo di successione" -Explicit = "Esplicito" +Explicit = "Esplicita" SingleRecurrence = "Ricorrente d'ordine 1" DoubleRecurrence = "Ricorrente d'ordine 2" SequenceOptions = "Opzioni della successione" diff --git a/apps/toolbox.it.i18n b/apps/toolbox.it.i18n index 179be7b55..1a4462380 100644 --- a/apps/toolbox.it.i18n +++ b/apps/toolbox.it.i18n @@ -106,13 +106,13 @@ NthRoot = "Radice n-esima" BasedLogarithm = "Logaritmo di base a" Calculation = "Calcolo" ComplexNumber = "Numeri complessi" -Combinatorics = "Enumerazione" +Combinatorics = "Calcolo combinatorio" Arithmetic = "Aritmetica" Matrices = "Matrici" NewMatrix = "Nuova matrice" -Identity = "Identità matrice di dimensione n" +Identity = "Matrice identità di dimensione n" Lists = "Elenchi" -HyperbolicTrigonometry = "Trigonometria iperbolica" +HyperbolicTrigonometry = "Funzioni iperboliche" Fluctuation = "Intervallo di previsione" DerivateNumber = "Derivata" Integral = "Integrale" @@ -152,7 +152,7 @@ Prediction95 = "Intervallo di previsione al 95%" Prediction = "Intervallo di previsione semplice" Confidence = "Intervallo di confidenza" RandomAndApproximation = "Aleatorietà e approssimazione" -RandomFloat = "Numero decimale in [0,1[" +RandomFloat = "Decimale aleatorio tra [0,1[" RandomInteger = "Intero aleatorio tra [a,b]" PrimeFactorDecomposition = "Scomposizione in fattori primi" NormCDF = "P(X Date: Tue, 16 Jun 2020 13:49:35 +0200 Subject: [PATCH 422/453] [IT]changed Sample standard deviation --- apps/statistics/base.it.i18n | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/statistics/base.it.i18n b/apps/statistics/base.it.i18n index 941345722..99aacf03d 100644 --- a/apps/statistics/base.it.i18n +++ b/apps/statistics/base.it.i18n @@ -20,6 +20,6 @@ Median = "Mediana" ThirdQuartile = "Terzo quartile" TotalSize = "Dimensione totale" Range = "Ampiezza" -StandardDeviationSigma = "Deviazione standard" -SampleStandardDeviationS = "Esempio deviazione stnrd" +StandardDeviationSigma = "Deviazione standard σ" +SampleStandardDeviationS = "Dev. std campionaria s" InterquartileRange = "Scarto interquartile" From 363bf4a620714424eaf853beb1ec710da493024e Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Thu, 25 Jun 2020 11:37:58 +0200 Subject: [PATCH 423/453] [apps/calculation] Fixed ellipsis scrolling When scrolling to a calculation without additional outputs from a calculation with additional outputs, the ellipsis, though invisible, would remain selected. Change-Id: I7408ae004b9374e432ac58361616fa2ecf1550d8 --- apps/calculation/history_controller.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index e2cbf20f2..cc43c3c0b 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -161,6 +161,9 @@ void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableV setSelectedSubviewType(SubviewType::Input, false, previousSelectedCellX, previousSelectedCellY); } else { HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell()); + if (selectedSubviewType() == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { + setSelectedSubviewType(SubviewType::Output, false, previousSelectedCellX, previousSelectedCellY); + } SubviewType nextSelectedSubviewType = selectedSubviewType(); if (selectedCell && !selectedCell->displaysSingleLine()) { nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output; From 123d5f9076d34cae2cd6acd527d4cbc5fbfbe1a7 Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Thu, 25 Jun 2020 17:50:34 +0200 Subject: [PATCH 424/453] [apps/calculation] Fixed tall calculation scroll When displaying a calculation taller than the screen, the output could be displayed above the screen. - type 1/2/3/4/5/6/7/8/9 (the main fraction between the 1 and 2) - press UP to select the output ==> The output is still offscreen. Change-Id: Ic3ed7664ae693d22486f8b2f9f3a8f2324c3d7c9 --- apps/calculation/history_view_cell.h | 1 + apps/calculation/selectable_table_view.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index d50256fc8..c949afe79 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -58,6 +58,7 @@ public: void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; Shared::ScrollableTwoExpressionsView * outputView() { return &m_scrollableOutputView; } + ScrollableExpressionView * inputView() { return &m_inputView; } Calculation::AdditionalInformationType additionalInformationType() const { return m_calculationAdditionInformation; } private: constexpr static KDCoordinate k_resultWidth = 80; diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index 12599842b..126af887c 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -35,6 +35,8 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo unhighlightSelectedCell(); /* Main part of the scroll */ + HistoryViewCell * cell = (HistoryViewCell *)(selectedCell()); + assert(cell); KDCoordinate contentOffsetX = contentOffset().x(); KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling(); if (subviewType == HistoryViewCellDataSource::SubviewType::Input) { @@ -43,12 +45,15 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo } else { contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); } + } else if (cell->displaysSingleLine() && dataSource()->rowHeight(j) > maxContentHeightDisplayableWithoutScrolling()) { + /* If we cannot display the full calculation, we display the output as + * close as possible to the top of the screen without drawing empty space + * between the history and the input field. */ + contentOffsetY = dataSource()->cumulatedHeightFromIndex(j) + std::min(dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(), cell->inputView()->layout().baseline() - cell->outputView()->baseline()); } setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); /* For the same reason, we have to rehighlight the new history view cell and * reselect the first responder. */ - HistoryViewCell * cell = (HistoryViewCell *)(selectedCell()); - assert(cell); cell->setHighlighted(true); Container::activeApp()->setFirstResponder(cell); } From 0b74dd005dba82baa01bb51acc6fede441f2b713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 10:45:55 +0200 Subject: [PATCH 425/453] [apps/calculation] SelectableTableView: fix scrollToSubviewOfTypeOfCellAtLocation When scrolling, the table layout is likely to change and the selected cell might not been the same. --- apps/calculation/selectable_table_view.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index 126af887c..83f59323f 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -31,11 +31,11 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo return; } /* As we scroll, the selected calculation does not use the same history view - * cell, thus, we want to deselect the previous used history view cell. */ + * cell, thus, we want to deselect the previous used history view cell. (*) */ unhighlightSelectedCell(); /* Main part of the scroll */ - HistoryViewCell * cell = (HistoryViewCell *)(selectedCell()); + HistoryViewCell * cell = static_cast(selectedCell()); assert(cell); KDCoordinate contentOffsetX = contentOffset().x(); KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling(); @@ -52,8 +52,12 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo contentOffsetY = dataSource()->cumulatedHeightFromIndex(j) + std::min(dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(), cell->inputView()->layout().baseline() - cell->outputView()->baseline()); } setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); - /* For the same reason, we have to rehighlight the new history view cell and - * reselect the first responder. */ + /* For the same reason as (*), we have to rehighlight the new history view + * cell and reselect the first responder. + * We have to recall "selectedCell" because when the table might have been + * relayouted in "setContentOffset".*/ + cell = static_cast(selectedCell()); + assert(cell); cell->setHighlighted(true); Container::activeApp()->setFirstResponder(cell); } From 9508a89a1b8e9029d6dada9b63cca999e2328e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 10:06:08 +0200 Subject: [PATCH 426/453] [apps/calculation] Missing inclusion --- apps/calculation/selectable_table_view.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index 83f59323f..de77af0f7 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -1,4 +1,5 @@ #include "selectable_table_view.h" +#include namespace Calculation { From db331e054a84ac94cca33163c6aa94924f279dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 10:11:03 +0200 Subject: [PATCH 427/453] [apps/code] variable_box_controller: avoid unused variable warning when DEBUG=0 --- apps/code/variable_box_controller.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 75c000edd..9881b213d 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -594,7 +594,6 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont // Keep only MP_TOKEN_NAME tokens if (lex->tok_kind == MP_TOKEN_NAME) { - const char * name = lex->vstr.buf; int nameLength = lex->vstr.len; /* If the token autocompletes the text and it is not already in the @@ -612,7 +611,7 @@ void VariableBoxController::loadCurrentVariablesInScript(const char * scriptCont } assert(beginningLineIndex == line); const char * tokenInText = beginningLine + lex->tok_column - 1; // tok_column starts at 1, not 0 - assert(strncmp(tokenInText, name, nameLength) == 0); + assert(strncmp(tokenInText, lex->vstr.buf, nameLength) == 0); ScriptNode::Type nodeType = (defToken || *(tokenInText + nameLength) == '(')? ScriptNode::Type::WithParentheses : ScriptNode::Type::WithoutParentheses; if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, nodeType, origin, tokenInText, nameLength)) { From 1da2f23914a2f500e2bacacfc76d5b2d6b4441f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 15:59:00 +0200 Subject: [PATCH 428/453] [escher] SelectableTableView: fix delegate notification when deselecting table view This fixes the following bug: input 1.2/2, OK, up, down, the exact ouput is still displayed but should have toggled --- escher/src/selectable_table_view.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/escher/src/selectable_table_view.cpp b/escher/src/selectable_table_view.cpp index 9b4aab505..b77f46011 100644 --- a/escher/src/selectable_table_view.cpp +++ b/escher/src/selectable_table_view.cpp @@ -71,6 +71,7 @@ void SelectableTableView::deselectTable(bool withinTemporarySelection) { selectRow(-1); if (m_delegate) { m_delegate->tableViewDidChangeSelection(this, previousSelectedCellX, previousSelectedCellY, withinTemporarySelection); + m_delegate->tableViewDidChangeSelectionAndDidScroll(this, previousSelectedCellX, previousSelectedCellY, withinTemporarySelection); } } @@ -87,17 +88,20 @@ bool SelectableTableView::selectCellAtLocation(int i, int j, bool setFirstRespon selectColumn(i); selectRow(j); + /* The delegate is notified: + * - after changing the selected cell but before scrolling: for instance, + * ExpressionModelListController needs to update its memoized cell before + * being able to scroll; + * - after scrolling: for instance, the calculation history table might + * change its cell content when selected (outup toggling, ellipsis toggling) + * and thus need to access the right used cell - which is defined only + * after scrolling. + */ + if (m_delegate) { m_delegate->tableViewDidChangeSelection(this, previousX, previousY, withinTemporarySelection); } - /* We need to scroll: - * - After notifying the delegate. For instance, - * ExpressionModelListController needs to update its memoized cell - * height values before any scroll. - * - Before setting the first responder. If the first responder is a view, it - * might change during the scroll. */ - if (selectedRow() >= 0) { scrollToCell(selectedColumn(), selectedRow()); } From 457fa6a92546d7e1dc94341a80d6c0140d75319c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 16:06:36 +0200 Subject: [PATCH 429/453] [apps/calculation] When EditExpressionController becomes the first responder, scroll to the bottom of the table (and not the last cell). Indeed, the last cell might be to big to be displayed and scroll to it might scroll to its top. This fixes the following bug: input 1/2/3/4/5/6/7/8, OK, up, down. We did not scroll to the bottom of the table. --- apps/calculation/edit_expression_controller.cpp | 7 +++---- apps/calculation/edit_expression_controller.h | 7 ++++--- apps/calculation/selectable_table_view.cpp | 11 ++++++++--- apps/calculation/selectable_table_view.h | 1 + 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index b02f63211..cd7702e93 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -9,7 +9,7 @@ using namespace Poincare; namespace Calculation { -EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) : +EditExpressionController::ContentView::ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) : View(), m_mainView(subview), m_expressionField(parentResponder, inputEventHandlerDelegate, textFieldDelegate, layoutFieldDelegate) @@ -42,7 +42,7 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, ViewController(parentResponder), m_historyController(historyController), m_calculationStore(calculationStore), - m_contentView(this, (TableView *)m_historyController->view(), inputEventHandlerDelegate, this, this) + m_contentView(this, static_cast(m_historyController->view()), inputEventHandlerDelegate, this, this) { m_cacheBuffer[0] = 0; } @@ -53,8 +53,7 @@ void EditExpressionController::insertTextBody(const char * text) { } void EditExpressionController::didBecomeFirstResponder() { - int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; - m_contentView.mainView()->scrollToCell(0, lastRow); + m_contentView.mainView()->scrollToBottom(); m_contentView.expressionField()->setEditing(true, false); Container::activeApp()->setFirstResponder(m_contentView.expressionField()); } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index fe2d4c44c..eee1c4033 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -8,6 +8,7 @@ #include "../shared/layout_field_delegate.h" #include "history_controller.h" #include "calculation_store.h" +#include "selectable_table_view.h" namespace Calculation { @@ -34,15 +35,15 @@ public: private: class ContentView : public View { public: - ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate); + ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate); void reload(); - TableView * mainView() { return m_mainView; } + CalculationSelectableTableView * mainView() { return m_mainView; } ExpressionField * expressionField() { return &m_expressionField; } private: int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; - TableView * m_mainView; + CalculationSelectableTableView * m_mainView; ExpressionField m_expressionField; }; void reloadView(); diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index de77af0f7..9020cab1c 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -12,6 +12,12 @@ CalculationSelectableTableView::CalculationSelectableTableView(Responder * paren setDecoratorType(ScrollView::Decorator::Type::None); } +void CalculationSelectableTableView::scrollToBottom() { + KDCoordinate contentOffsetX = contentOffset().x(); + KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling(); + setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); +} + void CalculationSelectableTableView::scrollToCell(int i, int j) { if (m_contentView.bounds().height() < bounds().height()) { setTopMargin(bounds().height() - m_contentView.bounds().height()); @@ -21,9 +27,8 @@ void CalculationSelectableTableView::scrollToCell(int i, int j) { ::SelectableTableView::scrollToCell(i, j); ScrollView::layoutSubviews(); if (m_contentView.bounds().height() - contentOffset().y() < bounds().height()) { - KDCoordinate contentOffsetX = contentOffset().x(); - KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling(); - setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); + // Avoid empty space at the end of the table + scrollToBottom(); } } diff --git a/apps/calculation/selectable_table_view.h b/apps/calculation/selectable_table_view.h index 07823d9f1..d1740ab78 100644 --- a/apps/calculation/selectable_table_view.h +++ b/apps/calculation/selectable_table_view.h @@ -9,6 +9,7 @@ class CalculationSelectableTableView : public ::SelectableTableView { public: CalculationSelectableTableView(Responder * parentResponder, TableViewDataSource * dataSource, SelectableTableViewDataSource * selectionDataSource, SelectableTableViewDelegate * delegate = nullptr); + void scrollToBottom(); void scrollToCell(int i, int j) override; void scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j); }; From 736833da342d56de8628582ee75d8d3f503e1eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 16:09:05 +0200 Subject: [PATCH 430/453] [escher] Typo --- escher/src/scroll_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index ab8f8cabd..c8500c87c 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -98,7 +98,7 @@ void ScrollView::scrollToContentRect(KDRect rect, bool allowOverscroll) { KDPoint br = rect.bottomRight(); KDRect visibleRect = visibleContentRect(); /* We first check that we can display the whole rect. If we can't, we focus - * the croll to the closest part of the rect. */ + * the scroll to the closest part of the rect. */ if (visibleRect.height() < rect.height()) { // The visible rect is too small to display 'rect' if (rect.top() >= visibleRect.top()) { From aef804d149a7ba912f61544ec8d9d97dc3e6b0b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 17:29:55 +0200 Subject: [PATCH 431/453] [apps/calculation] HistoryController: avoid 2 calls to setSelectedSubviewType in tableViewDidChangeSelectionAndDidScroll --- apps/calculation/history_controller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index cc43c3c0b..b9818d01f 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -161,13 +161,13 @@ void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableV setSelectedSubviewType(SubviewType::Input, false, previousSelectedCellX, previousSelectedCellY); } else { HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell()); - if (selectedSubviewType() == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { - setSelectedSubviewType(SubviewType::Output, false, previousSelectedCellX, previousSelectedCellY); - } SubviewType nextSelectedSubviewType = selectedSubviewType(); if (selectedCell && !selectedCell->displaysSingleLine()) { nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output; } + if (nextSelectedSubviewType == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { + nextSelectedSubviewType = SubviewType::Output; + } setSelectedSubviewType(nextSelectedSubviewType, false, previousSelectedCellX, previousSelectedCellY); } // The selectedCell may change during setSelectedSubviewType From 94d3ac98284950be7e88bfa5cdf5f99f82c0f183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 17:31:10 +0200 Subject: [PATCH 432/453] [apps/calculation] HistoryController: fix order of actions in Backspace handle event This fixes the following bug: input 1/2/3/4/5/6/7/8, OK, OK, input 1, OK, up, backspace. The selection disappeared. --- apps/calculation/history_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index b9818d01f..33185d172 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -128,8 +128,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); - tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); m_selectableTableView.scrollToCell(0, selectedRow()); + tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); return true; } if (event == Ion::Events::Clear) { From 1281a4a508807f9befcba228a4b528716e8881e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 17:34:25 +0200 Subject: [PATCH 433/453] [apps/calculation] HistoryController: avoid duplicate code when handling backspace event. Keep the same selected subview. --- apps/calculation/history_controller.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 33185d172..41037c3f6 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -128,8 +128,11 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); - m_selectableTableView.scrollToCell(0, selectedRow()); - tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); + HistoryViewCell * selectedCell = static_cast(m_selectableTableView.selectedCell()); + if (subviewType == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { + subviewType = SubviewType::Output; + } + setSelectedSubviewType(subviewType, true, 0, selectedRow()); return true; } if (event == Ion::Events::Clear) { From 96c7d84633ecc6ba46d2c71136c36ea3769606c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 17:47:52 +0200 Subject: [PATCH 434/453] [apps/calculation] Factorize code to avoid selecting ellipsis on cell where ellipsis is not displayed --- apps/calculation/history_controller.cpp | 17 ++++++++++------- apps/calculation/history_controller.h | 1 + apps/calculation/history_view_cell.h | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 41037c3f6..667c8b14c 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -128,10 +128,6 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); - HistoryViewCell * selectedCell = static_cast(m_selectableTableView.selectedCell()); - if (subviewType == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { - subviewType = SubviewType::Output; - } setSelectedSubviewType(subviewType, true, 0, selectedRow()); return true; } @@ -168,9 +164,6 @@ void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableV if (selectedCell && !selectedCell->displaysSingleLine()) { nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output; } - if (nextSelectedSubviewType == SubviewType::Ellipsis && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { - nextSelectedSubviewType = SubviewType::Output; - } setSelectedSubviewType(nextSelectedSubviewType, false, previousSelectedCellX, previousSelectedCellY); } // The selectedCell may change during setSelectedSubviewType @@ -227,6 +220,16 @@ bool HistoryController::calculationAtIndexToggles(int index) { return index >= 0 && index < m_calculationStore->numberOfCalculations() && calculationAtIndex(index)->displayOutput(context) == Calculation::DisplayOutput::ExactAndApproximateToggle; } + +void HistoryController::setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX, int previousSelectedY) { + // Avoid selecting non-displayed ellipsis + HistoryViewCell * selectedCell = static_cast(m_selectableTableView.selectedCell()); + if (subviewType == SubviewType::Ellipsis && selectedCell && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) { + subviewType = SubviewType::Output; + } + HistoryViewCellDataSource::setSelectedSubviewType(subviewType, sameCell, previousSelectedX, previousSelectedY); +} + void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cell, HistoryViewCell ** previousCell, int previousSelectedCellX, int previousSelectedCellY, SubviewType type, SubviewType previousType) { /* If the selection change triggers the toggling of the outputs, we update * the whole table as the height of the selected cell row might have changed. */ diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h index 64d75755c..021a0e876 100644 --- a/apps/calculation/history_controller.h +++ b/apps/calculation/history_controller.h @@ -31,6 +31,7 @@ public: void willDisplayCellForIndex(HighlightCell * cell, int index) override; KDCoordinate rowHeight(int j) override; int typeAtLocation(int i, int j) override; + void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override; void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; private: int storeIndex(int i) { return numberOfRows() - i - 1; } diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index c949afe79..7bddbe434 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -18,7 +18,7 @@ public: Ellipsis = 3 }; HistoryViewCellDataSource() : m_selectedSubviewType(SubviewType::Output) {} - void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1); + virtual void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1); SubviewType selectedSubviewType() const { return m_selectedSubviewType; } private: /* This method should belong to a delegate instead of a data source but as From cb62747e484ceda5ad94855d4a28c6ff10a919c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 26 Jun 2020 09:53:25 +0200 Subject: [PATCH 435/453] build: Version 14.2.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index d72699321..20eaeeff4 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 14.1.0 +EPSILON_VERSION ?= 14.2.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0 From e78c5c02d319c70011a9e4854b7f20951b043071 Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Mon, 29 Jun 2020 18:55:27 +0200 Subject: [PATCH 436/453] [apps/calculation] Fixed history scroll Fixed a bug involving mishandled negative offsets in CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation and cleaned up the function. Change-Id: I4394ca9dc9748e8b761e7f722e41014d71d3373f --- apps/calculation/selectable_table_view.cpp | 55 +++++++++++++++++----- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index 9020cab1c..8a2884ce1 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -44,19 +44,50 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo HistoryViewCell * cell = static_cast(selectedCell()); assert(cell); KDCoordinate contentOffsetX = contentOffset().x(); - KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling(); - if (subviewType == HistoryViewCellDataSource::SubviewType::Input) { - if (j == 0) { - contentOffsetY = 0; - } else { - contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); - } - } else if (cell->displaysSingleLine() && dataSource()->rowHeight(j) > maxContentHeightDisplayableWithoutScrolling()) { - /* If we cannot display the full calculation, we display the output as - * close as possible to the top of the screen without drawing empty space - * between the history and the input field. */ - contentOffsetY = dataSource()->cumulatedHeightFromIndex(j) + std::min(dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(), cell->inputView()->layout().baseline() - cell->outputView()->baseline()); + + KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); + if (cell->displaysSingleLine() && dataSource()->rowHeight(j) > maxContentHeightDisplayableWithoutScrolling()) { + /* If we cannot display the full calculation, we display the selected + * layout as close as possible to the top of the screen without drawing + * empty space between the history and the input field. + * + * Below are some values we can assign to contentOffsetY, and the kinds of + * display they entail : + * (the selected cell is at index j) + * + * 1 - cumulatedHeightFromIndex(j) + * Aligns the top of the cell with the top of the zone in which the + * history can be drawn. + * + * 2 - (cumulatedHeightFromIndex(j+1) + * - maxContentHeightDisplayableWithoutScrolling()) + * Aligns the bottom of the cell with the top of the input field. + * + * 3 - cumulatedHeightFromIndex(j) + baseline1 - baseline2 + * Aligns the top of the selected layout with the top of the screen (only + * used when the selected layout is the smallest). + * + * The following drawing shows where the calculation would be aligned with + * each value of contentOffsetY, for the calculation (1/3)/(4/2) = 1/6. + * + * (1) (2) (3) + * +--------------+ +--------------+ +--------------+ + * | 1 | | --- - | | 3 1 | + * | - | | 4 6 | | --- - | + * | 3 1 | | - | | 4 6 | + * | --- - | | 2 | | - | + * +--------------+ +--------------+ +--------------+ + * | (1/3)/(4/2) | | (1/3)/(4/2) | | (1/3)/(4/2) | + * +--------------+ +--------------+ +--------------+ + * + * */ + contentOffsetY += std::min( + dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(), + std::max(0, (cell->inputView()->layout().baseline() - cell->outputView()->baseline()) * (subviewType == HistoryViewCellDataSource::SubviewType::Input ? -1 : 1))); + } else if (subviewType != HistoryViewCellDataSource::SubviewType::Input) { + contentOffsetY += dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(); } + setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); /* For the same reason as (*), we have to rehighlight the new history view * cell and reselect the first responder. From a4c0903f536816908fc11ca408e10a40cbd10a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 30 Jun 2020 17:24:50 +0200 Subject: [PATCH 437/453] [i18n/pt] Fix typo --- apps/toolbox.pt.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 6660625a9..4215d6969 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -29,7 +29,7 @@ UnitMassGramMilli = "Miligrama" UnitMassGramMicro = "Micrograma" UnitMassGramNano = "Nanograma" UnitMassTonne = "Tonelada" -UnitCurrentMenu = "Intensidade da currente elétrica" +UnitCurrentMenu = "Intensidade da corrente elétrica" UnitCurrentAmpere = "Ampere" UnitCurrentAmpereMilli = "Miliampere" UnitCurrentAmpereMicro = "Microampere" From 3cf80b86d62a0b3773e8c43a6ebb72aa09dde6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Jul 2020 10:23:27 +0200 Subject: [PATCH 438/453] [apps/i18n] Fix italian translation typo --- apps/variables.it.i18n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/variables.it.i18n b/apps/variables.it.i18n index 68a72ea3c..8871d3e51 100644 --- a/apps/variables.it.i18n +++ b/apps/variables.it.i18n @@ -7,4 +7,4 @@ EmptyExpressionBox1 = "Per definire una variabile, digitare :" EmptyFunctionBox1 = "Per definire una funzione, digitare :" EmptyExpressionBox2 = "Il nome della variabile può" EmptyFunctionBox2 = "Il nome della funzione può" -EnableCharacters = "contenere : A..Z, a..z, 0..9 et _" +EnableCharacters = "contenere : A..Z, a..z, 0..9 e _" From 558d0f6343eab497bd32f701e66a1b292c6da9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 16 Jun 2020 17:45:22 +0200 Subject: [PATCH 439/453] [.github/workflow] ci-workflow: fix emscripten version to 1.39.16 (later versions removed EMTERPRETER) --- .github/workflows/ci-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index e5c02961c..9c74c0ca0 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -70,7 +70,7 @@ jobs: steps: - uses: numworks/setup-emscripten@v2 with: - sdk: latest-fastcomp + sdk: 1.39.16-fastcomp - uses: actions/checkout@v2 - run: make -j2 PLATFORM=simulator TARGET=web - run: make -j2 PLATFORM=simulator TARGET=web epsilon.official.zip From 026fe120fe5eadf8e5a45c73b0f63e9d867136d8 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 17 Jun 2020 14:27:38 -0400 Subject: [PATCH 440/453] [simulator] Make the calculator's screen pixel-perfect --- ion/src/simulator/shared/layout.cpp | 2 +- ion/src/simulator/shared/main_sdl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/layout.cpp b/ion/src/simulator/shared/layout.cpp index 0b2241778..088e5444c 100644 --- a/ion/src/simulator/shared/layout.cpp +++ b/ion/src/simulator/shared/layout.cpp @@ -11,7 +11,7 @@ static constexpr float X(int x) { return static_cast(x)/static_cast(y)/static_cast(backgroundHeight); } static constexpr SDL_FRect areaOfInterest = {X(110), Y(30), X(940), Y(2150)}; -static constexpr SDL_FRect screenRect = {X(192), Y(191), X(779), Y(582)}; +static constexpr SDL_FRect screenRect = {X(192), Y(191), X(776), Y(582)}; static SDL_Rect sFrame; diff --git a/ion/src/simulator/shared/main_sdl.cpp b/ion/src/simulator/shared/main_sdl.cpp index bc7f59f83..0a79caf9c 100644 --- a/ion/src/simulator/shared/main_sdl.cpp +++ b/ion/src/simulator/shared/main_sdl.cpp @@ -73,7 +73,7 @@ void init() { Ion::Display::Height, 0 // Default flags: no high-dpi, not resizeable. #else - 290, 555, // Otherwise use a default size that matches the whole calculator + 458, 888, // Otherwise use a default size that makes the screen pixel-perfect SDL_WINDOW_ALLOW_HIGHDPI #if EPSILON_SDL_FULLSCREEN | SDL_WINDOW_FULLSCREEN From 7a9954152a9fa27ee4bbfe379aef9a2821375c71 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Jun 2020 22:32:31 -0400 Subject: [PATCH 441/453] [ion/simulator] Ion::Simulator::Main::relayout() should not draw That function is supposed to recompute the layout, not perform any drawing. Namely, presenting the render without a potential previous call to SDL_RenderClear could lead to some visual glitches. --- ion/src/simulator/shared/main_sdl.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ion/src/simulator/shared/main_sdl.cpp b/ion/src/simulator/shared/main_sdl.cpp index 0a79caf9c..241b2495c 100644 --- a/ion/src/simulator/shared/main_sdl.cpp +++ b/ion/src/simulator/shared/main_sdl.cpp @@ -115,11 +115,6 @@ void relayout() { sScreenRect.h = windowHeight; #else Layout::recompute(windowWidth, windowHeight); - SDL_Rect backgroundRect; - Layout::getBackgroundRect(&backgroundRect); - - SDL_RenderCopy(sRenderer, sBackgroundTexture, nullptr, &backgroundRect); - SDL_RenderPresent(sRenderer); #endif setNeedsRefresh(); From 5dfccd4a04ed8505bcc195b95c7c8fa40376426c Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Jun 2020 22:34:31 -0400 Subject: [PATCH 442/453] [ion/simulator] Relayout on any windows event We might be relayouting a bit too often, but better safe than sorry! Jokes aside, most SDL_WINDOWEVENT should trigger a relayout, and in general those events aren't triggered on a regular basis anyway. --- ion/src/simulator/shared/events_keyboard.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 61fe0f972..806372e19 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -175,9 +175,8 @@ Event getPlatformEvent() { while (SDL_PollEvent(&event)) { // The while is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { - if (event.window.event == SDL_WINDOWEVENT_RESIZED) { - Ion::Simulator::Main::relayout(); - } + Ion::Simulator::Main::relayout(); + break; } if (event.type == SDL_QUIT) { result = Termination; From 6b60fc561f8ee4d8bafd8c6791b76a3b848d3829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Jul 2020 16:23:09 +0200 Subject: [PATCH 443/453] [apps/regression] Fix wrong proportional model fit --- apps/regression/model/proportional_model.cpp | 4 ---- apps/regression/model/proportional_model.h | 1 - apps/regression/test/model.cpp | 8 ++++++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/regression/model/proportional_model.cpp b/apps/regression/model/proportional_model.cpp index 22f62e5a4..3ae682488 100644 --- a/apps/regression/model/proportional_model.cpp +++ b/apps/regression/model/proportional_model.cpp @@ -27,10 +27,6 @@ double ProportionalModel::levelSet(double * modelCoefficients, double xMin, doub return y/a; } -void ProportionalModel::fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) { - modelCoefficients[0] = store->slope(series); -} - double ProportionalModel::partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const { assert(derivateCoefficientIndex == 0); // Derivate: x diff --git a/apps/regression/model/proportional_model.h b/apps/regression/model/proportional_model.h index b2eca094f..8c2ff44d3 100644 --- a/apps/regression/model/proportional_model.h +++ b/apps/regression/model/proportional_model.h @@ -12,7 +12,6 @@ public: I18n::Message formulaMessage() const override { return I18n::Message::ProportionalRegressionFormula; } double evaluate(double * modelCoefficients, double x) const override; double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override; - void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override; double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override; int numberOfCoefficients() const override { return 1; } int bannerLinesCount() const override { return 2; } diff --git a/apps/regression/test/model.cpp b/apps/regression/test/model.cpp index ff07521e7..0abbad61a 100644 --- a/apps/regression/test/model.cpp +++ b/apps/regression/test/model.cpp @@ -50,6 +50,14 @@ QUIZ_CASE(proportional_regression) { assert_regression_is(x, y, 5, Model::Type::Proportional, coefficients); } +QUIZ_CASE(proportional_regression2) { + constexpr int numberOfPoints = 4; + double x[numberOfPoints] = {5.0, 2.0, 3.0, 4.0}; + double y[numberOfPoints] = {10.0, 6.0, 7.0, 8.0}; + double coefficients[] = {2.12963963}; + assert_regression_is(x, y, numberOfPoints, Model::Type::Proportional, coefficients); +} + QUIZ_CASE(quadratic_regression) { double x[] = {-34.0, -12.0, 5.0, 86.0, -2.0}; double y[] = {-8241.389, -1194.734, -59.163, - 46245.39, -71.774}; From 759fa6a60aa9b95177db6fce736c3730926bd9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 2 Jul 2020 17:08:52 +0200 Subject: [PATCH 444/453] [escher] Fix constexpr due to linux warning --- escher/src/modal_view_empty_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/modal_view_empty_controller.cpp b/escher/src/modal_view_empty_controller.cpp index 3a3d071d6..23f370a6c 100644 --- a/escher/src/modal_view_empty_controller.cpp +++ b/escher/src/modal_view_empty_controller.cpp @@ -2,7 +2,7 @@ #include #include -const KDColor ModalViewEmptyController::ModalViewEmptyView::k_backgroundColor; +constexpr KDColor ModalViewEmptyController::ModalViewEmptyView::k_backgroundColor; // ModalViewEmptyController::ModalViewEmptyView void ModalViewEmptyController::ModalViewEmptyView::initMessageViews() { From 38f3c9b8135da37d4c9a48524c475085c12ad233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 2 Jul 2020 14:43:59 +0200 Subject: [PATCH 445/453] build: Version 14.3.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index 20eaeeff4..d6cc8aebc 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 14.2.0 +EPSILON_VERSION ?= 14.3.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0 From 1ef3f34a313f9f2549faf5fcb65cee761e8d6f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 3 Jul 2020 14:21:56 +0200 Subject: [PATCH 446/453] [ion/apple] App needs to be inside Payload folder to build .ipa Otherwise the .ipa cannot be uploaded to the app store. --- ion/src/simulator/shared/apple/targets.mak | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/apple/targets.mak b/ion/src/simulator/shared/apple/targets.mak index 0245e6fb6..027602f2e 100644 --- a/ion/src/simulator/shared/apple/targets.mak +++ b/ion/src/simulator/shared/apple/targets.mak @@ -12,5 +12,8 @@ ifdef IOS_PROVISIONNING_PROFILE $(call rule_label,SIGN) $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "Apple Distribution: NumWorks" $(BUILD_DIR)/$*.app endif + @ echo "$(shell printf "%-8s" "COPY")$(notdir $*).app into Payload" + $(Q) cd $(dir $@) ; mkdir Payload; cp -r $(notdir $*).app Payload + $(call rule_label,ZIP) - $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) $*.app + $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) Payload From 35f20c4312ee3188aed1256a9d802ee1aa595061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 16:35:35 +0200 Subject: [PATCH 447/453] [apps/calculation] Comment possible failed height computation --- apps/calculation/history_controller.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 667c8b14c..e09cac524 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -208,6 +208,10 @@ KDCoordinate HistoryController::rowHeight(int j) { result = HistoryViewCell::Height(calculation.pointer(), expanded); calculation->setMemoizedHeight(expanded, result); } + /* We might want to put an assertion here to check the memoization: + * assert(result == HistoryViewCell::Height(calculation.pointer(), expanded)); + * However, Height might fail due to pool memory exhaustion, in which case the + * assertion fails even if "result" had the right value. */ return result; } From 924e235ba8ce0bbcc22dc395c4edb0178c909db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:16:22 +0200 Subject: [PATCH 448/453] [apps/calculation] Factorize some code --- apps/calculation/calculation.cpp | 12 ++++++++---- apps/calculation/calculation.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 7a7a9e425..236f59ed0 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -41,8 +41,7 @@ Calculation * Calculation::next() const { void Calculation::tidy() { /* Reset height memoization (the complex format could have changed when * re-entering Calculation app which would impact the heights). */ - m_height = -1; - m_expandedHeight = -1; + resetHeightMemoization(); } const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const { @@ -193,9 +192,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { void Calculation::forceDisplayOutput(DisplayOutput d) { m_displayOutput = d; // Reset heights memoization as it might have changed when we modify the display output - m_height = -1; - m_expandedHeight = -1; + resetHeightMemoization(); } + bool Calculation::shouldOnlyDisplayExactOutput() { /* If the input is a "store in a function", do not display the approximate * result. This prevents x->f(x) from displaying x = undef. */ @@ -290,4 +289,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co return AdditionalInformationType::None; } +void Calculation::resetHeightMemoization() { + m_height = -1; + m_expandedHeight = -1; +} + } diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index dc1646657..a09253abc 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -99,6 +99,7 @@ private: static constexpr int k_numberOfExpressions = 4; static constexpr KDCoordinate k_heightComputationFailureHeight = 50; static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000"; + void resetHeightMemoization(); /* Buffers holding text expressions have to be longer than the text written * by user (of maximum length TextField::maxBufferSize()) because when we * print an expression we add omitted signs (multiplications, parenthesis...) */ From 1128134c370fda350640d36b8a1640b5cde3abdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:26:06 +0200 Subject: [PATCH 449/453] [apps/calculation] Raise exception if row height miscomputed Scenario: Put the complex mode to exponential, then go back to Calculation and: Toolbox, Down, Down, Down, Down, OK, OK, Two, Plus, Imaginary, Toolbox, Down, Down, Down, Down, OK, Down, OK, Two, Plus, Imaginary, OK, Toolbox, Down, Down, Down, Down, Down, OK, Down, OK, Up, OK, Right, Zero, OK, OK, Toolbox, Down, Down, OK, Toolbox, Back, Up, Zero, Up, OK, Zero, Up, Up, Up --- apps/calculation/history_controller.cpp | 5 +++++ apps/calculation/history_view_cell.cpp | 20 ++++++++++++++++++-- apps/calculation/history_view_cell.h | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index e09cac524..159c36e8a 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -1,5 +1,6 @@ #include "history_controller.h" #include "app.h" +#include #include using namespace Shared; @@ -206,6 +207,10 @@ KDCoordinate HistoryController::rowHeight(int j) { KDCoordinate result = calculation->memoizedHeight(expanded); if (result < 0) { result = HistoryViewCell::Height(calculation.pointer(), expanded); + if (result < 0) { + // Raise, because Height modified the calculation and failed. + Poincare::ExceptionCheckpoint::Raise(); + } calculation->setMemoizedHeight(expanded, result); } /* We might want to put an assertion here to check the memoization: diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 3dff139a8..2f982053d 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -36,7 +36,16 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType, KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) { HistoryViewCell cell(nullptr); - cell.setCalculation(calculation, expanded); + bool didForceOutput = false; + cell.setCalculation(calculation, expanded, &didForceOutput); + if (didForceOutput) { + /* We could not compute the height of the calculation as it is (the display + * output was forced to another value during the height computation). + * Warning: the display output of calculation was actually changed, so it + * will cause problems if we already did some computations with another + * display value. */ + return -1; + } KDRect ellipsisFrame = KDRectZero; KDRect inputFrame = KDRectZero; KDRect outputFrame = KDRectZero; @@ -237,7 +246,8 @@ void HistoryViewCell::resetMemoization() { m_calculationCRC32 = 0; } -void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { +void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) { + assert(!didForceOutput || *didForceOutput == false); uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation)); if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) { return; @@ -265,6 +275,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { if (couldNotCreateExactLayout) { if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) { calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); + if (didForceOutput) { + *didForceOutput = true; + } } else { /* We should only display the exact result, but we cannot create it * -> raise an exception. */ @@ -287,6 +300,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { /* Set the display output to ApproximateOnly, make room in the pool by * erasing the exact layout, and retry to create the approximate layout */ calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); + if (didForceOutput) { + *didForceOutput = true; + } exactOutputLayout = Poincare::Layout(); couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index 7bddbe434..abe2d6ac8 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -51,7 +51,7 @@ public: Poincare::Layout layout() const override; KDColor backgroundColor() const override { return m_even ? KDColorWhite : Palette::WallScreen; } void resetMemoization(); - void setCalculation(Calculation * calculation, bool expanded); + void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr); int numberOfSubviews() const override { return 2 + displayedEllipsis(); } View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; From 982b467268f7853df612e85c466cc676fd7c3e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:40:46 +0200 Subject: [PATCH 450/453] [apps/calculation] Fix scrolling If the last cell is too big to fit entirely, we would scroll to the top of the calculation, instead of the bottom --- apps/calculation/history_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 159c36e8a..c8c153b6a 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -39,7 +39,7 @@ void HistoryController::reload() { * the table view twice. */ if (numberOfRows() > 0) { - m_selectableTableView.scrollToCell(0, numberOfRows()-1); + m_selectableTableView.scrollToBottom(); // Force to reload last added cell (hide the burger and exact output if necessary) tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, numberOfRows()-1); } From cc4ff3d40dd2c128f0b5b2379ee56303c08bc19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:52:34 +0200 Subject: [PATCH 451/453] [apps/calculation] Apply fix about Height computation There was a problem with the way of computing Height, see Calculation::HistoryViewCell. We did not encounter a problemeatic scenario here, but there is no reason it would have been safe before. --- .../illustrated_list_controller.cpp | 5 ++++ .../scrollable_three_expressions_cell.cpp | 24 +++++++++++++++---- .../scrollable_three_expressions_cell.h | 4 ++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.cpp b/apps/calculation/additional_outputs/illustrated_list_controller.cpp index b4d895621..1b78bef20 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.cpp +++ b/apps/calculation/additional_outputs/illustrated_list_controller.cpp @@ -1,4 +1,5 @@ #include "illustrated_list_controller.h" +#include #include #include "../app.h" @@ -82,6 +83,10 @@ KDCoordinate IllustratedListController::rowHeight(int j) { KDCoordinate result = calculation->memoizedHeight(expanded); if (result < 0) { result = ScrollableThreeExpressionsCell::Height(calculation.pointer()); + if (result < 0) { + // Raise, because Height modified the calculation and failed. + Poincare::ExceptionCheckpoint::Raise(); + } calculation->setMemoizedHeight(expanded, result); } return result + Metric::CellSeparatorThickness; diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp index 29fe03a9a..63cf7b17e 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp @@ -8,7 +8,8 @@ void ScrollableThreeExpressionsView::resetMemoization() { setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); } -void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { +void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool * didForceOutput) { + assert(!didForceOutput || *didForceOutput == false); Poincare::Context * context = App::app()->localContext(); // Clean the layouts to make room in the pool @@ -27,6 +28,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { Poincare::ExceptionCheckpoint::Raise(); } else { calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); + if (didForceOutput) { + *didForceOutput = true; + } } } } @@ -46,6 +50,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { /* Set the display output to ApproximateOnly, make room in the pool by * erasing the exact layout, and retry to create the approximate layout */ calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); + if (didForceOutput) { + *didForceOutput = true; + } exactOutputLayout = Poincare::Layout(); couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); @@ -67,7 +74,16 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { KDCoordinate ScrollableThreeExpressionsCell::Height(Calculation * calculation) { ScrollableThreeExpressionsCell cell; - cell.setCalculation(calculation); + bool didForceOutput = false; + cell.setCalculation(calculation, &didForceOutput); + if (didForceOutput) { + /* We could not compute the height of the calculation as it is (the display + * output was forced to another value during the height computation). + * Warning: the display output of calculation was actually changed, so it + * will cause problems if we already did some computations with another + * display value. */ + return -1; + } KDRect leftFrame = KDRectZero; KDRect centerFrame = KDRectZero; KDRect approximateSignFrame = KDRectZero; @@ -87,8 +103,8 @@ void ScrollableThreeExpressionsCell::reinitSelection() { m_view.reloadScroll(); } -void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation) { - m_view.setCalculation(calculation); +void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool * didForceOutput) { + m_view.setCalculation(calculation, didForceOutput); layoutSubviews(); } diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h index e8daa7f26..6dd8f52f3 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h @@ -16,7 +16,7 @@ public: setBackgroundColor(KDColorWhite); } void resetMemoization(); - void setCalculation(Calculation * calculation); + void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr); void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) { return m_contentCell.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame); } @@ -57,7 +57,7 @@ public: void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); } void resetMemoization() { m_view.resetMemoization(); } - void setCalculation(Calculation * calculation); + void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr); void setDisplayCenter(bool display); ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); } void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); } From d8f17da04ebd3e0d9f31ecf39e78b10665336ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:54:05 +0200 Subject: [PATCH 452/453] [apps/calculation] Add TODO comments about factorization --- .../additional_outputs/illustrated_list_controller.h | 2 ++ .../additional_outputs/scrollable_three_expressions_cell.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.h b/apps/calculation/additional_outputs/illustrated_list_controller.h index c4bca2415..970341821 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.h +++ b/apps/calculation/additional_outputs/illustrated_list_controller.h @@ -10,6 +10,8 @@ namespace Calculation { class IllustratedListController : public ListController, public SelectableTableViewDelegate { +/* TODO There is factorizable code between this and + * Calculation::HistoryController (at least rowHeight). */ public: IllustratedListController(EditExpressionController * editExpressionController); diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h index 6dd8f52f3..e89b68da1 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h @@ -8,6 +8,9 @@ namespace Calculation { +/* TODO There is factorizable code between this and Calculation::HistoryViewCell + * (at least setCalculation). */ + class ScrollableThreeExpressionsView : public Shared::AbstractScrollableMultipleExpressionsView { public: static constexpr KDCoordinate k_margin = Metric::CommonSmallMargin; From ef8a4f9e7b4c1ef562bead4393657ffee77083a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 6 Jul 2020 17:57:38 +0200 Subject: [PATCH 453/453] build: Version 14.4.0 --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index d6cc8aebc..1e6f096ed 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 14.3.0 +EPSILON_VERSION ?= 14.4.0 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_GETOPT ?= 0