Implement autocompletion for rule s-expr syntax.

This commit is contained in:
Jeff Young 2020-05-25 00:43:19 +01:00
parent 160981ee71
commit 90c4249de5
2 changed files with 117 additions and 0 deletions

View File

@ -48,10 +48,126 @@ PANEL_SETUP_RULES::PANEL_SETUP_RULES( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFr
m_textEditor->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, highlight );
m_textEditor->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
m_textEditor->Bind( wxEVT_STC_CHARADDED, &PANEL_SETUP_RULES::onScintillaCharAdded, this );
m_textEditor->Bind( wxEVT_STC_UPDATEUI, &PANEL_SETUP_RULES::onScintillaUpdateUI, this );
}
void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
{
constexpr int flags = wxSTC_FIND_REGEXP| wxSTC_FIND_POSIX;
m_textEditor->SearchAnchor();
int i = std::max( 0, m_textEditor->SearchPrev( flags, "\( *rule " ) );
int currentPos = m_textEditor->GetCurrentPos();
enum
{
NONE,
STRING,
SEXPR_OPEN,
SEXPR_TOKEN,
};
std::stack<wxString> sexprs;
wxString partial;
int context = NONE;
for( ; i < currentPos; ++i )
{
char c = (char) m_textEditor->GetCharAt( i );
if( c == '\\' )
{
i++; // skip escaped char
continue;
}
if( context == STRING )
{
if( c == '"' )
context = NONE;
else
partial += c;
continue;
}
if( c == '"' )
{
partial = wxEmptyString;
context = STRING;
}
else if( c == '(' )
{
if( context == SEXPR_OPEN && !partial.IsEmpty() )
sexprs.push( partial );
partial = wxEmptyString;
context = SEXPR_OPEN;
}
else if( c == ')' )
{
sexprs.pop();
context = NONE;
}
else if( c == ' ' )
{
if( context == SEXPR_OPEN && !partial.IsEmpty() )
{
sexprs.push( partial );
wxString top = sexprs.size() ? sexprs.top() : wxEmptyString;
if( top == "constraint" || top == "disallow" )
{
partial = wxEmptyString;
context = SEXPR_TOKEN;
continue;
}
}
context = NONE;
}
else
{
partial += c;
}
}
// NB: tokens MUST be in alphabetical order because the Scintilla engine is going
// to do a binary search on them
wxString tokens;
if( context == SEXPR_OPEN )
{
if( sexprs.empty() )
tokens = "rule version";
else if( sexprs.top() == "rule" )
tokens = "condition constraint disallow";
else if( sexprs.top() == "constraint" )
tokens = "max min opt";
if( !tokens.IsEmpty() )
m_textEditor->AutoCompShow( partial.size(), tokens );
}
else if( context == SEXPR_TOKEN )
{
if( sexprs.top() == "constraint" )
tokens = "annulus_width clearance hole track_width";
else if( sexprs.top() == "disallow" )
tokens = "blind_via graphic hole micro_via pad text track via zone";
int wordStartPos = m_textEditor->WordStartPosition( currentPos, true );
wxASSERT( currentPos - wordStartPos == partial.size() );
if( !tokens.IsEmpty() )
m_textEditor->AutoCompShow( partial.size(), tokens );
}
}
void PANEL_SETUP_RULES::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
{
auto isBrace = []( int c ) -> bool

View File

@ -43,6 +43,7 @@ public:
~PANEL_SETUP_RULES( ) override { };
private:
void onScintillaCharAdded( wxStyledTextEvent &aEvent );
void onScintillaUpdateUI( wxStyledTextEvent& aEvent );
bool TransferDataToWindow() override;