From ab8acad00e0a1179ba706f8a3189b031926d2afa Mon Sep 17 00:00:00 2001 From: Joel Blanco Berg Date: Mon, 2 Dec 2024 12:56:45 +0100 Subject: [PATCH] Lua code editors indentation (#7890) * It's not possible to indent lines even if they are empty * Tab does not indent the entire line anymore, instead it adds a tab at the caret position * String declarations are autoclosed now * Auto-indentation for function, while, if statements. * When pressing Enter, the new line will keep the indentation from the previous line --- src/common/LuaSupport.cpp | 4 - src/common/dsp/WavetableScriptEvaluator.cpp | 1 - src/surge-xt/gui/overlays/LuaEditors.cpp | 136 +++++++++++++++++- src/surge-xt/gui/overlays/LuaEditors.h | 2 + .../gui/widgets/OscillatorWaveformDisplay.cpp | 13 -- 5 files changed, 137 insertions(+), 19 deletions(-) diff --git a/src/common/LuaSupport.cpp b/src/common/LuaSupport.cpp index 07f243f4e03..57bfc929cbe 100644 --- a/src/common/LuaSupport.cpp +++ b/src/common/LuaSupport.cpp @@ -315,10 +315,6 @@ Surge::LuaSupport::SGLD::~SGLD() { std::cout << "Guarded stack leak: [" << label << "] exit=" << nt << " enter=" << top << std::endl; - for (int i = nt; i >= top; i--) - { - std::cout << " " << i << " -> " << lua_typename(L, lua_type(L, i)) << std::endl; - } } #endif } diff --git a/src/common/dsp/WavetableScriptEvaluator.cpp b/src/common/dsp/WavetableScriptEvaluator.cpp index ca6dd8d2492..0764d04a584 100644 --- a/src/common/dsp/WavetableScriptEvaluator.cpp +++ b/src/common/dsp/WavetableScriptEvaluator.cpp @@ -75,7 +75,6 @@ struct LuaWTEvaluator::Details lua_getglobal(L, "init"); if (!lua_isfunction(L, -1)) { - lua_pop(L, -1); makeEmptyState(true); } else diff --git a/src/surge-xt/gui/overlays/LuaEditors.cpp b/src/surge-xt/gui/overlays/LuaEditors.cpp index c5f29fe06af..6a6b76c0b99 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.cpp +++ b/src/surge-xt/gui/overlays/LuaEditors.cpp @@ -35,6 +35,7 @@ #include "widgets/MenuCustomComponents.h" #include #include "widgets/OscillatorWaveformDisplay.h" +#include namespace Surge { @@ -61,6 +62,62 @@ struct SurgeCodeEditorComponent : public juce::CodeEditorComponent c = c->getParentComponent(); } } + + // Handles auto indentation + + void handleReturnKey() override + { + + auto pos = this->getCaretPos(); + auto txt = pos.getLineText(); + int tabs = 0; + + for (int i = 0; i < txt.length(); i++) + { + if (txt.substring(i, i + 1) == " ") + { + tabs++; + } + else if (txt.substring(i, i + 1) == "\t") + { + tabs += this->getTabSize(); + } + else + { + bool indent = false; + auto trimmedTxt = txt.trim(); + + if (txt.substring(i, i + 8) == "function") + { + + indent = true; + } + else if (txt.substring(i, i + 2) == "if" && + trimmedTxt.substring(trimmedTxt.length() - 4, trimmedTxt.length()) == + "then") + { + indent = true; + } + else if (trimmedTxt.substring(0, 4) == "else") + { + indent = true; + } + else if (trimmedTxt.substring(trimmedTxt.length() - 2, trimmedTxt.length()) == + "do" || + trimmedTxt.substring(0, 5) == "while") + { + indent = true; + } + + tabs += indent == true ? this->getTabSize() : 0; + + break; + } + } + + this->insertTextAtCaret("\n"); + this->insertTextAtCaret(std::string(tabs, ' ')); + } }; struct EditorColors @@ -164,7 +221,7 @@ bool CodeEditorContainerWithApply::keyPressed(const juce::KeyPress &key, juce::C } else { - mainEditor->indentSelection(); + mainEditor->insertTabAtCaret(); } return true; @@ -225,12 +282,87 @@ bool CodeEditorContainerWithApply::keyPressed(const juce::KeyPress &key, juce::C return true; } + // search + else if (key.getModifiers().isCommandDown() && keyCode == 70) + { + /* + search for characters and use getCharacterBounds to get its screen position + */ + return true; + } + + // handle string completion + + else if (keyCode == 50) + { + return this->autoCompleteStringDeclaration("\""); + } + else if (keyCode == 39) + { + return this->autoCompleteStringDeclaration("'"); + } else { return Component::keyPressed(key); } } +void CodeEditorContainerWithApply::removeStringTrailsFromDocument() +{ + + /* + this needs some work as the caret position gets all screwed up after clean up + */ + + /* + auto caretPos = mainEditor->getCaretPos(); + + std::string s = mainEditor->getDocument().getAllContent().toStdString(); + std::regex pattern("[ \t]+$"); + std::string replacement = ""; + std::string result = std::regex_replace(s, pattern, replacement); + mainEditor->getDocument().replaceAllContent(result); + mainEditor->moveCaretTo(caretPos, false); + */ +} + +bool CodeEditorContainerWithApply::autoCompleteStringDeclaration(juce::String str) +{ + + auto pos = mainEditor->getCaretPos(); + auto txt = pos.getLineText(); + + int ApostrCount = 0; + + for (int i = 0; i < txt.length(); i++) + { + if (txt.substring(i, i + 1) == str) + ApostrCount++; + } + + // Close string + if (ApostrCount % 2 == 0) + { + + if (txt.substring(pos.getIndexInLine(), pos.getIndexInLine() + 1) != str) + { + mainEditor->insertTextAtCaret(str + str); + mainEditor->moveCaretLeft(false, false); + } + + else + { + mainEditor->moveCaretRight(false, false); + } + } + else + { + mainEditor->insertTextAtCaret(str); + } + return true; + // sdfsd +} + void CodeEditorContainerWithApply::paint(juce::Graphics &g) { g.fillAll(juce::Colours::black); } struct ExpandingFormulaDebugger : public juce::Component, public Surge::GUI::SkinConsumingComponent @@ -799,6 +931,7 @@ void FormulaModulatorEditor::onSkinChanged() void FormulaModulatorEditor::applyCode() { + removeStringTrailsFromDocument(); editor->undoManager()->pushFormula(scene, lfo_id, *formulastorage); formulastorage->setFormula(mainDocument->getAllContent().toStdString()); storage->getPatch().isDirty = true; @@ -1849,6 +1982,7 @@ void WavetableScriptEditor::setupEvaluator() void WavetableScriptEditor::applyCode() { + removeStringTrailsFromDocument(); osc->wavetable_formula = mainDocument->getAllContent().toStdString(); osc->wavetable_formula_res_base = controlArea->resolutionN->getIntValue(); osc->wavetable_formula_nframes = controlArea->framesN->getIntValue(); diff --git a/src/surge-xt/gui/overlays/LuaEditors.h b/src/surge-xt/gui/overlays/LuaEditors.h index 43b4ce8d773..eb161b6520b 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.h +++ b/src/surge-xt/gui/overlays/LuaEditors.h @@ -66,6 +66,8 @@ class CodeEditorContainerWithApply : public OverlayComponent, void buttonClicked(juce::Button *button) override; void codeDocumentTextDeleted(int startIndex, int endIndex) override; void codeDocumentTextInserted(const juce::String &newText, int insertIndex) override; + void removeStringTrailsFromDocument(); + bool autoCompleteStringDeclaration(juce::String str); bool keyPressed(const juce::KeyPress &key, Component *originatingComponent) override; virtual void setApplyEnabled(bool) {} diff --git a/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp b/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp index e9b278ad2d4..fc6d67eae34 100644 --- a/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp +++ b/src/surge-xt/gui/widgets/OscillatorWaveformDisplay.cpp @@ -601,7 +601,6 @@ void OscillatorWaveformDisplay::populateMenu(juce::PopupMenu &contextMenu, int s // Change this to 0 to disable WTSE component, to disable for release: change value, test, and push #define INCLUDE_WT_SCRIPTING_EDITOR 1 -#if HAS_LUA #if INCLUDE_WT_SCRIPTING_EDITOR contextMenu.addSeparator(); @@ -612,7 +611,6 @@ void OscillatorWaveformDisplay::populateMenu(juce::PopupMenu &contextMenu, int s contextMenu.addItem(Surge::GUI::toOSCase("Wavetable Script Editor..."), owts); contextMenu.addSeparator(); -#endif #endif // add this option only if we have any wavetables in the list @@ -729,17 +727,6 @@ void OscillatorWaveformDisplay::createWTMenuItems(juce::PopupMenu &contextMenu, contextMenu.addItem( Surge::GUI::toOSCase(fmt::format("Frame Length: {} samples", oscdata->wt.size)), true, false, nullptr); - -#if HAS_LUA - contextMenu.addSeparator(); - contextMenu.addItem(Surge::GUI::toOSCase("Wavetable Script Editor..."), - [w = juce::Component::SafePointer(this)]() { - if (!w) - return; - if (w->sge) - w->sge->showOverlay(SurgeGUIEditor::WTSCRIPT_EDITOR); - }); -#endif } } }