📄 nativeparser.cpp
字号:
col = editor->GetControl()->GetColumn(pos);
// replace tabs in line by equal-count spaces because col is in spaces!
actual.Replace(_T("\t"), tabwidth);
actual.Remove(col);
actual.Trim();
}
else
{
actual = lineText;
col = actual.Length() - 1;
}
Manager::Get()->GetMessageManager()->DebugLog(_("Doing AI for '%s':"), actual.c_str());
// find current function's namespace
wxString procName;
wxString scopeName;
FindFunctionNamespace(editor, &scopeName, &procName);
Token* scopeToken = 0L;
if (!scopeName.IsEmpty())
scopeToken = parser->FindTokenByName(scopeName, false, tkNamespace | tkClass);
while (1)
{
// wxString bef = actual;
wxString tok = GetCCToken(actual, tokenType);
// wxString aft = actual;
// Manager::Get()->GetMessageManager()->DebugLog("before='%s', token='%s', after='%s', namespace=%d", bef.c_str(), tok.c_str(), aft.c_str(), tokenType);
Manager::Get()->GetMessageManager()->DebugLog(_("tok='%s'"), tok.c_str());
if (tok.IsEmpty())
break;
if (actual.IsEmpty() && tokenType == pttSearchText)
{
searchtext = tok;
break;
}
if (tokenType == pttNamespace)
{
//parentToken = parser->FindTokenByName(tok);
parentToken = parser->FindChildTokenByName(parentToken, tok, true);
if (!parentToken)
parentToken = parser->FindChildTokenByName(scopeToken, tok, true); // try local scope
Manager::Get()->GetMessageManager()->DebugLog(_("Namespace '%s'"), parentToken ? parentToken->m_Name.c_str() : _("unknown"));
if (!parentToken)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Bailing out: namespace not found"));
return 0; // fail deliberately
}
}
else
{
Token* token = 0L;
// try #1 - special case
if (tok.Matches(_T("this"))) // <-- special case
{
token = scopeToken;
parentToken = scopeToken;
}
// try #2 - function's class member
if (!token)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Looking for %s under %s"), tok.c_str(), scopeToken ? scopeToken->m_Name.c_str() : _("Unknown"));
token = parser->FindChildTokenByName(scopeToken, tok, true); // try local scope
}
// try #3 - everything else
if (!token)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Looking for %s under %s"), tok.c_str(), parentToken ? parentToken->m_Name.c_str() : _("Unknown"));
token = parser->FindChildTokenByName(parentToken, tok, true);
}
// NOTE: Now that #2 is checked before #3, class member supersedes similarly named
// function argument (if any). But if we put #3 before #2, we 'll be checking
// global tokens first, which is not what we want...
if (token)
Manager::Get()->GetMessageManager()->DebugLog(_("Token found %s, type '%s'"), token->m_Name.c_str(), token->m_ActualType.c_str());
if (token && !token->m_ActualType.IsEmpty())
{
Manager::Get()->GetMessageManager()->DebugLog(_("actual type is %s"), token->m_ActualType.c_str());
wxString srch = token->m_ActualType;
int colon = srch.Find(_T("::"));
if (colon != -1)
{
// type has namespace; break it down and search for it
while (!srch.IsEmpty())
{
parentToken = parser->FindChildTokenByName(parentToken, srch.Left(colon), true);
if (!parentToken)
break;
Manager::Get()->GetMessageManager()->DebugLog(_("searching under %s"), parentToken->m_DisplayName.c_str());
srch.Remove(0, colon + 2); // plus two to compensate for "::"
colon = srch.Find(_T("::"));
if (colon == -1)
colon = wxSTRING_MAXLEN;
}
}
else
{
Manager::Get()->GetMessageManager()->DebugLog(_("Locating %s"), token->m_ActualType.c_str());
parentToken = parser->FindTokenByName(token->m_ActualType, true, tkClass | tkNamespace | tkEnum);
if (!parentToken) // one more, global, try (might be under a namespace)
parentToken = parser->FindTokenByName(token->m_ActualType, false, tkClass | tkNamespace | tkEnum);
}
}
Manager::Get()->GetMessageManager()->DebugLog(_("Class '%s'"), parentToken ? parentToken->m_Name.c_str() : _("unknown"));
if (!parentToken)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Bailing out: class not found"));
return 0; // fail deliberately
}
}
//Manager::Get()->GetMessageManager()->Log(mltDevDebug, "parentToken=0x%8.8x", parentToken);
}
if (noPartialMatch && searchtext.IsEmpty())
return 0;
bool bCaseSensitive = parser->Options().caseSensitive || caseSensitive;
if (!bCaseSensitive)
searchtext.MakeLower();
Manager::Get()->GetMessageManager()->DebugLog(_("Scope='%s'"), scopeToken ? scopeToken->m_Name.c_str() : _("Unknown"));
if (parentToken)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Final parent: '%s' (count=%d, search=%s)"), parentToken->m_Name.c_str(), parentToken->m_Children.GetCount(), searchtext.c_str());
for (unsigned int i = 0; i < parentToken->m_Children.GetCount(); ++i)
{
Token* token = parentToken->m_Children[i];
if (token->m_IsOperator)
continue; // ignore operators
wxString name = token->m_Name;
if (!bCaseSensitive)
name.MakeLower();
bool textCondition;
if (noPartialMatch)
textCondition = searchtext.IsEmpty() ? false : name.Matches(searchtext);
else
{
if (lineText.IsEmpty())
textCondition = searchtext.IsEmpty() ? true : name.StartsWith(searchtext);
else
textCondition = searchtext.IsEmpty() ? true : name.Matches(searchtext);
}
if (token->m_TokenKind == tkEnum)
{
// enums children (enumerators), are added by default
for (unsigned int i2 = 0; i2 < token->m_Children.GetCount(); ++i2)
{
Token* ctok = token->m_Children[i2];
ctok->m_Bool = true;
++count;
}
}
// scope-based member access :)
// display public members
// private/protected are displayed only if in same scope...
bool scopeCondition =
// we can access public members
token->m_Scope == tsPublic ||
// we can access private/protected members of current scope only
scopeToken == parentToken;
token->m_Bool = textCondition && scopeCondition;// &&
// token->m_TokenKind != tkConstructor && // ignore constructors
// token->m_TokenKind != tkDestructor; // and destructors too
if (token->m_Bool)
++count;
}
// look for inheritance
count += DoInheritanceAI(parentToken, scopeToken, searchtext, bCaseSensitive);
}
else
{
//Manager::Get()->GetMessageManager()->Log(mltDevDebug, "no token");
// just globals and current function's parent class members here...
Manager::Get()->GetMessageManager()->DebugLog(_("Procedure of class '%s' (0x%8.8x), name='%s'"), scopeName.c_str(), scopeToken, procName.c_str());
for (unsigned int i = 0; i < parser->GetTokens().GetCount(); ++i)
{
Token* token = parser->GetTokens()[i];
if (token->m_IsOperator)
continue; // ignore operators
wxString name = token->m_Name;
if (!bCaseSensitive)
name.MakeLower();
bool textCondition;
if (!noPartialMatch && lineText.IsEmpty())
textCondition = searchtext.IsEmpty() ? true : name.StartsWith(searchtext);
else
textCondition = searchtext.IsEmpty() ? false : name.Matches(searchtext);
token->m_Bool = textCondition &&
(!token->m_pParent || // globals
token->m_TokenKind == tkEnumerator || // enumerators
token->m_pParent == scopeToken || // child of procToken
!lineText.IsEmpty()); // locals too
if (token->m_Bool)
++count;
}
// look for inheritance
count += DoInheritanceAI(scopeToken, scopeToken, searchtext, bCaseSensitive);
}
return count;
}
int NativeParser::DoInheritanceAI(Token* parentToken, Token* scopeToken, const wxString& searchText, bool caseSensitive)
{
int count = 0;
if (!parentToken)
return 0;
Manager::Get()->GetMessageManager()->DebugLog(_("Checking inheritance of %s"), parentToken->m_Name.c_str());
Manager::Get()->GetMessageManager()->DebugLog(_("- Has %d ancestor(s)"), parentToken->m_Ancestors.GetCount());
for (unsigned int i = 0; i < parentToken->m_Ancestors.GetCount(); ++i)
{
Token* ancestor = parentToken->m_Ancestors[i];
Manager::Get()->GetMessageManager()->DebugLog(_("- Checking ancestor %s"), ancestor->m_Name.c_str());
int bak = count;
for (unsigned int x = 0; x < ancestor->m_Children.GetCount(); ++x)
{
Token* token = ancestor->m_Children[x];
wxString name = token->m_Name;
if (!caseSensitive)
name.MakeLower();
bool textCondition = searchText.IsEmpty() ? true : name.StartsWith(searchText);
//Manager::Get()->GetMessageManager()->DebugLog("- [%s] %s: %s", searchText.c_str(), name.c_str(), textCondition ? "match" : "no match");
token->m_Bool = textCondition &&
(token->m_Scope == tsPublic || (scopeToken && scopeToken->InheritsFrom(ancestor)));
if (token->m_Bool)
count++;
}
Manager::Get()->GetMessageManager()->DebugLog(_("- %d matches"), count - bak);
count += DoInheritanceAI(ancestor, scopeToken, searchText, caseSensitive);
}
return count;
}
bool NativeParser::SkipWhitespaceForward(cbEditor* editor, int& pos)
{
if (!editor)
return false;
wxChar ch = editor->GetControl()->GetCharAt(pos);
int len = editor->GetControl()->GetLength() - 1;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
{
while (pos < len && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'))
{
++pos;
ch = editor->GetControl()->GetCharAt(pos);
}
return true;
}
return false;
}
bool NativeParser::SkipWhitespaceBackward(cbEditor* editor, int& pos)
{
if (!editor)
return false;
wxChar ch = editor->GetControl()->GetCharAt(pos);
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
{
while (pos > 0 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'))
{
--pos;
ch = editor->GetControl()->GetCharAt(pos);
}
return true;
}
return false;
}
int NativeParser::FindCurrentBlockStart(cbEditor* editor)
{
int pos = -1;
int line = editor->GetControl()->GetCurrentLine();
while (line >= 0)
{
int level = editor->GetControl()->GetFoldLevel(line);
if ((level & wxSCI_FOLDLEVELHEADERFLAG) &&
(wxSCI_FOLDLEVELBASE == (level & wxSCI_FOLDLEVELNUMBERMASK)))
{
// we 're at block start (maybe '{')
wxString lineStr = editor->GetControl()->GetLine(line);
pos = lineStr.Find(_T("{"));
if (pos != wxNOT_FOUND)
{
pos += editor->GetControl()->PositionFromLine(line);
break;
}
}
--line;
}
return pos;
}
bool NativeParser::FindFunctionNamespace(cbEditor* editor, wxString* nameSpace, wxString* procName)
{
if (!nameSpace && !procName)
return false;
int posOf = FindCurrentBlockStart(editor);
if (posOf != wxNOT_FOUND)
{
// look for :: right before procname and procargs
// if we find a }, we failed (probably no class member this function)...
bool done = false;
int nest = 0;
bool passedArgs = false;
bool hasNS = false;
while (posOf > 0)
{
--posOf;
char ch = editor->GetControl()->GetCharAt(posOf);
switch (ch)
{
case ')' : --nest; passedArgs = false; break;
case '(' :
++nest;
passedArgs = nest == 0;
if (passedArgs)
{
--posOf;
SkipWhitespaceBackward(editor, posOf);
}
break;
}
if (passedArgs)
{
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
{
int bkp = posOf;
SkipWhitespaceBackward(editor, posOf);
done = true;
hasNS = ch == ':' && editor->GetControl()->GetCharAt(posOf - 1) == ':';
posOf = bkp;
}
}
if (done || ch == '}' || ch == ';')
break;
}
Manager::Get()->GetMessageManager()->DebugLog(_("Pos=%d"), posOf);
if (done)
{
if (procName)
{
int procEnd = editor->GetControl()->WordEndPosition(posOf + 1, true);
*procName = editor->GetControl()->GetTextRange(posOf + 1, procEnd);
}
if (nameSpace && hasNS)
{
nameSpace->Clear();
posOf -= 2;
int scopeStart = editor->GetControl()->WordStartPosition(posOf, true);
*nameSpace = editor->GetControl()->GetTextRange(scopeStart, posOf + 1);
}
Manager::Get()->GetMessageManager()->DebugLog(_("NS: '%s', PROC: '%s'"), nameSpace ? nameSpace->c_str() : _T(""), procName ? procName->c_str() : _T(""));
return true;
}
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Can't find block start."));
return false;
}
// events
void NativeParser::OnThreadStart(wxCommandEvent& event)
{
// nothing for now
}
void NativeParser::OnThreadEnd(wxCommandEvent& event)
{
// nothing for now
}
void NativeParser::OnParserEnd(wxCommandEvent& event)
{
Parser* parser = (Parser*)event.GetClientData();
if (parser)// && parser->Done())
{
cbProject* project = FindProjectFromParser(parser);
if (project)
DisplayStatus(parser, project);
else
Manager::Get()->GetMessageManager()->DebugLog(_("Parser aborted (project closed)."));
if (project == Manager::Get()->GetProjectManager()->GetActiveProject())
{
Manager::Get()->GetMessageManager()->DebugLog(_("Updating class browser..."));
if (m_pClassBrowser)
{
m_pClassBrowser->SetParser(parser);
m_pClassBrowser->Update();
}
Manager::Get()->GetMessageManager()->DebugLog(_("Class browser updated."));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -