diff --git a/escher/include/escher/clipboard.h b/escher/include/escher/clipboard.h index 808cbd9d3..63431faec 100644 --- a/escher/include/escher/clipboard.h +++ b/escher/include/escher/clipboard.h @@ -9,7 +9,7 @@ class Clipboard { public: static Clipboard * sharedClipboard(); void store(const char * storedText, int length = -1); - const char * storedText() { return m_textBuffer; } + const char * storedText(); void reset(); void enterPython() { replaceCharForPython(true); } void exitPython() { replaceCharForPython(false); } diff --git a/escher/src/clipboard.cpp b/escher/src/clipboard.cpp index 5fa300799..863ea183a 100644 --- a/escher/src/clipboard.cpp +++ b/escher/src/clipboard.cpp @@ -12,6 +12,31 @@ void Clipboard::store(const char * storedText, int length) { strlcpy(m_textBuffer, storedText, length == -1 ? TextField::maxBufferSize() : std::min(TextField::maxBufferSize(), length + 1)); } +const char * Clipboard::storedText() { + /* In order to allow copy/paste of empty formulas, we need to add empty + * layouts between empty system parenthesis. This way, when the expression + * is parsed, it is recognized as a proper formula and appears with the correct + * visual layout. + * Without this process, copying an empty integral then pasting it gives : + * int((), x, (), ()) instead of drawing an empty integral. + * + * Furthermore, in case the user switches from linear to natural writing mode + * we need to add an empty layout between parenthesis to allow proper layout + * construction. */ + constexpr int numberOfPairs = 6; + constexpr UTF8Helper::TextPair textPairs[numberOfPairs] = { + UTF8Helper::TextPair("()", "(\x11)"), + UTF8Helper::TextPair("[]", "[\x11]"), + UTF8Helper::TextPair("[,", "[\x11,"), + UTF8Helper::TextPair(",,", ",\x11,"), + UTF8Helper::TextPair(",]", ",\x11]"), + UTF8Helper::TextPair("\x12\x13", "\x12\x11\x13"), + }; + + UTF8Helper::tryAndReplacePatternsInStringByPatterns(m_textBuffer, TextField::maxBufferSize(), (UTF8Helper::TextPair *) &textPairs, numberOfPairs, true); + return m_textBuffer; +} + void Clipboard::reset() { strlcpy(m_textBuffer, "", 1); } diff --git a/escher/test/clipboard.cpp b/escher/test/clipboard.cpp index 7c895c9b4..510c683ef 100644 --- a/escher/test/clipboard.cpp +++ b/escher/test/clipboard.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include void assert_clipboard_enters_and_exits_python(const char * string, const char * stringResult) { @@ -19,3 +21,29 @@ QUIZ_CASE(escher_clipboard_enters_and_exits_python) { assert_clipboard_enters_and_exits_python("1×𝐢^2", "1*1j**2"); assert_clipboard_enters_and_exits_python("12^(1/4)×(π/6)×(12×π)^(1/4)", "12**(1/4)*(pi/6)*(12*pi)**(1/4)"); } + +using namespace Poincare; + +void assert_stored_text_is_parseable(Poincare::Layout layout) { + constexpr int bufferSize = 500; + char buffer[bufferSize]; + layout.serializeForParsing(buffer, bufferSize); + Clipboard * clipboard = Clipboard::sharedClipboard(); + clipboard->store(buffer); + Expression e = Expression::Parse(clipboard->storedText(), nullptr, false); + Layout result = e.createLayout(Preferences::sharedPreferences()->displayMode(), Poincare::PrintFloat::k_numberOfStoredSignificantDigits); + quiz_assert(layout.isIdenticalTo(result)); +} + +QUIZ_CASE(escher_clipboard_stored_text_is_parseable) { + Layout l = IntegralLayout::Builder(EmptyLayout::Builder(), CodePointLayout::Builder('x'), EmptyLayout::Builder(), EmptyLayout::Builder()); + assert_stored_text_is_parseable(l); + l = NthRootLayout::Builder(EmptyLayout::Builder()); + assert_stored_text_is_parseable(l); + l = MatrixLayout::Builder(CodePointLayout::Builder('1'), EmptyLayout::Builder(), EmptyLayout::Builder(), CodePointLayout::Builder('2')); + assert_stored_text_is_parseable(l); + l = SumLayout::Builder(EmptyLayout::Builder(), CodePointLayout::Builder('n'), EmptyLayout::Builder(), EmptyLayout::Builder()); + assert_stored_text_is_parseable(l); + l = SumLayout::Builder(EmptyLayout::Builder(), CodePointLayout::Builder('n'), EmptyLayout::Builder(), EmptyLayout::Builder()); + assert_stored_text_is_parseable(l);; +} \ No newline at end of file