diff --git a/bin/assets/colorschemes/colorschemes.conf b/bin/assets/colorschemes/colorschemes.conf index 30db30db9..90a9b48d6 100644 --- a/bin/assets/colorschemes/colorschemes.conf +++ b/bin/assets/colorschemes/colorschemes.conf @@ -186,6 +186,8 @@ selection = #b7dce8 line_number = #d0d0d0 line_number2 = #808080 line_highlight = #f2f2f2 +suggestion = #404040,#e8e8e8 +suggestion_selected = #404040,#f7f7f7 normal = #181818 symbol = #181818 @@ -391,6 +393,9 @@ minimap_highlight = #FF00FFFF error = #990000FF; warning = #999900FF; notice = #8abdff +suggestion = #1d1f27,#e1e1e6 +suggestion_selected = #222533,#ffffff +suggestion_scrollbar = #3daee9 [solarized light] background = #fdf6e3 @@ -401,6 +406,9 @@ selection = #eee8d5 line_number = #93a1a1 line_number2 = #002b36 line_highlight = #eee8d5 +suggestion = #657b83,#f7f1de +suggestion_selected = #657b83,#eee8d5 +suggestion_scrollbar = #002b36 normal = #657b83 symbol = #657b83 @@ -583,6 +591,9 @@ minimap_highlight = #FF00FFFF error = #990000FF; warning = #999900FF; notice = #8abdff +suggestion = #1d1f27,#e1e1e6 +suggestion_selected = #222533,#f7f9f9 +suggestion_scrollbar = #ff5971 [solarobj] background = #fdf6e3 @@ -613,6 +624,10 @@ error = #990000FF; warning = #999900FF; notice = #8abdff +suggestion = #3e3c37,#ebe4d2 +suggestion_selected = #3e3c37,#fff8e4 +suggestion_scrollbar = #6c71c4 + [catppuccin macchiato] background = #24273a text = #cad3f5 @@ -669,8 +684,8 @@ line_break_column = #54575b99 matching_bracket = #dbdbdb matching_selection = #ffff00 matching_search = #0000f0 -suggestion = #e1e1e6,#1d1f27 -suggestion_selected = #ffffff,#222533 +suggestion = #1d1f27,#e1e1e6 +suggestion_selected = #222533,#ffffff suggestion_scrollbar = #3daee9 error = #ff3030 warning = yellow diff --git a/bin/assets/plugins/debugger.json b/bin/assets/plugins/debugger.json index fff95bdc2..2a4a84139 100644 --- a/bin/assets/plugins/debugger.json +++ b/bin/assets/plugins/debugger.json @@ -20,17 +20,6 @@ "env": "${env}" } }, - { - "name": "Launch binary in Terminal", - "request": "launch", - "arguments": { - "program": "${file}", - "args": "${args}", - "cwd": "${cwd}", - "env": "${env}", - "runInTerminal": true - } - }, { "name": "Attach to Name", "request": "attach", @@ -258,8 +247,7 @@ "request": "launch", "arguments": { "program": "${file}", - "args": "${args}", - "stopOnEntry": true + "args": "${args}" } } ] diff --git a/bin/assets/plugins/lspclient.json b/bin/assets/plugins/lspclient.json index 5a96f9dca..7864e827d 100644 --- a/bin/assets/plugins/lspclient.json +++ b/bin/assets/plugins/lspclient.json @@ -103,7 +103,8 @@ "name": "zls", "url": "https://github.com/zigtools/zls", "command": "zls", - "file_patterns": ["%.zig$"] + "file_patterns": ["%.zig$"], + "extra_trigger_chars": [ "," ] }, { "language": "odin", diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index 54720c8ac..462b82b34 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -302,7 +302,9 @@ ListView::cell { } ListBox:hover, -ListView:hover { +ListView:hover, +ListBox:focus, +ListView:focus { border-color: var(--primary); } @@ -383,8 +385,8 @@ SpinBox::input { } SpinBox::input, -SpinBox::input::hover, -SpinBox::input::focus { +SpinBox::input:hover, +SpinBox::input:focus { border-width: 0dp; border-color: transparent; } diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index b38317de7..feb1e36e7 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -437,6 +437,9 @@ class EE_API String { /** @return The number of codepoints of the utf8 string. */ static size_t utf8Length( const std::string_view& utf8String ); + /** Converts a character position from an utf8 string to a code point position */ + static size_t utf8ToCodepointPosition( const std::string_view& utf8Text, size_t utf8Pos ); + /** @return The next character in a utf8 null terminated string */ static Uint32 utf8Next( char*& utf8String ); diff --git a/include/eepp/ui/doc/textrange.hpp b/include/eepp/ui/doc/textrange.hpp index c302f0873..4a03fbccd 100644 --- a/include/eepp/ui/doc/textrange.hpp +++ b/include/eepp/ui/doc/textrange.hpp @@ -114,6 +114,12 @@ class EE_API TextRange { bool isNormalized() const { return mStart <= mEnd; } + static TextRange convertToLineColumn( const String::View& text, Int64 startOffset, + Int64 endOffset ); + + static TextRange convertToLineColumn( const std::string_view& text, Int64 startOffset, + Int64 endOffset ); + private: TextPosition mStart; TextPosition mEnd; @@ -121,6 +127,10 @@ class EE_API TextRange { TextPosition normalizedStart() const { return mStart < mEnd ? mStart : mEnd; } TextPosition normalizedEnd() const { return mStart < mEnd ? mEnd : mStart; } + + template + static TextRange convertToLineColumn( const StringType& text, Int64 startOffset, + Int64 endOffset ); }; class EE_API TextRanges : public std::vector { diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 9a30db70c..dff88fee1 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -1261,18 +1261,18 @@ bool String::isAscii() const { size_t len = mString.size(); size_t i = 0; -// #ifdef EE_STD_SIMD -// using simd_type = simd::native_simd; -// constexpr size_t simd_size = simd_type::size(); -// const simd_type ascii_limit = 127; -// for ( ; i + simd_size - 1 < len; i += simd_size ) { -// simd_type chunk; -// chunk.copy_from( &data[i], simd::element_aligned ); -// auto mask = chunk > ascii_limit; -// if ( simd::any_of( mask ) ) -// return false; -// } -// #endif + // #ifdef EE_STD_SIMD + // using simd_type = simd::native_simd; + // constexpr size_t simd_size = simd_type::size(); + // const simd_type ascii_limit = 127; + // for ( ; i + simd_size - 1 < len; i += simd_size ) { + // simd_type chunk; + // chunk.copy_from( &data[i], simd::element_aligned ); + // auto mask = chunk > ascii_limit; + // if ( simd::any_of( mask ) ) + // return false; + // } + // #endif for ( ; i < len; ++i ) if ( data[i] > 127 ) @@ -1590,6 +1590,44 @@ Uint32 String::utf8Next( char*& utf8String ) { return utf8::unchecked::next( utf8String ); } +size_t String::utf8ToCodepointPosition( const std::string_view& utf8Text, size_t utf8Pos ) { + size_t codepointPos = 0; + size_t bytePos = 0; + + while ( bytePos < utf8Pos && bytePos < utf8Text.length() ) { + unsigned char c = utf8Text[bytePos]; + + // Skip continuation bytes (10xxxxxx) + if ( ( c & 0xC0 ) == 0x80 ) { + bytePos++; + continue; + } + + // Count this as one codepoint + codepointPos++; + + // Move to the next character + if ( c < 0x80 ) + bytePos += 1; // ASCII + else if ( c < 0xE0 ) + bytePos += 2; // 2-byte sequence + else if ( c < 0xF0 ) + bytePos += 3; // 3-byte sequence + else + bytePos += 4; // 4-byte sequence + + // Handle potential truncated sequences + if ( bytePos > utf8Text.length() ) + break; + } + + // If we're in the middle of a character, return the previous complete character position + if ( utf8Pos > bytePos ) + codepointPos--; + + return codepointPos; +} + String::operator std::string() const { return toUtf8(); } diff --git a/src/eepp/ui/doc/syntaxtokenizer.cpp b/src/eepp/ui/doc/syntaxtokenizer.cpp index 327e9e7ab..907807400 100644 --- a/src/eepp/ui/doc/syntaxtokenizer.cpp +++ b/src/eepp/ui/doc/syntaxtokenizer.cpp @@ -197,6 +197,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax PatternMatcher::Range matches[12]; int start, end; + const std::string_view textv{ text }; size_t numMatches; size_t i = startIndex; SyntaxState retState = state; @@ -228,7 +229,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax ( range.first == -1 || rangeSubsyntax.first < range.first ) ) { if ( !skipSubSyntaxSeparator ) { pushToken( tokens, curState.subsyntaxInfo->types[0], - text.substr( i, rangeSubsyntax.second - i ) ); + textv.substr( i, rangeSubsyntax.second - i ) ); } popSubsyntax( curState, retState, syntax ); i = rangeSubsyntax.second; @@ -239,16 +240,16 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax if ( !skip ) { if ( range.first != -1 ) { if ( range.second > range.first && pattern.types.size() >= 3 ) { - pushToken( tokens, pattern.types[0], text.substr( i, range.first - i ) ); + pushToken( tokens, pattern.types[0], textv.substr( i, range.first - i ) ); pushToken( tokens, pattern.types[pattern.types.size() - 1], - text.substr( range.first, range.second - range.first ) ); + textv.substr( range.first, range.second - range.first ) ); } else { - pushToken( tokens, pattern.types[0], text.substr( i, range.second - i ) ); + pushToken( tokens, pattern.types[0], textv.substr( i, range.second - i ) ); } setSubsyntaxPatternIdx( curState, retState, SYNTAX_TOKENIZER_STATE_NONE ); i = range.second; } else { - pushToken( tokens, pattern.types[0], text.substr( i ) ); + pushToken( tokens, pattern.types[0], textv.substr( i ) ); break; } } @@ -264,7 +265,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax if ( rangeSubsyntax.first != -1 ) { if ( !skipSubSyntaxSeparator ) { pushToken( tokens, curState.subsyntaxInfo->types[0], - text.substr( i, rangeSubsyntax.second - i ) ); + textv.substr( i, rangeSubsyntax.second - i ) ); } popSubsyntax( curState, retState, syntax ); i = rangeSubsyntax.second; @@ -292,7 +293,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax int patternMatchStart = matches[0].start; int patternMatchEnd = matches[0].end; std::string patternFullText( - text.substr( patternMatchStart, patternMatchEnd - patternMatchStart ) ); + textv.substr( patternMatchStart, patternMatchEnd - patternMatchStart ) ); auto patternType = pattern.types[0]; int lastStart = patternMatchStart; int lastEnd = patternMatchEnd; @@ -315,13 +316,13 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax if ( curMatch == 1 && start > lastStart ) { pushToken( tokens, patternType, - text.substr( patternMatchStart, start - patternMatchStart ) ); + textv.substr( patternMatchStart, start - patternMatchStart ) ); } else if ( start > lastEnd ) { pushToken( tokens, patternType, - text.substr( lastEnd, start - lastEnd ) ); + textv.substr( lastEnd, start - lastEnd ) ); } - patternText = text.substr( start, end - start ); + patternText = textv.substr( start, end - start ); SyntaxStyleType type = curState.currentSyntax->getSymbol( patternText ); if ( !skipSubSyntaxSeparator || !pattern.hasSyntax() ) { pushToken( tokens, @@ -344,7 +345,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax if ( curMatch == numMatches - 1 && end < patternMatchEnd ) { pushToken( tokens, patternType, - text.substr( end, patternMatchEnd - end ) ); + textv.substr( end, patternMatchEnd - end ) ); i = patternMatchEnd; } @@ -367,7 +368,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax String::utf8Next( strEnd ); end = start + ( strEnd - strStart ); } - patternText = text.substr( start, end - start ); + patternText = textv.substr( start, end - start ); SyntaxStyleType type = curState.currentSyntax->getSymbol( patternText ); if ( !skipSubSyntaxSeparator || !pattern.hasSyntax() ) { pushToken( tokens, diff --git a/src/eepp/ui/doc/textrange.cpp b/src/eepp/ui/doc/textrange.cpp index 1506bef67..71565c199 100644 --- a/src/eepp/ui/doc/textrange.cpp +++ b/src/eepp/ui/doc/textrange.cpp @@ -101,6 +101,68 @@ TextRange TextRange::fromString( const std::string& range ) { return {}; } +template +TextRange TextRange::convertToLineColumn( const StringType& text, Int64 startOffset, + Int64 endOffset ) { + if ( startOffset < 0 || endOffset < 0 || startOffset > static_cast( text.length() ) || + endOffset > static_cast( text.length() ) || startOffset > endOffset ) { + return {}; + } + + TextRange result; + Int64 currentLine = 0; + Int64 currentCol = 0; + Int64 currentPos = 0; + bool foundStart = false; + bool foundEnd = false; + size_t len = text.length(); + + for ( size_t i = 0; i < len; i++ ) { + if ( currentPos == startOffset ) { + result.setStart( { currentLine, currentCol } ); + foundStart = true; + } + + if ( currentPos == endOffset ) { + result.setEnd( { currentLine, currentCol } ); + foundEnd = true; + } + + if ( foundStart && foundEnd ) + break; + + if ( i == text.length() ) + break; + + if ( text[i] == '\n' ) { + currentLine++; + currentCol = 0; + } else { + currentCol++; + } + + currentPos++; + } + + if ( currentPos == startOffset ) + result.setStart( { currentLine, currentCol } ); + + if ( currentPos == endOffset ) + result.setEnd( { currentLine, currentCol } ); + + return result; +} + +TextRange TextRange::convertToLineColumn( const String::View& text, Int64 startOffset, + Int64 endOffset ) { + return convertToLineColumn( text, startOffset, endOffset ); +} + +TextRange TextRange::convertToLineColumn( const std::string_view& text, Int64 startOffset, + Int64 endOffset ) { + return convertToLineColumn( text, startOffset, endOffset ); +} + TextRanges::TextRanges() {} TextRanges::TextRanges( const std::vector& ranges ) : std::vector( ranges ) {} diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index 1dc5bc162..33e6c95d9 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -357,10 +357,9 @@ bool AutoCompletePlugin::onKeyDown( UICodeEditor* editor, const KeyEvent& event } } else if ( mShortcuts["autocomplete-next-signature-help"] == eventShortcut ) { if ( mSignatureHelp.signatures.size() > 1 ) { - mSignatureHelpSelected = - mSignatureHelpSelected == (int)mSignatureHelp.signatures.size() - 1 - ? mSignatureHelp.signatures.size() - 1 - : 0; + mSignatureHelpSelected = mSignatureHelpSelected <= 0 + ? mSignatureHelp.signatures.size() + : mSignatureHelpSelected; --mSignatureHelpSelected; mSignatureHelpSelected = mSignatureHelpSelected % mSignatureHelp.signatures.size(); editor->invalidateDraw(); @@ -818,9 +817,68 @@ AutoCompletePlugin::processSignatureHelp( const LSPSignatureHelp& signatureHelp } if ( !editor ) return {}; - editor->runOnMainThread( [this, editor, signatureHelp] { + + // Convert the LSP Signature Help into our own object: + // We will convert the UTF-8 label to UTF-32, then we will remove any new lines and extra spaces + // This guarantees that we always display a single line signature help + SignatureHelp signatures; + signatures.activeSignature = signatureHelp.activeSignature; + signatures.activeParameter = signatureHelp.activeParameter; + signatures.signatures.reserve( signatureHelp.signatures.size() ); + + TextDocument doc; + for ( const auto& sig : signatureHelp.signatures ) { + String initialLabel( sig.label ); + SignatureInformation nsig; + nsig.documentation = sig.documentation; + + doc.reset(); + doc.textInput( initialLabel ); + std::vector parameters; + parameters.reserve( sig.parameters.size() ); + + for ( size_t i = 0; i < sig.parameters.size(); i++ ) { + auto start = String::utf8ToCodepointPosition( sig.label, sig.parameters[i].start ); + auto end = String::utf8ToCodepointPosition( sig.label, sig.parameters[i].end ); + auto sel = TextRange::convertToLineColumn( initialLabel.view(), start, end ); + + if ( i == 0 ) + doc.setSelection( i, sel ); + else + doc.addSelection( sel ); + + parameters.emplace_back( doc.getSelectedText( i ) ); + } + + auto selections( doc.getSelections() ); + nsig.parameters.reserve( selections.size() ); + + if ( 0 != doc.replaceAll( "\n", "" ) ) { + while ( 0 != doc.replaceAll( " ", " " ) ) + ; + + nsig.label = doc.line( 0 ).getTextWithoutNewLine(); + + for ( const auto& param : parameters ) { + auto res = doc.find( param ); + if ( res.isValid() ) + nsig.parameters.emplace_back( res.result ); + } + } else { + nsig.label = std::move( initialLabel ); + + if ( !sig.parameters.empty() ) { + for ( auto& sel : selections ) + nsig.parameters.emplace_back( sel ); + } + } + + signatures.signatures.emplace_back( nsig ); + } + + editor->runOnMainThread( [this, editor, signatures = std::move( signatures )] { mSignatureHelpVisible = true; - mSignatureHelp = signatureHelp; + mSignatureHelp = signatures; if ( mSignatureHelp.signatures.empty() ) resetSignatureHelp(); editor->invalidateDraw(); @@ -942,7 +1000,7 @@ void AutoCompletePlugin::drawSignatureHelp( UICodeEditor* editor, const Vector2f primitives.setColor( Color( selectedStyle.background ).blendAlpha( editor->getAlpha() ) ); String str; if ( mSignatureHelp.signatures.size() > 1 ) { - str = String::format( "%s (%d of %zu)", curSig.label.c_str(), + str = String::format( "%s (%d of %zu)", curSig.label.toUtf8(), mSignatureHelpSelected == -1 ? 1 : mSignatureHelpSelected + 1, mSignatureHelp.signatures.size() ); } else { @@ -962,38 +1020,42 @@ void AutoCompletePlugin::drawSignatureHelp( UICodeEditor* editor, const Vector2f } bool hasParams = !curSig.parameters.empty(); - LSPParameterInformation curParam = + TextRange curParam = hasParams ? curSig.parameters[mSignatureHelp.activeParameter % curSig.parameters.size()] - : LSPParameterInformation{ -1, -1 }; + : TextRange{}; Rectf curParamRect; if ( hasParams ) { curParamRect = Rectf( { { boxRect.getPosition().x + mBoxPadding.Left + - curParam.start * editor->getGlyphWidth(), + curParam.start().column() * editor->getGlyphWidth(), boxRect.getPosition().y }, - { ( curParam.end - curParam.start ) * editor->getGlyphWidth(), mRowHeight } } ); + { ( curParam.end().column() - curParam.start().column() ) * editor->getGlyphWidth(), + mRowHeight } } ); if ( !editor->getScreenRect().contains( Rectf{ { curParamRect.getPosition().x + - ( curParam.end - curParam.start ) * editor->getGlyphWidth(), + ( curParam.end().column() - curParam.start().column() ) * + editor->getGlyphWidth(), curParamRect.getPosition().y }, curParamRect.getSize() } ) ) { auto offset = editor->getTextPositionOffset( mSignatureHelpPosition ); - pos = { static_cast( startScroll.x - curParam.start * editor->getGlyphWidth() + + pos = { static_cast( startScroll.x - + curParam.start().column() * editor->getGlyphWidth() + offset.x ), static_cast( startScroll.y + offset.y + vdiff ) }; boxRect.setPosition( pos ); curParamRect.setPosition( { boxRect.getPosition().x + mBoxPadding.Left + - curParam.start * editor->getGlyphWidth(), + curParam.start().column() * editor->getGlyphWidth(), boxRect.getPosition().y } ); } } primitives.drawRoundedRectangle( boxRect, 0.f, Vector2f::One, 6 ); - if ( hasParams && curParam.end - curParam.start > 0 && curParam.end < (int)str.size() ) { + if ( hasParams && curParam.end() != curParam.start() && + curParam.end().column() < (int)str.size() ) { primitives.setColor( matchingSelection.color ); primitives.drawRoundedRectangle( curParamRect, 0.f, Vector2f::One, 6 ); } @@ -1112,10 +1174,13 @@ void AutoCompletePlugin::postDraw( UICodeEditor* editor, const Vector2f& startSc LSPCompletionItemHelper::toIconString( suggestion.kind ), PixelDensity::dpToPxI( 12 ) ); if ( icon ) { + Color iconColor( icon->getColor() ); + icon->setColor( mSuggestionIndex == (int)i ? selectedStyle.color : normalStyle.color ); Vector2f padding( eefloor( ( iconSpace.getWidth() - icon->getSize().getWidth() ) * 0.5f ), eefloor( ( iconSpace.getHeight() - icon->getSize().getHeight() ) * 0.5f ) ); icon->draw( { cursorPos.x + padding.x, cursorPos.y + mRowHeight * count + padding.y } ); + icon->setColor( iconColor ); } if ( mSuggestionIndex == (int)i && !suggestion.documentation.value.empty() ) { diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index 6bbc86e4c..423b9048c 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -63,7 +63,7 @@ class AutoCompletePlugin : public Plugin { "Auto complete shows the completion popup as you type, so you can fill " "in long words by typing only a few characters.", AutoCompletePlugin::New, - { 0, 2, 6 }, + { 0, 2, 7 }, AutoCompletePlugin::NewSync }; } @@ -144,7 +144,20 @@ class AutoCompletePlugin : public Plugin { Int32 mSuggestionsStartIndex{ 0 }; std::unordered_map mCapabilities; Mutex mCapabilitiesMutex; - LSPSignatureHelp mSignatureHelp; + + struct SignatureInformation { + String label; + LSPMarkupContent documentation; + std::vector parameters; + }; + + struct SignatureHelp { + std::vector signatures; + int activeSignature{ 0 }; + int activeParameter{ 0 }; + }; + + SignatureHelp mSignatureHelp; TextPosition mSignatureHelpPosition; Int32 mSignatureHelpSelected{ -1 }; Mutex mHandlesMutex; diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 6f03ee497..ff7b2376a 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -192,10 +192,6 @@ void DebuggerClientListener::sendBreakpoints() { Lock l( mPlugin->mBreakpointsMutex ); for ( const auto& fileBps : mPlugin->mBreakpoints ) { std::string path( fileBps.first ); - if ( isRemote() ) { - FileSystem::filePathRemoveBasePath( mPlugin->mProjectPath, path ); - path = "/" + path; - } mClient->setBreakpoints( path, fromSet( fileBps.second ) ); } } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 760b1e79c..f09de0fc3 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -330,6 +330,7 @@ static std::initializer_list DebuggerCommandList = { "debugger-breakpoint-enable-toggle", "debugger-start", "debugger-stop", + "debugger-start-stop", "debugger-step-over", "debugger-step-into", "debugger-step-out", @@ -448,7 +449,7 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi } if ( mKeyBindings.empty() ) { - mKeyBindings["debugger-start"] = "mod+f5"; + mKeyBindings["debugger-start-stop"] = "mod+f5"; mKeyBindings["debugger-continue-interrupt"] = "f5"; mKeyBindings["debugger-breakpoint-toggle"] = "f9"; mKeyBindings["debugger-breakpoint-enable-toggle"] = "mod+f9"; @@ -1269,6 +1270,13 @@ void DebuggerPlugin::onRegisterDocument( TextDocument* doc ) { doc->setCommand( "debugger-stop", [this] { exitDebugger( true ); } ); + doc->setCommand( "debugger-start-stop", [this] { + if ( mDebugger ) + exitDebugger( true ); + else + runCurrentConfig(); + } ); + doc->setCommand( "debugger-breakpoint-toggle", [doc, this] { if ( setBreakpoint( doc, doc->getSelection().start().line() + 1 ) ) getUISceneNode()->getRoot()->invalidateDraw(); diff --git a/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp b/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp index 5c9776b3e..74a444c55 100644 --- a/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp +++ b/src/tools/ecode/plugins/debugger/models/threadsmodel.cpp @@ -24,8 +24,11 @@ std::string ThreadsModel::columnName( const size_t& colIdx ) const { Variant ThreadsModel::data( const ModelIndex& modelIndex, ModelRole role ) const { if ( role == ModelRole::Display && modelIndex.column() == Columns::ID ) { - return Variant( String::format( "#%d (%s)", mThreads[modelIndex.row()].id, - mThreads[modelIndex.row()].name.c_str() ) ); + if ( mThreads[modelIndex.row()].name.empty() ) + return Variant( String::format( "#%d", mThreads[modelIndex.row()].id ) ); + else + return Variant( String::format( "#%d (%s)", mThreads[modelIndex.row()].id, + mThreads[modelIndex.row()].name.c_str() ) ); } else if ( role == ModelRole::Icon && modelIndex.column() == Columns::ID && mThreads[modelIndex.row()].id == mCurrentThreadId ) { static UIIcon* circleFilled = mSceneNode->findIcon( "circle-filled" ); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 0f55ee0bf..14648c505 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -1,5 +1,5 @@ -#include "lspclientplugin.hpp" #include "../../version.hpp" +#include "lspclientplugin.hpp" #include #include #include @@ -1284,6 +1284,7 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std lsp.host = tlsp.host; lsp.port = tlsp.port; lsp.initializationOptions = tlsp.initializationOptions; + lsp.extraTriggerChars = tlsp.extraTriggerChars; lsp.usesLSP = use; if ( obj.contains( "share_process" ) && obj["share_process"].is_boolean() ) { lsp.shareProcessWithOtherDefinition = obj["share_process"].get(); @@ -1320,13 +1321,22 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std auto& fp = obj["file_patterns"]; for ( auto& pattern : fp ) - lsp.filePatterns.push_back( pattern.get() ); + if ( pattern.is_string() ) + lsp.filePatterns.push_back( pattern.get() ); if ( obj.contains( "rootIndicationFileNames" ) ) { lsp.rootIndicationFileNames.clear(); auto& fnms = obj["rootIndicationFileNames"]; for ( auto& fn : fnms ) - lsp.rootIndicationFileNames.push_back( fn ); + if ( fn.is_string() ) + lsp.rootIndicationFileNames.push_back( fn ); + } + + if ( obj.contains( "extra_trigger_chars" ) && obj["extra_trigger_chars"].is_array() ) { + for ( auto& jch : obj["extra_trigger_chars"] ) { + if ( jch.is_string() ) + lsp.extraTriggerChars.push_back( jch ); + } } sanitizeCommand( lsp.command, mManager->getWorkspaceFolder() ); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index b2727fa93..25fced745 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -1,5 +1,5 @@ -#include "lspclientserver.hpp" #include "lspclientplugin.hpp" +#include "lspclientserver.hpp" #include "lspclientservermanager.hpp" #include #include @@ -1201,6 +1201,10 @@ void LSPClientServer::initialize() { try { #endif fromJson( mCapabilities, resp["capabilities"] ); + + for ( const auto& ch : mLSP.extraTriggerChars ) + if ( !ch.empty() ) + mCapabilities.signatureHelpProvider.triggerCharacters.push_back( ch[0] ); #ifndef EE_DEBUG } catch ( const json::exception& e ) { Log::warning( diff --git a/src/tools/ecode/plugins/lsp/lspdefinition.hpp b/src/tools/ecode/plugins/lsp/lspdefinition.hpp index 8f31bb8fc..727c53a75 100644 --- a/src/tools/ecode/plugins/lsp/lspdefinition.hpp +++ b/src/tools/ecode/plugins/lsp/lspdefinition.hpp @@ -30,6 +30,7 @@ struct LSPDefinition { std::string usesLSP; bool shareProcessWithOtherDefinition{ false }; bool disabled{ false }; + std::vector extraTriggerChars; bool commandAvailable() const { auto cmdp( String::split( command, ' ' ) ); diff --git a/src/tools/ecode/plugins/lsp/lspprotocol.hpp b/src/tools/ecode/plugins/lsp/lspprotocol.hpp index 1ad011a3d..731693ce2 100644 --- a/src/tools/ecode/plugins/lsp/lspprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspprotocol.hpp @@ -637,7 +637,7 @@ struct LSPPreviousResultId { using LSPPreviousResultIds = std::vector; static constexpr auto LSPDocumentDiagnosticReportKindFull = "full"; -static constexpr auto LSPDocumentDiagnosticReportKindUnchanged= "unchanged"; +static constexpr auto LSPDocumentDiagnosticReportKindUnchanged = "unchanged"; struct LSPFullDocumentDiagnosticReport { URI uri;