Index: src/plugins/codecompletion/coderefactoring.cpp =================================================================== --- src/plugins/codecompletion/coderefactoring.cpp (revision 0) +++ src/plugins/codecompletion/coderefactoring.cpp (revision 0) @@ -0,0 +1,359 @@ +/* + * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3 + * http://www.gnu.org/licenses/gpl-3.0.html + */ + +#include +#include "coderefactoring.h" +#include "nativeparser.h" +#include "cbstyledtextctrl.h" +#include "cbproject.h" +#include "encodingdetector.h" +#include "searchresultslog.h" + +#include + +CodeRefactoring::CodeRefactoring(NativeParser& np) : + m_NativeParser(np) +{ +} + +CodeRefactoring::~CodeRefactoring() +{ +} + +wxString CodeRefactoring::GetSymbolUnderCursor() +{ + EditorManager* edMan = Manager::Get()->GetEditorManager(); + cbEditor* editor = edMan->GetBuiltinActiveEditor(); + if (!editor) + return wxEmptyString; + + if (!m_NativeParser.GetParser()->Done()) + { + cbMessageBox(_("C++ Parser is still parsing files..."), _("Code Refactoring"), wxOK | wxICON_WARNING); + return wxEmptyString; + } + + const int pos = editor->GetControl()->GetCurrentPos(); + const int start = editor->GetControl()->WordStartPosition(pos, true); + const int end = editor->GetControl()->WordEndPosition(pos, true); + return editor->GetControl()->GetTextRange(start, end); +} + +bool CodeRefactoring::Parse() +{ + cbEditor* editor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); + if (!editor) + return false; + + const wxString targetText = GetSymbolUnderCursor(); + if (targetText.IsEmpty()) + return false; + + TokenIdxSet targetResult; + m_NativeParser.MarkItemsByAI(targetResult, m_NativeParser.GetParser()->Options().useSmartSense); + m_NativeParser.RemoveInvalid(targetResult, targetText); + if (targetResult.empty()) + { + cbMessageBox(_("Symbol not found under cursor!"), _("Code Refactoring"), wxOK | wxICON_WARNING); + return false; + } + + cbProject* project = m_NativeParser.GetProjectByFilename(editor->GetFilename()); + const int ret = cbMessageBox(_("Only search open files? Select \"No\" search the project!"), + _("Code Refactoring"), wxYES_NO); + size_t count = SearchInFiles(project, targetText, ret == wxID_YES); + if (count) + count = VerifyResult(project, targetResult, targetText); + + return !!count; +} + +void CodeRefactoring::FindReferences() +{ + if (Parse()) + DoFindReferences(); +} + +void CodeRefactoring::RenameSymbols() +{ + const wxString targetText = GetSymbolUnderCursor(); + if (targetText.Len() < 2) + return; + + wxString replaceText = wxGetTextFromUser(_("Rename symbols under cursor"), + _("Code Refactoring"), + targetText, + Manager::Get()->GetAppWindow()); + if (!replaceText.IsEmpty() && replaceText != targetText && Parse()) + DoRenameSymbols(targetText, replaceText); +} + +size_t CodeRefactoring::SearchInFiles(cbProject* project, const wxString& targetText, bool onlyOpenFiles) +{ + EditorManager* edMan = Manager::Get()->GetEditorManager(); + cbEditor* editor = edMan->GetBuiltinActiveEditor(); + if (!editor) + return 0; + + m_SearchDataMap.clear(); + wxArrayString files; + + if (onlyOpenFiles) + { + for (int i = 0; i < edMan->GetEditorsCount(); ++i) + files.Add(edMan->GetEditor(i)->GetFilename()); + } + else + { + if (!project) + files.Add(editor->GetFilename()); + else + { + // fill the search list with all the project files + for (int i = 0; i < project->GetFilesCount(); ++i) + { + ProjectFile* pf = project->GetFile(i); + FileType ft = CCFileTypeOf(pf->relativeFilename); + if (ft != ftOther) + files.Add(pf->file.GetFullPath()); + } + } + } + + if (files.IsEmpty()) + return 0; + + // now that list is filled, we'll search + cbStyledTextCtrl* control = new cbStyledTextCtrl(editor->GetParent(), wxID_ANY, wxDefaultPosition, wxSize(0, 0)); + control->Show(false); + + // let's create a progress dialog because it might take some time depending on the files count + wxProgressDialog* progress = new wxProgressDialog(_("Code Refactoring"), + _("Please wait while searching inside the project..."), + files.GetCount(), + Manager::Get()->GetAppWindow(), + wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); + PlaceWindow(progress); + + for (size_t i = 0; i < files.GetCount(); ++i) + { + // update the progress bar + if (!progress->Update(i)) + break; // user pressed "Cancel" + + // check if the file is already opened in built-in editor and do search in it + cbEditor* ed = edMan->IsBuiltinOpen(files[i]); + if (ed) + control->SetText(ed->GetControl()->GetText()); + else // else load the file in the control + { + EncodingDetector detector(files[i]); + if (!detector.IsOK()) + continue; // failed + control->SetText(detector.GetWxStr()); + } + + Find(control, files[i], targetText); + } + + delete control; // done with it + delete progress; // done here too + + return m_SearchDataMap.size(); +} + +size_t CodeRefactoring::VerifyResult(cbProject* project, const TokenIdxSet& targetResult, + const wxString& targetText) +{ + EditorManager* edMan = Manager::Get()->GetEditorManager(); + cbEditor* editor = edMan->GetBuiltinActiveEditor(); + if (!editor) + return 0; + + // now that list is filled, we'll search + cbStyledTextCtrl* control = new cbStyledTextCtrl(editor->GetParent(), wxID_ANY, wxDefaultPosition, wxSize(0, 0)); + control->Show(false); + + size_t totalCount = 0; + for (SearchDataMap::iterator it = m_SearchDataMap.begin(); it != m_SearchDataMap.end(); ++it) + totalCount += it->second.size(); + + // let's create a progress dialog because it might take some time depending on the files count + wxProgressDialog* progress = new wxProgressDialog(_("Code Refactoring"), + _("Please wait while verifying result..."), + totalCount, + Manager::Get()->GetAppWindow(), + wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); + PlaceWindow(progress); + + size_t task = totalCount; + TokenIdxSet result; + bool userBreak = false; + for (SearchDataMap::iterator it = m_SearchDataMap.begin(); it != m_SearchDataMap.end();) + { + // check if the file is already opened in built-in editor and do search in it + cbEditor* ed = edMan->IsBuiltinOpen(it->first); + if (ed) + control->SetText(ed->GetControl()->GetText()); + else // else load the file in the control + { + EncodingDetector detector(it->first); + if (!detector.IsOK()) + { + task -= it->second.size(); + continue; // failed + } + control->SetText(detector.GetWxStr()); + } + + ccSearchData searchData = { control, it->first }; + + for (SearchDataList::iterator itList = it->second.begin(); itList != it->second.end();) + { + // update the progress bar + if (!progress->Update(totalCount - (--task))) + { + userBreak = true; + break; // user pressed "Cancel" + } + + // e.g. void |Test(... + // we *must* goto pos as "void T|est(..." + control->GotoPos(itList->pos + 1); + + m_NativeParser.MarkItemsByAI(&searchData, result, m_NativeParser.GetParser()->Options().useSmartSense); + m_NativeParser.RemoveInvalid(result, targetText); + + TokenIdxSet::iterator intersect = std::find_first_of(targetResult.begin(), targetResult.end(), + result.begin(), result.end()); + if (intersect == targetResult.end()) + it->second.erase(itList++); + else + ++itList; + } + + if (it->second.empty()) + m_SearchDataMap.erase(it++); + else + ++it; + + if (userBreak) + break; + } + + delete control; // done with it + delete progress; // done here too + + return m_SearchDataMap.size(); +} + +void CodeRefactoring::Find(cbStyledTextCtrl* control, const wxString& file, const wxString& target) +{ + const int end = control->GetLength(); + int start = 0; + int pos = 0; + + for (;;) + { + int lengthFound; + pos = control->FindText(start, end, target, wxSCI_FIND_WHOLEWORD | wxSCI_FIND_MATCHCASE, &lengthFound); + if (pos != wxSCI_INVALID_POSITION) + { + start = pos + lengthFound; + + // TODO (Loaden) not work? + const int style = control->GetStyleAt(pos); // always been zero? + if (control->IsString(style) || control->IsComment(style)) + continue; + + int line = control->LineFromPosition(pos); + wxString text = control->GetLine(line).Trim(true).Trim(false); + m_SearchDataMap[file].push_back(crSearchData(pos, line, text)); + } + else + break; + } +} + +void CodeRefactoring::DoFindReferences() +{ + cbEditor* editor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); + if (!editor) + return; + + SearchResultsLog* searchLog = Manager::Get()->GetEditorManager()->GetSearchResultLogger(); + + const wxString focusFile = editor->GetFilename(); + const int focusLine = editor->GetControl()->GetCurrentLine(); + wxFileName fn(focusFile); + const wxString basePath(fn.GetPath()); + size_t index = 0; + size_t focusIndex = 0; + + searchLog->Clear(); + searchLog->SetBasePath(basePath); + + for (SearchDataMap::iterator it = m_SearchDataMap.begin(); it != m_SearchDataMap.end(); ++it) + { + for (SearchDataList::iterator itList = it->second.begin(); itList != it->second.end(); ++itList) + { + if (it->first == focusFile && itList->line == focusLine) + focusIndex = index; + + wxArrayString values; + wxFileName curFn(it->first); + curFn.MakeRelativeTo(basePath); + values.Add(curFn.GetFullPath()); + values.Add(wxString::Format(_T("%d"), itList->line + 1)); + values.Add(itList->text); + searchLog->Append(values, Logger::info); + + ++index; + } + } + + if (Manager::Get()->GetConfigManager(_T("message_manager"))->ReadBool(_T("/auto_show_search"), true)) + { + CodeBlocksLogEvent evtSwitch(cbEVT_SWITCH_TO_LOG_WINDOW, searchLog); + CodeBlocksLogEvent evtShow(cbEVT_SHOW_LOG_MANAGER); + Manager::Get()->ProcessEvent(evtSwitch); + Manager::Get()->ProcessEvent(evtShow); + } + + searchLog->FocusEntry(focusIndex); +} + +void CodeRefactoring::DoRenameSymbols(const wxString& targetText, const wxString& replaceText) +{ + EditorManager* edMan = Manager::Get()->GetEditorManager(); + cbEditor* editor = edMan->GetBuiltinActiveEditor(); + if (!editor) + return; + + cbProject* project = m_NativeParser.GetProjectByFilename(editor->GetFilename()); + + for (SearchDataMap::iterator it = m_SearchDataMap.begin(); it != m_SearchDataMap.end(); ++it) + { + // check if the file is already opened in built-in editor and do search in it + cbEditor* ed = edMan->IsBuiltinOpen(it->first); + if (!ed) + { + ProjectFile* pf = project ? project->GetFileByFilename(it->first) : 0; + ed = edMan->Open(it->first, it->second.front().pos, pf); + } + + cbStyledTextCtrl* control = ed->GetControl(); + control->BeginUndoAction(); + + for (SearchDataList::reverse_iterator rIter = it->second.rbegin(); rIter != it->second.rend(); ++rIter) + { + control->SetTargetStart(rIter->pos); + control->SetTargetEnd(rIter->pos + targetText.Len()); + control->ReplaceTarget(replaceText); + } + + control->EndUndoAction(); + } +} Index: src/plugins/codecompletion/coderefactoring.h =================================================================== --- src/plugins/codecompletion/coderefactoring.h (revision 0) +++ src/plugins/codecompletion/coderefactoring.h (revision 0) @@ -0,0 +1,52 @@ +/* + * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3 + * http://www.gnu.org/licenses/gpl-3.0.html + */ + +#ifndef CODEREFACTORING_H +#define CODEREFACTORING_H + +#include "nativeparser.h" + +struct crSearchData +{ + int pos; + int line; + const wxString text; + crSearchData(int pos, int line, const wxString& text) : + pos(pos), + line(line), + text(text) + {} +}; + +class CodeRefactoring +{ + typedef std::list SearchDataList; + typedef std::map SearchDataMap; + +public: + CodeRefactoring(NativeParser& np); + virtual ~CodeRefactoring(); + + void FindReferences(); + void RenameSymbols(); + +private: + size_t SearchInFiles(cbProject* project, const wxString& targetText, bool onlyOpenFiles); + size_t VerifyResult(cbProject* project, const TokenIdxSet& targetResult, const wxString& targetText); + void Find(cbStyledTextCtrl* control, const wxString& file, const wxString& target); + wxString GetSymbolUnderCursor(); + + void DoFindReferences(); + void DoRenameSymbols(const wxString& targetText, const wxString& replaceText); + +private: + bool Parse(); + +private: + NativeParser& m_NativeParser; + SearchDataMap m_SearchDataMap; +}; + +#endif // CODEREFACTORING_H Index: src/plugins/codecompletion/nativeparser.cpp =================================================================== --- src/plugins/codecompletion/nativeparser.cpp (revision 6574) +++ src/plugins/codecompletion/nativeparser.cpp (working copy) @@ -216,20 +216,28 @@ if (activeProject) { Parser* parser = GetParserByProject(activeProject); - if ((parser && parser->IsFileParsed(filename)) || activeProject->GetFileByFilename(filename, false, true)) + if ( ( parser + && parser->IsFileParsed(filename) ) + || activeProject->GetFileByFilename(filename, false, true) ) + { return activeProject; + } else { - ProjectsArray* projArr = Manager::Get()->GetProjectManager()->GetProjects(); - for (size_t i = 0; i < projArr->GetCount(); ++i) + ProjectsArray* projs = Manager::Get()->GetProjectManager()->GetProjects(); + for (size_t i = 0; i < projs->GetCount(); ++i) { - cbProject* project = projArr->Item(i); + cbProject* project = projs->Item(i); if (!project || project == activeProject) continue; parser = GetParserByProject(project); - if ((parser && parser->IsFileParsed(filename)) || project->GetFileByFilename(filename, false, true)) + if ( ( parser + && parser->IsFileParsed(filename) ) + || project->GetFileByFilename(filename, false, true) ) + { return project; + } } } } @@ -505,7 +513,7 @@ _("Reparse?"), wxYES_NO | wxICON_QUESTION) == wxID_YES) { ClearParsers(); - ForceReparseActiveProject(); + ReparseCurrentProject(); return; } } @@ -654,7 +662,8 @@ TRACE(_T("AddCompilerDirs() : Adding compiler dir to parser: ") + dir.GetFullPath()); } else - Manager::Get()->GetLogManager()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), out.wx_str(), base.wx_str())); + Manager::Get()->GetLogManager()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), + out.wx_str(), base.wx_str())); } // find out which compiler, if gnu, do the special trick @@ -727,8 +736,10 @@ if (compilerId == _T("gcc")) { static wxString gccDefs; - if (gccDefs.IsEmpty()) + static bool firstExecute = true; + if (firstExecute) { + firstExecute = false; #ifdef __WXMSW__ wxString cmd(_T("cpp -dM -E nul")); #else @@ -779,8 +790,10 @@ else if (compilerId.StartsWith(_T("msvc"))) { static wxString vcDefs; - if (vcDefs.IsEmpty()) + static bool firstExecute = true; + if (firstExecute) { + firstExecute = false; Compiler* compiler = CompilerFactory::GetCompiler(compilerId); wxString cmd = compiler->GetMasterPath() + _T("\\bin\\") + compiler->GetPrograms().C; Manager::Get()->GetMacrosManager()->ReplaceMacros(cmd); @@ -874,8 +887,11 @@ // keep the gcc compiler path's once if found accross C::B session // makes opening workspaces a *lot* faster by avoiding endless calls to the compiler static wxArrayString gcc_compiler_dirs; - if (!gcc_compiler_dirs.IsEmpty()) + static bool firstExecute = true; + if (!firstExecute) return gcc_compiler_dirs; + else + firstExecute = false; // for starters , only do this for gnu compiler //Manager::Get()->GetLogManager()->DebugLog(_T("CompilerID ") + CompilerID); @@ -945,6 +961,12 @@ return false; } + if (project && project->GetFilesCount() == 0) + { + Manager::Get()->GetLogManager()->DebugLog(_T("Can not parsing empty project!")); + return false; + } + Parser* parser = new(std::nothrow) Parser(this); if (!parser) { @@ -1001,7 +1023,7 @@ bool NativeParser::SwitchParser(cbProject* project, Parser* parser) { - if (parser == m_pParser || GetParserByProject(project) != parser) + if (!parser || parser == m_pParser || GetParserByProject(project) != parser) return false; SetParser(parser); @@ -1015,6 +1037,9 @@ bool NativeParser::ReparseFile(cbProject* project, const wxString& filename) { + if (CCFileTypeOf(filename) == ftOther) + return false; + Parser* parser = GetParserByProject(project); if (!parser) return false; @@ -1024,6 +1049,9 @@ bool NativeParser::AddFileToParser(cbProject* project, const wxString& filename) { + if (CCFileTypeOf(filename) == ftOther) + return false; + Parser* parser = GetParserByProject(project); if (!parser) return false; @@ -1064,8 +1092,8 @@ if (NormalizePath(dir, base)) parser->AddIncludeDir(dir.GetFullPath()); else - Manager::Get()->GetLogManager()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), path.wx_str(), base.wx_str())); - + Manager::Get()->GetLogManager()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), + path.wx_str(), base.wx_str())); } wxArrayString fronts; @@ -1123,7 +1151,7 @@ token = token.SubString(1, token.Len() - 2).Trim(false).Trim(true); wxArrayString finds = parser->FindFileInIncludeDirs(token); for (size_t i = 0; i < finds.GetCount(); ++i) - frontMap[++frontCnt] = finds[i]; + frontMap[++frontCnt] = finds[i] + _T(", 1"); } } @@ -1131,7 +1159,7 @@ for (int i = 0; i < project->GetFilesCount(); ++i) { ProjectFile* pf = project->GetFile(i); - FileType ft = FileTypeOf(pf->relativeFilename); + FileType ft = CCFileTypeOf(pf->relativeFilename); if (ft == ftHeader) // parse header files { bool isUpFrontFile = false; @@ -1140,7 +1168,7 @@ if (it->second.IsSameAs(pf->file.GetFullName(), false)) { isUpFrontFile = true; - frontMap[it->first] = pf->file.GetFullPath(); + frontMap[it->first] = pf->file.GetFullPath() + _T(", 0"); frontTempMap.erase(it); break; } @@ -1167,15 +1195,24 @@ if (!fronts.IsEmpty()) { for (size_t i = 0; i < fronts.GetCount(); ++i) - Manager::Get()->GetLogManager()->DebugLog(F(_T("Header to parse up-front: '%s'"), fronts[i].wx_str())); + { + const bool systemHeaderFile = (fronts[i].Last() == _T('1')); + const int pos = fronts[i].Find(_T(','), true); + wxString file = fronts[i].SubString(0, pos - 1); + Manager::Get()->GetLogManager()->DebugLog(F(_T("Header to parse up-front: '%s'"), + file.wx_str())); + parser->AddUpFrontHeaders(file, systemHeaderFile); + } - Manager::Get()->GetLogManager()->DebugLog(F(_T("Add up-front parsing %d file(s) for project '%s'..."), fronts.GetCount(), project->GetTitle().wx_str())); - parser->AddBatchParse(fronts, true); + Manager::Get()->GetLogManager()->DebugLog(F(_T("Add up-front parsing %d file(s) for project '%s'..."), + fronts.GetCount(), project->GetTitle().wx_str())); } if (!headers.IsEmpty() || !sources.IsEmpty()) { - Manager::Get()->GetLogManager()->DebugLog(F(_T("Add batch-parsing %d file(s) for project '%s'..."), headers.GetCount() + sources.GetCount(), project->GetTitle().wx_str())); + Manager::Get()->GetLogManager()->DebugLog(F(_T("Add batch-parsing %d file(s) for project '%s'..."), + headers.GetCount() + sources.GetCount(), + project->GetTitle().wx_str())); parser->AddBatchParse(headers); parser->AddBatchParse(sources); } @@ -1184,16 +1221,41 @@ parser->StartParsing(); } -void NativeParser::ForceReparseActiveProject() +void NativeParser::ReparseCurrentProject() { - cbProject* curProject = Manager::Get()->GetProjectManager()->GetActiveProject(); - if (curProject) + cbProject* project = GetProjectByParser(m_pParser); + if (project) { - DeleteParser(curProject); - CreateParser(curProject); + DeleteParser(project); + CreateParser(project); } } +void NativeParser::ReparseSelectedProject() +{ + wxTreeCtrl* tree = Manager::Get()->GetProjectManager()->GetTree(); + if (!tree) + return; + + wxTreeItemId treeItem = tree->GetSelection(); + if (!treeItem.IsOk()) + return; + + const FileTreeData* data = static_cast(tree->GetItemData(treeItem)); + if (!data) + return; + + if (data->GetKind() == FileTreeData::ftdkProject) + { + cbProject* project = data->GetProject(); + if (project) + { + DeleteParser(project); + CreateParser(project); + } + } +} + // UNUSED bool NativeParser::LoadCachedData(cbProject* project) { @@ -1259,16 +1321,13 @@ return result; } -bool NativeParser::ParseFunctionArguments(cbEditor* ed, int caretPos) +bool NativeParser::ParseFunctionArguments(ccSearchData* searchData, int caretPos) { - if (!ed || !m_pParser->Done()) - return false; - if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(_T("ParseFunctionArguments() Parse function arguments")); TokenIdxSet proc_result; - if (FindCurrentFunctionToken(ed, proc_result, caretPos) != 0) + if (FindCurrentFunctionToken(searchData, proc_result, caretPos) != 0) { for (TokenIdxSet::iterator it = proc_result.begin(); it != proc_result.end(); ++it) { @@ -1314,30 +1373,27 @@ return false; } -bool NativeParser::ParseLocalBlock(cbEditor* ed, int caretPos) +bool NativeParser::ParseLocalBlock(ccSearchData* searchData, int caretPos) { - if (!ed || !m_pParser->Done()) - return false; - if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(_T("ParseLocalBlock() Parse local block")); - int blockStart = FindCurrentFunctionStart(ed, 0, 0, caretPos); + int blockStart = FindCurrentFunctionStart(searchData, 0, 0, caretPos); if (blockStart != -1) { ++blockStart; // skip { - int blockEnd = caretPos == -1 ? ed->GetControl()->GetCurrentPos() : caretPos; - if (blockEnd < 0 || blockEnd > ed->GetControl()->GetLength()) + int blockEnd = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos; + if (blockEnd < 0 || blockEnd > searchData->control->GetLength()) { if (s_DebugSmartSense) - Manager::Get()->GetLogManager()->DebugLog(F(_T("ParseLocalBlock() ERROR blockEnd=%d and edLength=%d?!"), blockEnd, ed->GetControl()->GetLength())); + Manager::Get()->GetLogManager()->DebugLog(F(_T("ParseLocalBlock() ERROR blockEnd=%d and edLength=%d?!"), blockEnd, searchData->control->GetLength())); return false; } if (blockStart >= blockEnd) blockStart = blockEnd; - wxString buffer = ed->GetControl()->GetTextRange(blockStart, blockEnd); + wxString buffer = searchData->control->GetTextRange(blockStart, blockEnd); buffer.Trim(); if (!buffer.IsEmpty() && !m_pParser->ParseBuffer(buffer, false, false, true)) { @@ -1372,23 +1428,20 @@ return false; } -bool NativeParser::ParseUsingNamespace(cbEditor* ed, TokenIdxSet& search_scope, int caretPos) +bool NativeParser::ParseUsingNamespace(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos) { - if (!ed) - return false; - TokensTree* tree = m_pParser->GetTokens(); if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(_T("ParseUsingNamespace() Parse file scope for \"using namespace\"")); wxArrayString ns; - int pos = caretPos == -1 ? ed->GetControl()->GetCurrentPos() : caretPos; - if (pos < 0 || pos > ed->GetControl()->GetLength()) + int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos; + if (pos < 0 || pos > searchData->control->GetLength()) return false; // Get the buffer from begin of the editor to the current caret position - wxString buffer = ed->GetControl()->GetTextRange(0, pos); + wxString buffer = searchData->control->GetTextRange(0, pos); m_pParser->ParseBufferForUsingNamespace(buffer, ns); for (size_t i = 0; i < ns.GetCount(); ++i) @@ -1422,22 +1475,33 @@ return true; } +size_t NativeParser::MarkItemsByAI(TokenIdxSet& result, bool reallyUseAI, bool isPrefix, bool caseSensitive, int caretPos) +{ + if (s_DebugSmartSense) + Manager::Get()->GetLogManager()->DebugLog(F(_T("MarkItemsByAI()"))); + + cbEditor* editor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); + if (!editor) + return 0; + + ccSearchData searchData = { editor->GetControl(), editor->GetFilename() }; + + return MarkItemsByAI(&searchData, result, reallyUseAI, isPrefix, caseSensitive, caretPos); +} + // Here, we collect the "using namespace XXXX" directives // Also, we locate the current caret in which function, then, add the function parameters to Token trie // Also, the variables in the function body( local block ) was add to the Token trie -size_t NativeParser::MarkItemsByAI(TokenIdxSet& result, bool reallyUseAI, bool fullMatch, bool caseSensitive, int caretPos) +size_t NativeParser::MarkItemsByAI(ccSearchData* searchData, TokenIdxSet& result, bool reallyUseAI, bool isPrefix, + bool caseSensitive, int caretPos) { - if (s_DebugSmartSense) - Manager::Get()->GetLogManager()->DebugLog(F(_T("MarkItemsByAI()"))); - result.clear(); - cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); - if (!ed) - return 0; - if (!m_pParser->Done()) + { Manager::Get()->GetLogManager()->DebugLog(_T("C++ Parser is still parsing files...")); + return 0; + } else { // remove old temporaries @@ -1446,13 +1510,13 @@ // find "using namespace" directives in the file TokenIdxSet search_scope; - ParseUsingNamespace(ed, search_scope, caretPos); + ParseUsingNamespace(searchData, search_scope, caretPos); // parse function's arguments - ParseFunctionArguments(ed, caretPos); + ParseFunctionArguments(searchData, caretPos); // parse current code block (from the start of function up to the cursor) - ParseLocalBlock(ed, caretPos); + ParseLocalBlock(searchData, caretPos); if (!reallyUseAI) { @@ -1462,12 +1526,25 @@ result.insert(i); return result.size(); } + // we have correctly collected all the tokens, so we will do the artificial intelligence search - return AI(result, ed, wxEmptyString, fullMatch, caseSensitive, &search_scope, caretPos); + return AI(result, searchData, wxEmptyString, isPrefix, caseSensitive, &search_scope, caretPos); } - return 0; } +void NativeParser::RemoveInvalid(TokenIdxSet& result, const wxString& target) +{ + TokensTree* tokens = m_pParser->GetTokens(); + for (TokenIdxSet::iterator it = result.begin(); it != result.end();) + { + Token* tk = tokens->at(*it); + if (!tk || tk->m_Name != target) + result.erase(it++); + else + ++it; + } +} + const wxString& NativeParser::GetCodeCompletionItems() { m_CCItems.Clear(); @@ -1558,16 +1635,18 @@ m_CallTips.Clear(); int end = 0; int commas = 0; - wxString lineText = _T(""); + wxString lineText; cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); do { if (!ed || !m_pParser->Done()) break; - int line = ed->GetControl()->GetCurrentLine(); - lineText = ed->GetControl()->GetLine(line); - end = ed->GetControl()->GetCurrentPos() - ed->GetControl()->PositionFromLine(line); + ccSearchData searchData = { ed->GetControl(), ed->GetFilename() }; + + int line = searchData.control->GetCurrentLine(); + lineText = searchData.control->GetLine(line); + end = searchData.control->GetCurrentPos() - ed->GetControl()->PositionFromLine(line); int nest = 0; while (end > 0) { @@ -1596,9 +1675,9 @@ tokens->FreeTemporaries(); TokenIdxSet search_scope; - ParseUsingNamespace(ed, search_scope); - ParseFunctionArguments(ed); - ParseLocalBlock(ed); + ParseUsingNamespace(&searchData, search_scope); + ParseFunctionArguments(&searchData); + ParseLocalBlock(&searchData); m_GettingCalltips = true; @@ -1607,7 +1686,7 @@ lineText = tk->m_Type; TokenIdxSet result; - if (!AI(result, ed, lineText, true, true, &search_scope)) + if (!AI(result, &searchData, lineText, true, true, &search_scope)) break; for (TokenIdxSet::iterator it = result.begin(); it != result.end(); ++it) @@ -1982,9 +2061,9 @@ // Start an Artificial Intelligence (!) sequence to gather all the matching tokens.. // The actual AI is in FindAIMatches() below... size_t NativeParser::AI(TokenIdxSet& result, - cbEditor* editor, + ccSearchData* searchData, const wxString& lineText, - bool fullMatch, + bool isPrefix, bool caseSensitive, TokenIdxSet* search_scope, int caretPos) @@ -1992,23 +2071,23 @@ m_LastAISearchWasGlobal = false; m_LastAIGlobalSearch.Clear(); - int pos = caretPos == -1 ? editor->GetControl()->GetCurrentPos() : caretPos; - if (pos < 0 || pos > editor->GetControl()->GetLength()) + int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos; + if (pos < 0 || pos > searchData->control->GetLength()) return 0; - m_EditorStartWord = editor->GetControl()->WordStartPosition(pos, true); + m_EditorStartWord = searchData->control->WordStartPosition(pos, true); m_EditorEndWord = pos; //editor->GetControl()->WordEndPosition(pos, true); - int line = editor->GetControl()->LineFromPosition(pos); + int line = searchData->control->LineFromPosition(pos); // Get the actual search text, such as "objA.m_aaa.m_bbb" wxString actual_search; int col; wxString tabwidth; - tabwidth.Pad(editor->GetControl()->GetTabWidth(), ' '); + tabwidth.Pad(searchData->control->GetTabWidth(), ' '); if (lineText.IsEmpty()) { - actual_search = editor->GetControl()->GetLine(line); - col = editor->GetControl()->GetColumn(pos); + actual_search = searchData->control->GetLine(line); + col = searchData->control->GetColumn(pos); // replace tabs in line by equal-count spaces because col is in spaces! actual_search.Replace(_T("\t"), tabwidth); actual_search.Remove(col); @@ -2020,37 +2099,6 @@ col = actual_search.Length() - 1; } - if (s_DebugSmartSense) - Manager::Get()->GetLogManager()->DebugLog(F(_T("AI() AI enter, actual_search: \"%s\""), actual_search.wx_str())); - - static ProjectFile* cached_project = 0; - static cbEditor* cached_editor = 0; - static int cached_editor_start_word = 0; - static wxString cached_search; - static size_t cached_results_count = 0; - - // early-out opportunity - // if the user starts typing a token that in our last search had 0 results, - // and we see that he's continuing typing for that same token, - // don't even bother to search - if ( cached_project == editor->GetProjectFile() - && cached_editor == editor - && cached_editor_start_word == m_EditorStartWord - && cached_results_count == 0 - && actual_search.StartsWith(cached_search) ) - { - if (s_DebugSmartSense) - Manager::Get()->GetLogManager()->DebugLog(_T("AI() AI leave, Aborting search: last attempt returned 0 results")); - - // but set m_LastAISearchWasGlobal correctly so C++ keywords can be shown - std::queue components; - BreakUpComponents(actual_search, components); - m_LastAISearchWasGlobal = components.size() <= 1; - if (!components.empty()) - m_LastAIGlobalSearch = components.front().component; - return 0; - } - // Do the whole job here if (s_DebugSmartSense) { @@ -2062,7 +2110,7 @@ // we ' ll get the function's token (all matches) and add its parent namespace TokenIdxSet scope_result; TokenIdxSet proc_result; - if (FindCurrentFunctionToken(editor, proc_result) != 0) + if (FindCurrentFunctionToken(searchData, proc_result) != 0) { for (TokenIdxSet::iterator it = proc_result.begin(); it != proc_result.end(); ++it) { @@ -2123,15 +2171,8 @@ if (!components.empty()) m_LastAIGlobalSearch = components.front().component; - ResolveExpression(components, *search_scope, result, caseSensitive, fullMatch); + ResolveExpression(components, *search_scope, result, caseSensitive, isPrefix); - cached_editor = editor; - if (result.size() || (m_EditorEndWord - m_EditorStartWord)) - cached_editor_start_word = m_EditorStartWord; - - cached_search = actual_search; - cached_results_count = result.size(); - if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(F(_T("AI() AI leave, returned %d results"),result.size())); @@ -2216,7 +2257,7 @@ size_t NativeParser::FindAIMatches(std::queue components, TokenIdxSet& result, int parentTokenIdx, - bool fullMatch, + bool isPrefix, bool caseSensitive, bool use_inheritance, short int kindMask, @@ -2240,7 +2281,7 @@ // this will make the AI behave like it's the previous scope (or the current if no previous scope) // move on please, nothing to see here... - return FindAIMatches(components, result, parentTokenIdx, fullMatch, caseSensitive, use_inheritance, kindMask, search_scope); + return FindAIMatches(components, result, parentTokenIdx, isPrefix, caseSensitive, use_inheritance, kindMask, search_scope); } // we 'll only add tokens in the result set if we get matches for the last token @@ -2256,7 +2297,7 @@ TokenIdxSet local_result; GenerateResultSet(tree, searchtext, parentTokenIdx, local_result, (caseSensitive || !isLastComponent), - (isLastComponent && !fullMatch), kindMask); + (isLastComponent && !isPrefix), kindMask); if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(F(_T("FindAIMatches() Looping %d results"), local_result.size())); @@ -2383,7 +2424,7 @@ while (it != type_result.end()) { std::queue lcomp = components; - FindAIMatches(lcomp, result, *it, fullMatch, caseSensitive, use_inheritance, kindMask, search_scope); + FindAIMatches(lcomp, result, *it, isPrefix, caseSensitive, use_inheritance, kindMask, search_scope); ++it; } } @@ -2406,7 +2447,7 @@ result.insert(id); // else recurse this function using id as a parent else - FindAIMatches(components, result, id, fullMatch, caseSensitive, use_inheritance, kindMask, search_scope); + FindAIMatches(components, result, id, isPrefix, caseSensitive, use_inheritance, kindMask, search_scope); } if (s_DebugSmartSense) @@ -2592,7 +2633,8 @@ return (result.size()>0 ? result.size() : 0); } -size_t NativeParser::ResolveExpression(std::queue components, const TokenIdxSet& searchScope, TokenIdxSet& result, bool isCaseSense, bool IsPrefix) +size_t NativeParser::ResolveExpression(std::queue components, const TokenIdxSet& searchScope, + TokenIdxSet& result, bool caseSense, bool isPrefix) { m_TemplateMap.clear(); static ParserComponent lastComponent; @@ -2641,7 +2683,7 @@ Manager::Get()->GetLogManager()->DebugLog(F(_T("search scope: %d"), (*tt))); } - GenerateResultSet(searchText, initialScope, initialResult, (isCaseSense || !isLastComponent), (!IsPrefix && isLastComponent)); + GenerateResultSet(searchText, initialScope, initialResult, (caseSense || !isLastComponent), (!isPrefix && isLastComponent)); // now we should clear the initialScope. initialScope.clear(); @@ -2936,37 +2978,29 @@ } // returns current function's position (not line) in the editor -int NativeParser::FindCurrentFunctionStart(cbEditor* editor, wxString* nameSpace, wxString* procName, int caretPos) +int NativeParser::FindCurrentFunctionStart(ccSearchData* searchData, wxString* nameSpace, wxString* procName, int caretPos) { - cbStyledTextCtrl* control = editor->GetControl(); - if (!control) - { - if (s_DebugSmartSense) - Manager::Get()->GetLogManager()->DebugLog(_T("FindCurrentFunctionStart() Cannot access control.")); - return -1; - } + static cbStyledTextCtrl* s_LastControl = 0; + static int s_LastLine = -1; + static int s_LastResult = -1; + static wxString s_LastFile; + static wxString s_LastNS; + static wxString s_LastPROC; - static ProjectFile* s_LastProject = 0; - static cbEditor* s_LastEditor = 0; - static int s_LastLine = -1; - static int s_LastResult = -1; - static wxString s_LastNS; - static wxString s_LastPROC; - // cache last result for optimization - int pos = caretPos == -1 ? control->GetCurrentPos() : caretPos; - if ((pos < 0) || (pos > control->GetLength())) + int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos; + if ((pos < 0) || (pos > searchData->control->GetLength())) { if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(F(_T("FindCurrentFunctionStart() Cannot determine position. caretPos=%d, control=%d"), - caretPos, control->GetCurrentPos())); + caretPos, searchData->control->GetCurrentPos())); return -1; } - int line = control->LineFromPosition(pos) + 1; + int line = searchData->control->LineFromPosition(pos) + 1; if ( (line == s_LastLine) - && ( (editor == s_LastEditor) && (!editor->GetModified()) ) - && (editor->GetProjectFile()==s_LastProject) ) + && ( (searchData->control == s_LastControl) && (!searchData->control->GetModify()) ) + && (searchData->file == s_LastFile) ) { if (nameSpace) *nameSpace = s_LastNS; if (procName) *procName = s_LastPROC; @@ -2980,20 +3014,20 @@ if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(F(_T("FindCurrentFunctionStart() Looking for tokens in '%s'"), - editor->GetFilename().wx_str())); - s_LastProject = editor->GetProjectFile(); - s_LastEditor = editor; + searchData->file.wx_str())); + s_LastFile = searchData->file; + s_LastControl = searchData->control; s_LastLine = line; // we have all the tokens in the current file, then just do a loop on all the tokens, see if the line is in // the token's imp. TokenIdxSet result; - size_t num_results = m_pParser->FindTokensInFile(editor->GetFilename(), result, tkAnyFunction | tkClass); + size_t num_results = m_pParser->FindTokensInFile(searchData->file, result, tkAnyFunction | tkClass); if (s_DebugSmartSense) Manager::Get()->GetLogManager()->DebugLog(F(_T("FindCurrentFunctionStart() Found %d results"), num_results)); TokensTree* tree = m_pParser->GetTokens(); - const size_t currentFileIndex = tree->GetFileIndex(editor->GetFilename()); + const size_t currentFileIndex = tree->GetFileIndex(searchData->file); for (TokenIdxSet::iterator it = result.begin(); it != result.end(); ++it) { if (s_DebugSmartSense) @@ -3020,14 +3054,14 @@ s_LastNS = token->GetNamespace(); s_LastPROC = token->m_Name; - s_LastResult = control->PositionFromLine(token->m_ImplLine - 1); + s_LastResult = searchData->control->PositionFromLine(token->m_ImplLine - 1); // locate function's opening brace if(token->m_TokenKind & tkAnyFunction) { - while (s_LastResult < control->GetTextLength()) + while (s_LastResult < searchData->control->GetTextLength()) { - wxChar ch = control->GetCharAt(s_LastResult); + wxChar ch = searchData->control->GetCharAt(s_LastResult); if (ch == _T('{')) break; else if (ch == 0) @@ -3065,15 +3099,12 @@ // find a function where current caret located. // We need to find extra class scope, otherwise, we will failed do the cc in a class declaration // -size_t NativeParser::FindCurrentFunctionToken(cbEditor* editor, TokenIdxSet& result, int caretPos) +size_t NativeParser::FindCurrentFunctionToken(ccSearchData* searchData, TokenIdxSet& result, int caretPos) { - if (!editor || !m_pParser->Done()) - return 0; - TokenIdxSet scope_result; wxString procName; wxString scopeName; - FindCurrentFunctionStart(editor, &scopeName, &procName, caretPos); + FindCurrentFunctionStart(searchData, &scopeName, &procName, caretPos); if (procName.IsEmpty()) return 0; @@ -3222,9 +3253,8 @@ for (int i = 0; i < project->GetFilesCount(); ++i) { ProjectFile* pf = project->GetFile(i); - if (!pf) - continue; - parser->MarkFileTokensAsLocal(pf->file.GetFullPath(), true, project); + if (CCFileTypeOf(pf->relativeFilename) != ftOther) + parser->MarkFileTokensAsLocal(pf->file.GetFullPath(), true, project); } } @@ -3265,7 +3295,8 @@ Parser* parser = GetParserByProject(project); if (!parser) { - if (CreateParser(project)) + FileType ft = CCFileTypeOf(m_LastActivatedFile); + if (ft != ftOther && CreateParser(project)) { parser = GetParserByProject(project); if (!project) @@ -3377,8 +3408,7 @@ virtual wxDirTraverseResult OnFile(const wxString& filename) { - wxString ext = filename.AfterLast(_T('.')).Lower(); - if (ext.StartsWith(_T("h")) || ext.StartsWith(_T("c")) || ext.IsEmpty()) + if (CCFileTypeOf(filename) != ftOther) m_Files.Add(filename); return wxDIR_CONTINUE; } @@ -3458,7 +3488,6 @@ return dirs; } - void NativeParser::AddPaths(wxArrayString& dirs, const wxString& path, bool hasExt) { wxString s; @@ -3491,6 +3520,7 @@ } } } + void NativeParser::AddTemplateAlias(const int& id, const TokenIdxSet& actualTypeScope, TokenIdxSet& initialScope, TokensTree* tree) { if (!tree) @@ -3516,6 +3546,7 @@ } } } + void NativeParser::ResolveTemplateMap(const wxString& searchStr, const TokenIdxSet& actualTypeScope, TokenIdxSet& initialScope) { if (actualTypeScope.empty()) @@ -3534,6 +3565,7 @@ } } } + void NativeParser::ResolveOpeartor(const OperatorType& tokenOperatorType, const TokenIdxSet& tokens, TokensTree* tree, const TokenIdxSet& searchScope, TokenIdxSet& result) { TokenIdxSet opInitialScope; Index: src/plugins/codecompletion/codecompletion.cpp =================================================================== --- src/plugins/codecompletion/codecompletion.cpp (revision 6574) +++ src/plugins/codecompletion/codecompletion.cpp (working copy) @@ -122,8 +122,12 @@ int idMenuGotoDeclaration = wxNewId(); int idMenuGotoImplementation = wxNewId(); int idMenuOpenIncludeFile = wxNewId(); +int idMenuFindReferences = wxNewId(); +int idMenuRenameSymbols = wxNewId(); int idViewClassBrowser = wxNewId(); -int idProjectReparse = wxNewId(); +int idCurrentProjectReparse = wxNewId(); +int idSelectedProjectReparse = wxNewId(); +int idSelectedFileReparse = wxNewId(); int idEditorSubMenu = wxNewId(); int idClassMethod = wxNewId(); int idUnimplementedClassMethods = wxNewId(); @@ -145,7 +149,7 @@ #define EDITOR_AND_LINE_INTERVAL 150 BEGIN_EVENT_TABLE(CodeCompletion, cbCodeCompletionPlugin) - EVT_UPDATE_UI_RANGE(idMenuCodeComplete, idProjectReparse, CodeCompletion::OnUpdateUI) + EVT_UPDATE_UI_RANGE(idMenuCodeComplete, idCurrentProjectReparse, CodeCompletion::OnUpdateUI) EVT_MENU(idMenuCodeComplete, CodeCompletion::OnCodeComplete) EVT_MENU(idMenuShowCallTip, CodeCompletion::OnShowCallTip) @@ -154,6 +158,8 @@ EVT_MENU(idMenuGotoNextFunction, CodeCompletion::OnGotoNextFunction) EVT_MENU(idMenuGotoDeclaration, CodeCompletion::OnGotoDeclaration) EVT_MENU(idMenuGotoImplementation, CodeCompletion::OnGotoDeclaration) + EVT_MENU(idMenuFindReferences, CodeCompletion::OnFindReferences) + EVT_MENU(idMenuRenameSymbols, CodeCompletion::OnRenameSymbols) EVT_MENU(idClassMethod, CodeCompletion::OnClassMethod) EVT_MENU(idUnimplementedClassMethods, CodeCompletion::OnUnimplementedClassMethods) EVT_MENU(idGotoDeclaration, CodeCompletion::OnGotoDeclaration) @@ -162,7 +168,9 @@ EVT_MENU(idMenuOpenIncludeFile, CodeCompletion::OnOpenIncludeFile) EVT_MENU(idViewClassBrowser, CodeCompletion::OnViewClassBrowser) - EVT_MENU(idProjectReparse, CodeCompletion::OnProjectReparse) + EVT_MENU(idCurrentProjectReparse, CodeCompletion::OnCurrentProjectReparse) + EVT_MENU(idSelectedProjectReparse, CodeCompletion::OnSelectedProjectReparse) + EVT_MENU(idSelectedFileReparse, CodeCompletion::OnSelectedFileReparse) EVT_TIMER(idCodeCompleteTimer, CodeCompletion::OnCodeCompleteTimer) EVT_TIMER(idFunctionsParsingTimer, CodeCompletion::OnStartParsingFunctions) @@ -283,6 +291,7 @@ CodeCompletion::CodeCompletion() : m_InitDone(false), + m_CodeRefactoring(m_NativeParser), m_EditorHookId(0), m_TimerCodeCompletion(this, idCodeCompleteTimer), m_TimerFunctionsParsing(this, idFunctionsParsingTimer), @@ -435,8 +444,21 @@ { m_EditMenu = menuBar->GetMenu(pos); m_EditMenu->AppendSeparator(); - m_EditMenu->Append(idMenuCodeComplete, _("Complete code\tCtrl-Space")); + + const wxLanguageInfo* info = wxLocale::GetLanguageInfo(wxLANGUAGE_DEFAULT); + if ( ( info->Language >= wxLANGUAGE_CHINESE + && info->Language <= wxLANGUAGE_CHINESE_TAIWAN ) + || info->Language == wxLANGUAGE_JAPANESE + || info->Language == wxLANGUAGE_KOREAN ) + { + m_EditMenu->Append(idMenuCodeComplete, _("Complete code\tShift-Space")); + } + else + m_EditMenu->Append(idMenuCodeComplete, _("Complete code\tCtrl-Space")); + m_EditMenu->Append(idMenuShowCallTip, _("Show call tip\tCtrl-Shift-Space")); + m_EditMenu->AppendSeparator(); + m_EditMenu->Append(idMenuRenameSymbols, _("Rename symbols\tAlt-N")); } else Manager::Get()->GetLogManager()->DebugLog(_T("Could not find Edit menu!")); @@ -450,6 +472,7 @@ m_SearchMenu->Append(idMenuGotoNextFunction, _("Goto next function\tCtrl-PgDn")); m_SearchMenu->Append(idMenuGotoDeclaration, _("Goto declaration\tCtrl-Shift-.")); m_SearchMenu->Append(idMenuGotoImplementation, _("Goto implementation\tCtrl-.")); + m_SearchMenu->Append(idMenuFindReferences, _("Find references\tAlt-.")); m_SearchMenu->Append(idMenuOpenIncludeFile, _("Open include file\tCtrl-Alt-.")); } else @@ -495,7 +518,7 @@ if (items[i]->IsSeparator()) { m_ProjectMenu->InsertSeparator(i); - m_ProjectMenu->Insert(i + 1, idProjectReparse, _("Reparse this project"), _("Reparse current actived project")); + m_ProjectMenu->Insert(i + 1, idCurrentProjectReparse, _("Reparse current project"), _("Reparse of the final switched project")); inserted = true; break; } @@ -505,7 +528,7 @@ if (!inserted) { m_ProjectMenu->AppendSeparator(); - m_ProjectMenu->Append(idProjectReparse, _("Reparse this project"), _("Reparse current actived project")); + m_ProjectMenu->Append(idCurrentProjectReparse, _("Reparse current project"), _("Reparse of the final switched project")); } } else @@ -558,7 +581,8 @@ { wxString NameUnderCursor; bool IsInclude = false; - if (EditorHasNameUnderCursor(NameUnderCursor, IsInclude)) + const bool nameUnderCursor = EditorHasNameUnderCursor(NameUnderCursor, IsInclude); + if (nameUnderCursor) { if (IsInclude) { @@ -570,15 +594,26 @@ else { wxString msg; + size_t pos = 0; msg.Printf(_("Find declaration of: '%s'"), NameUnderCursor.wx_str()); - menu->Insert(0, idGotoDeclaration, msg); + menu->Insert(pos, idGotoDeclaration, msg); + ++pos; msg.Printf(_("Find implementation of: '%s'"), NameUnderCursor.wx_str()); - menu->Insert(1, idGotoImplementation, msg); + menu->Insert(pos, idGotoImplementation, msg); + ++pos; - menu->Insert(2, wxID_SEPARATOR, wxEmptyString); + if (m_NativeParser.GetParser()->Done()) + { + msg.Printf(_("Find references of: '%s'"), NameUnderCursor.wx_str()); + menu->Insert(pos, idMenuFindReferences, msg); + ++pos; + } + + menu->Insert(pos, wxID_SEPARATOR, wxEmptyString); } } + const int insertId = menu->FindItem(_("Insert")); if (insertId != wxNOT_FOUND) { @@ -597,11 +632,24 @@ } else Manager::Get()->GetLogManager()->DebugLog(_T("Could not find Insert menu!")); + + if (m_NativeParser.GetParser()->Done() && nameUnderCursor && !IsInclude) + { + wxMenu* refactorMenu = new wxMenu(); + refactorMenu->Append(idMenuRenameSymbols, _("Rename symbols"), _("Rename symbols under cursor")); + menu->AppendSeparator(); + menu->Append(wxID_ANY, _T("Code Refactoring"), refactorMenu); + } } else if (type == mtProjectManager) { - if (data && data->GetKind() == FileTreeData::ftdkProject) - menu->Append(idProjectReparse, _("Reparse this project"), _("Reparse current actived project")); + if (data) + { + if (data->GetKind() == FileTreeData::ftdkProject) + menu->Append(idSelectedProjectReparse, _("Reparse this project"), _("Reparse current actived project")); + else if (data->GetKind() == FileTreeData::ftdkFile) + menu->Append(idSelectedFileReparse, _("Reparse this file"), _("Reparse current selected file")); + } } } @@ -690,6 +738,7 @@ { m_EditMenu->Delete(idMenuCodeComplete); m_EditMenu->Delete(idMenuShowCallTip); + m_EditMenu->Delete(idMenuRenameSymbols); } if (m_SearchMenu) { @@ -698,6 +747,7 @@ m_SearchMenu->Delete(idMenuGotoNextFunction); m_SearchMenu->Delete(idMenuGotoDeclaration); m_SearchMenu->Delete(idMenuGotoImplementation); + m_SearchMenu->Delete(idMenuFindReferences); m_SearchMenu->Delete(idMenuOpenIncludeFile); } } @@ -1550,7 +1600,6 @@ // a project/workspace, because the class browser would need to be updated again. // So we need to update it with the EVT_WORKSPACE_CHANGED event, which gets // triggered after everything's finished loading/closing. - if (!ProjectManager::IsBusy() && IsAttached() && m_InitDone) { cbProject* project = event.GetProject(); @@ -1563,7 +1612,7 @@ if (!Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor()) { Parser* parser = m_NativeParser.GetParserByProject(project); - if (parser != m_NativeParser.GetParser()) + if (parser && parser != m_NativeParser.GetParser()) m_NativeParser.SwitchParser(project, parser); } @@ -1595,7 +1644,7 @@ m_TimerProjectSaved.SetClientData(event.GetProject()); // we need more time for waiting wxExecute in NativeParser::AddCompilerPredefinedMacros - m_TimerProjectSaved.Start(1000, wxTIMER_ONE_SHOT); + m_TimerProjectSaved.Start(200, wxTIMER_ONE_SHOT); event.Skip(); } @@ -1609,13 +1658,14 @@ if (projs->Index(project) == wxNOT_FOUND) return; - if ( IsAttached() - && m_InitDone - && project - && m_NativeParser.GetParserByProject(project) - && m_NativeParser.DeleteParser(project) ) + if (IsAttached() && m_InitDone && project) { - Manager::Get()->GetLogManager()->DebugLog(_T("Reparsing project.")); + if ( m_NativeParser.GetParserByProject(project) + && m_NativeParser.DeleteParser(project) ) + { + Manager::Get()->GetLogManager()->DebugLog(_T("Reparsing project.")); + } + m_NativeParser.CreateParser(project); } @@ -2055,7 +2105,6 @@ else choice->SetSelection(wxNOT_FOUND); } - } void CodeCompletion::UpdateFunctions(unsigned int scopeItem) @@ -2236,11 +2285,17 @@ void CodeCompletion::OnUpdateUI(wxUpdateUIEvent& event) { + wxString NameUnderCursor; + bool IsInclude = false; + const bool HasNameUnderCursor = EditorHasNameUnderCursor(NameUnderCursor, IsInclude); + const bool HasEd = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor() != 0; if (m_EditMenu) { m_EditMenu->Enable(idMenuCodeComplete, HasEd); m_EditMenu->Enable(idMenuShowCallTip, HasEd); + const bool RenameEnable = HasNameUnderCursor && !IsInclude && m_NativeParser.GetParser()->Done(); + m_EditMenu->Enable(idMenuRenameSymbols, RenameEnable); } if (m_SearchMenu) @@ -2248,12 +2303,12 @@ m_SearchMenu->Enable(idMenuGotoFunction, HasEd); m_SearchMenu->Enable(idMenuGotoPrevFunction, HasEd); m_SearchMenu->Enable(idMenuGotoNextFunction, HasEd); - wxString NameUnderCursor; - bool IsInclude = false; - const bool HasNameUnderCursor = EditorHasNameUnderCursor(NameUnderCursor, IsInclude); + const bool GotoEnable = HasNameUnderCursor && !IsInclude; m_SearchMenu->Enable(idMenuGotoDeclaration, GotoEnable); m_SearchMenu->Enable(idMenuGotoImplementation, GotoEnable); + const bool FindEnable = HasNameUnderCursor && !IsInclude && m_NativeParser.GetParser()->Done(); + m_SearchMenu->Enable(idMenuFindReferences, FindEnable); const bool IncludeEnable = HasNameUnderCursor && IsInclude; m_SearchMenu->Enable(idMenuOpenIncludeFile, IncludeEnable); } @@ -2266,8 +2321,8 @@ if (m_ProjectMenu) { - bool projActived = Manager::Get()->GetProjectManager()->GetActiveProject(); - m_ProjectMenu->Enable(idProjectReparse, projActived); + cbProject* project = m_NativeParser.GetProjectByParser(m_NativeParser.GetParser()); + m_ProjectMenu->Enable(idCurrentProjectReparse, !!project); } // must do... @@ -2375,18 +2430,8 @@ // get the matching set TokenIdxSet result; m_NativeParser.MarkItemsByAI(result, m_NativeParser.GetParser()->Options().useSmartSense); + m_NativeParser.RemoveInvalid(result, target); - // filter - TokensTree* tokens = m_NativeParser.GetParser()->GetTokens(); - for (TokenIdxSet::iterator it = result.begin(); it != result.end();) - { - Token* tk = tokens->at(*it); - if (!tk || tk->m_Name != target) - result.erase(it++); - else - ++it; - } - // one match Token* token = NULL; if (result.size() == 1) @@ -2465,6 +2510,16 @@ } } +void CodeCompletion::OnFindReferences(wxCommandEvent& event) +{ + m_CodeRefactoring.FindReferences(); +} + +void CodeCompletion::OnRenameSymbols(wxCommandEvent& event) +{ + m_CodeRefactoring.RenameSymbols(); +} + void CodeCompletion::OnOpenIncludeFile(wxCommandEvent& event) { wxString LastIncludeFileFrom; @@ -2544,12 +2599,46 @@ cbMessageBox(wxString::Format(_("Not found: %s"), NameUnderCursor.c_str()), _("Warning"), wxICON_WARNING); } -void CodeCompletion::OnProjectReparse(wxCommandEvent& event) +void CodeCompletion::OnCurrentProjectReparse(wxCommandEvent& event) { - m_NativeParser.ForceReparseActiveProject(); + m_NativeParser.ReparseCurrentProject(); event.Skip(); } +void CodeCompletion::OnSelectedProjectReparse(wxCommandEvent& event) +{ + m_NativeParser.ReparseSelectedProject(); + event.Skip(); +} + +void CodeCompletion::OnSelectedFileReparse(wxCommandEvent& event) +{ + wxTreeCtrl* tree = Manager::Get()->GetProjectManager()->GetTree(); + if (!tree) + return; + + wxTreeItemId treeItem = tree->GetSelection(); + if (!treeItem.IsOk()) + return; + + const FileTreeData* data = static_cast(tree->GetItemData(treeItem)); + if (!data) + return; + + if (data->GetKind() == FileTreeData::ftdkFile) + { + cbProject* project = data->GetProject(); + ProjectFile* pf = project->GetFile(data->GetFileIndex()); + if (pf && m_NativeParser.ReparseFile(project, pf->file.GetFullPath())) + { + Manager::Get()->GetLogManager()->DebugLog(_T("Reparsing the selected file ") + + pf->file.GetFullPath()); + } + } + + event.Skip(); +} + void CodeCompletion::EditorEventHook(cbEditor* editor, wxScintillaEvent& event) { ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion")); @@ -2834,6 +2923,8 @@ void CodeCompletion::OnRealtimeParsing(wxTimerEvent& event) { cbProject* project = m_NativeParser.GetProjectByFilename(m_LastFile); + if (project && !project->GetFileByFilename(m_LastFile, false, true)) + return; if (m_NativeParser.ReparseFile(project, m_LastFile)) Manager::Get()->GetLogManager()->DebugLog(_T("Reparsing when typing for editor ") + m_LastFile); } Index: src/plugins/codecompletion/nativeparser.h =================================================================== --- src/plugins/codecompletion/nativeparser.h (revision 6574) +++ src/plugins/codecompletion/nativeparser.h (working copy) @@ -60,6 +60,12 @@ OperatorType tokenOperatorType; }; +struct ccSearchData +{ + cbStyledTextCtrl* control; + wxString file; +}; + class NativeParser : public wxEvtHandler { public: @@ -90,11 +96,14 @@ bool RemoveFileFromParser(cbProject* project, const wxString& filename); void RereadParserOptions(); - void ForceReparseActiveProject(); + void ReparseCurrentProject(); + void ReparseSelectedProject(); - - size_t MarkItemsByAI(TokenIdxSet& result, bool reallyUseAI = true, bool fullMatch = false, + size_t MarkItemsByAI(TokenIdxSet& result, bool reallyUseAI = true, bool isPrefix = false, bool caseSensitive = false, int caretPos = -1); + size_t MarkItemsByAI(ccSearchData* searchData, TokenIdxSet& result, bool reallyUseAI = true, + bool isPrefix = false, bool caseSensitive = false, int caretPos = -1); + void RemoveInvalid(TokenIdxSet& result, const wxString& target); const wxString& GetCodeCompletionItems(); void GetCallTipHighlight(const wxString& calltip, int* start, int* end); @@ -109,9 +118,9 @@ // returns the editor's position where the current function starts // optionally, returns the function's namespace (ends in double-colon ::) and name - int FindCurrentFunctionStart(cbEditor* editor, wxString* nameSpace = 0L, wxString* procName = 0L, int caretPos = -1); + int FindCurrentFunctionStart(ccSearchData* searchData, wxString* nameSpace = 0L, wxString* procName = 0L, int caretPos = -1); // fills the result argument with all the tokens matching the current function (hopefully, just one) - size_t FindCurrentFunctionToken(cbEditor* editor, TokenIdxSet& result, int caretPos = -1); + size_t FindCurrentFunctionToken(ccSearchData* searchData, TokenIdxSet& result, int caretPos = -1); ClassBrowser* GetClassBrowser() const { return m_pClassBrowser; } void CreateClassBrowser(); @@ -130,19 +139,25 @@ private: friend class CodeCompletion; - size_t AI(TokenIdxSet& result, cbEditor* editor, const wxString& lineText = wxEmptyString, bool fullMatch = false, bool caseSensitive = false, TokenIdxSet* search_scope = 0, int caretPos = -1); + size_t AI(TokenIdxSet& result, ccSearchData* searchData, const wxString& lineText = wxEmptyString, + bool isPrefix = false, bool caseSensitive = false, TokenIdxSet* search_scope = 0, + int caretPos = -1); - size_t FindAIMatches(std::queue components, TokenIdxSet& result, int parentTokenIdx = -1, bool fullMatch = false, bool caseSensitive = false, bool use_inheritance = true, short int kindMask = 0xFFFF, TokenIdxSet* search_scope = 0); + size_t FindAIMatches(std::queue components, TokenIdxSet& result, int parentTokenIdx = -1, + bool isPrefix = false, bool caseSensitive = false, bool use_inheritance = true, + short int kindMask = 0xFFFF, TokenIdxSet* search_scope = 0); size_t BreakUpComponents(const wxString& actual, std::queue& components); bool BelongsToParentOrItsAncestors(TokensTree* tree, Token* token, int parentIdx, bool use_inheritance = true); - size_t GenerateResultSet(TokensTree* tree, const wxString& search, int parentIdx, TokenIdxSet& result, bool caseSens = true, bool isPrefix = false, short int kindMask = 0xFFFF); - size_t GenerateResultSet(wxString search, const TokenIdxSet& ptrParentID, TokenIdxSet& result, bool caseSens = true, bool isPrefix = false, short int kindMask = 0xFFFF); + size_t GenerateResultSet(TokensTree* tree, const wxString& search, int parentIdx, TokenIdxSet& result, + bool caseSens = true, bool isPrefix = false, short int kindMask = 0xFFFF); + size_t GenerateResultSet(wxString search, const TokenIdxSet& ptrParentID, TokenIdxSet& result, + bool caseSens = true, bool isPrefix = false, short int kindMask = 0xFFFF); bool LastAISearchWasGlobal() const { return m_LastAISearchWasGlobal; } const wxString& LastAIGlobalSearch() const { return m_LastAIGlobalSearch; } - bool ParseUsingNamespace(cbEditor* ed, TokenIdxSet& search_scope, int caretPos = -1); - bool ParseFunctionArguments(cbEditor* ed, int caretPos = -1); - bool ParseLocalBlock(cbEditor* ed, int caretPos = -1); // parses from the start of function up to the cursor + bool ParseUsingNamespace(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos = -1); + bool ParseFunctionArguments(ccSearchData* searchData, int caretPos = -1); + bool ParseLocalBlock(ccSearchData* searchData, int caretPos = -1); // parses from the start of function up to the cursor unsigned int FindCCTokenStart(const wxString& line); wxString GetNextCCToken(const wxString& line, unsigned int& startAt, OperatorType& tokenOperatroType); @@ -170,7 +185,7 @@ size_t ResolveActualType(wxString searchText, const TokenIdxSet& searchScope, TokenIdxSet& result); size_t ResolveExpression(std::queue components, const TokenIdxSet& searchScope, - TokenIdxSet& result, bool IsCaseSense = true, bool IsPrefix = false); + TokenIdxSet& result, bool caseSense = true, bool isPrefix = false); void CollectSS(const TokenIdxSet& searchScope, TokenIdxSet& actualTypeScope, TokensTree* tree); void AddTemplateAlias(const int& actualTypeResult, const TokenIdxSet& actualTypeScope, TokenIdxSet& initialScope, TokensTree* tree); Index: src/plugins/codecompletion/codecompletion.h =================================================================== --- src/plugins/codecompletion/codecompletion.h (revision 6574) +++ src/plugins/codecompletion/codecompletion.h (working copy) @@ -13,6 +13,7 @@ #include #include "nativeparser.h" +#include "coderefactoring.h" #include #include @@ -93,8 +94,12 @@ void OnClassMethod(wxCommandEvent& event); void OnUnimplementedClassMethods(wxCommandEvent& event); void OnGotoDeclaration(wxCommandEvent& event); + void OnFindReferences(wxCommandEvent& event); + void OnRenameSymbols(wxCommandEvent& event); void OnOpenIncludeFile(wxCommandEvent& event); - void OnProjectReparse(wxCommandEvent& event); + void OnCurrentProjectReparse(wxCommandEvent& event); + void OnSelectedProjectReparse(wxCommandEvent& event); + void OnSelectedFileReparse(wxCommandEvent& event); void OnAppDoneStartup(CodeBlocksEvent& event); void OnCodeCompleteTimer(wxTimerEvent& event); void OnWorkspaceChanged(CodeBlocksEvent& event); @@ -122,7 +127,6 @@ void FunctionPosition(int &scopeItem, int &functionItem) const; void GotoFunctionPrevNext(bool next = false); int NameSpacePosition() const; - void ParseActiveProjects(); void OnStartParsingFunctions(wxTimerEvent& event); void OnFindFunctionAndUpdate(wxTimerEvent& event); void OnScope(wxCommandEvent& event); @@ -142,6 +146,7 @@ wxMenu* m_ViewMenu; wxMenu* m_ProjectMenu; NativeParser m_NativeParser; + CodeRefactoring m_CodeRefactoring; int m_EditorHookId; int m_LastPosForCodeCompletion; wxTimer m_TimerCodeCompletion; Index: src/plugins/codecompletion/classbrowser.cpp =================================================================== --- src/plugins/codecompletion/classbrowser.cpp (revision 6574) +++ src/plugins/codecompletion/classbrowser.cpp (working copy) @@ -532,7 +532,7 @@ void ClassBrowser::OnForceReparse(wxCommandEvent& /*event*/) { if (m_NativeParser) - m_NativeParser->ForceReparseActiveProject(); + m_NativeParser->ReparseCurrentProject(); } void ClassBrowser::OnCBViewMode(wxCommandEvent& event) Index: src/plugins/codecompletion/parser/parser.h =================================================================== --- src/plugins/codecompletion/parser/parser.h (revision 6574) +++ src/plugins/codecompletion/parser/parser.h (working copy) @@ -126,13 +126,16 @@ class Parser : public wxEvtHandler { + friend class ParserThread; + friend class AddParseThread; + public: - friend class ParserThread; Parser(wxEvtHandler* parent); ~Parser(); void PrepareParsing(); - void AddBatchParse(const wxArrayString& filenames, bool isUpFront = false); + void AddUpFrontHeaders(const wxString& filename, bool systemHeaderFile); + void AddBatchParse(const wxArrayString& filenames); void StartParsing(bool delay = true); bool ParseBuffer(const wxString& buffer, bool isLocal = true, bool bufferSkipBlocks = false, bool isTemp = false); @@ -213,7 +216,7 @@ bool m_UsingCache; // true if loaded from cache typedef std::vector PTVector; - std::queue m_PoolQueue; + std::queue m_PoolTask; // Do task one by one! cbThreadPool m_Pool; bool m_IsUpFront; TokensTree* m_pTokensTree; @@ -230,9 +233,13 @@ bool m_StopWatchRunning; long m_LastStopWatchTime; bool m_IgnoreThreadEvents; - wxArrayString m_UpFrontHeaders; + + wxArrayString m_UpFrontHeaders; // All up-front headers + wxArrayString m_SystemUpFrontHeaders; // Only system up-front headers, for reparse + wxArrayString m_BatchParseFiles; // All other batch parse files bool m_IsBatchParseDone; ParsingType m_ParsingType; + wxCriticalSection m_TokensTreeCritical; wxCriticalSection m_BatchParsingCritical; Index: src/plugins/codecompletion/parser/token.cpp =================================================================== --- src/plugins/codecompletion/parser/token.cpp (revision 6574) +++ src/plugins/codecompletion/parser/token.cpp (working copy) @@ -27,6 +27,27 @@ ProfileTimer::ProfileMap ProfileTimer::m_ProfileMap; +FileType CCFileTypeOf(const wxString& filename) +{ + const wxString file = filename.AfterLast(wxFILE_SEP_PATH).Lower(); + const int pos = file.Find(_T('.'), true); + wxString ext; + if (pos != wxNOT_FOUND) + ext = file.SubString(pos + 1, file.Len()); + + if ( ext.IsEmpty() + || ext == _T("h") + || ext == _T("hpp") + || ext == _T("tcc")) + return ftHeader; + else if ( ext ==_T("cpp") + || ext ==_T("c") + || ext ==_T("cxx") ) + return ftSource; + else + return ftOther; +} + inline void SaveTokenIdxSetToFile(wxOutputStream* f,const TokenIdxSet& data) { SaveIntToFile(f, (int)(data.size())); Index: src/plugins/codecompletion/parser/parserthread.cpp =================================================================== --- src/plugins/codecompletion/parser/parserthread.cpp (revision 6574) +++ src/plugins/codecompletion/parser/parserthread.cpp (working copy) @@ -149,7 +149,6 @@ m_pTokensTree = tokensTree; } - wxChar ParserThread::SkipToOneOfChars(const wxString& chars, bool supportNesting) { unsigned int level = m_Tokenizer.GetNestingLevel(); @@ -1296,6 +1295,9 @@ } } + if (CCFileTypeOf(filename) == ftOther) + return; + if (!filename.IsEmpty()) { TRACE(F(_T("HandleIncludes() : Found include file '%s'"), filename.wx_str())); Index: src/plugins/codecompletion/parser/token.h =================================================================== --- src/plugins/codecompletion/parser/token.h (revision 6574) +++ src/plugins/codecompletion/parser/token.h (working copy) @@ -115,6 +115,8 @@ fpsDone }; +FileType CCFileTypeOf(const wxString& filename); + WX_DEFINE_ARRAY(Token*, TokensArray); typedef vector TokenList; Index: src/plugins/codecompletion/parser/parser.cpp =================================================================== --- src/plugins/codecompletion/parser/parser.cpp (revision 6574) +++ src/plugins/codecompletion/parser/parser.cpp (working copy) @@ -29,7 +29,7 @@ #include #ifndef CB_PRECOMP - #include "editorbase.h" + #include "editorbase.h" #endif #define CC_PARSER_DEBUG_OUTPUT 0 @@ -55,6 +55,37 @@ BEGIN_EVENT_TABLE(Parser, wxEvtHandler) END_EVENT_TABLE() +class AddParseThread : public cbThreadedTask +{ +public: + AddParseThread(Parser* parser) : m_Parent(parser) + {} + + int Execute() + { + m_Parent->m_IsUpFront = true; + + // Add up-front headers + for (size_t i = 0; i < m_Parent->m_UpFrontHeaders.GetCount(); ++i) + m_Parent->AddParse(m_Parent->m_UpFrontHeaders[i]); + + m_Parent->m_IsUpFront = false; + + // Add all other files + for (size_t i = 0; i < m_Parent->m_BatchParseFiles.GetCount(); ++i) + m_Parent->AddParse(m_Parent->m_BatchParseFiles[i]); + + m_Parent->m_UpFrontHeaders.Clear(); + m_Parent->m_BatchParseFiles.Clear(); + m_Parent->m_IsParsing = true; + + return 0; + } + +private: + Parser* m_Parent; +}; + Parser::Parser(wxEvtHandler* parent) : m_pParent(parent), m_UsingCache(false), @@ -64,7 +95,7 @@ m_IsFirstBatch(false), m_IsParsing(false), m_Timer(this, TIMER_ID), - m_BatchTimer(this,BATCH_TIMER_ID), + m_BatchTimer(this, BATCH_TIMER_ID), m_StopWatchRunning(false), m_LastStopWatchTime(0), m_IgnoreThreadEvents(false), @@ -185,7 +216,7 @@ bool Parser::Done() { wxCriticalSectionLocker locker(m_BatchParsingCritical); - return m_PoolQueue.empty() && m_Pool.Done(); + return m_PoolTask.empty() && m_Pool.Done(); } Token* Parser::FindTokenByName(const wxString& name, bool globalsOnly, short int kindMask) @@ -292,25 +323,26 @@ m_IsFirstBatch = true; } -void Parser::AddBatchParse(const wxArrayString& filenames, bool isUpFront) +void Parser::AddUpFrontHeaders(const wxString& filename, bool systemHeaderFile) { - if (filenames.IsEmpty() || m_IsParsing) - return; + // Do up-front parse in sub thread + m_UpFrontHeaders.Add(filename); - StartStopWatch(); + // Save system up-front headers, when all task is over, we need reparse it! + if (systemHeaderFile) + m_SystemUpFrontHeaders.Add(filename); +} - if (isUpFront) - m_IsUpFront = true; - - for (size_t i = 0; i < filenames.GetCount(); ++i) +void Parser::AddBatchParse(const wxArrayString& filenames) +{ + if (m_BatchParseFiles.IsEmpty()) + m_BatchParseFiles = filenames; + else { - AddParse(filenames[i]); // defer loading until later - if (isUpFront) - m_UpFrontHeaders.Add(filenames[i]); + m_BatchParseFiles.Alloc(m_BatchParseFiles.GetCount() + filenames.GetCount()); + for (size_t i = 0; i < filenames.GetCount(); ++i) + m_BatchParseFiles.Add(filenames[i]); } - - EndStopWatch(); - m_IsUpFront = false; } void Parser::StartParsing(bool delay) @@ -338,7 +370,6 @@ bool Parser::Parse(const wxString& bufferOrFilename, bool isLocal, ParserThreadOptions& opts) { - wxString buffOrFile = bufferOrFilename; bool result = false; do { @@ -346,9 +377,9 @@ { wxCriticalSectionLocker locker(m_TokensTreeCritical); - bool canparse = !m_pTokensTree->IsFileParsed(buffOrFile); + bool canparse = !m_pTokensTree->IsFileParsed(bufferOrFilename); if (canparse) - canparse = m_pTokensTree->ReserveFileForParsing(buffOrFile, true) != 0; + canparse = m_pTokensTree->ReserveFileForParsing(bufferOrFilename, true) != 0; if (!canparse) { @@ -361,15 +392,16 @@ opts.loader = Manager::Get()->GetFileManager()->Load(bufferOrFilename, m_NeedsReparse); } - TRACE(_T("Parse() : Creating task for: %s"), buffOrFile.wx_str()); - ParserThread* thread = new(std::nothrow) ParserThread(this, buffOrFile, isLocal, opts, m_pTokensTree); + TRACE(_T("Parse() : Creating task for: %s"), bufferOrFilename.wx_str()); + ParserThread* thread = new(std::nothrow) ParserThread(this, bufferOrFilename, isLocal, opts, m_pTokensTree); if (!thread) - return false; -#if !CC_PARSER_PROFILE_TEST - if (opts.useBuffer) -#else - if (true) + break; + + bool doParseNow = opts.useBuffer; +#if CC_PARSER_PROFILE_TEST + doParseNow = true; #endif + if (doParseNow) { result = thread->Parse(); LinkInheritance(true); @@ -377,42 +409,44 @@ break; } - TRACE(_T("Parse() : Parsing %s"), buffOrFile.wx_str()); + TRACE(_T("Parse() : Parsing %s"), bufferOrFilename.wx_str()); if (!m_IsUpFront) { - TRACE(_T("Parse() : Parallel Parsing %s"), buffOrFile.wx_str()); + TRACE(_T("Parse() : Parallel Parsing %s"), bufferOrFilename.wx_str()); - if (m_IsFirstBatch && wxThread::IsMain()) + // Add a task for all project files + if (m_IsFirstBatch) { m_IsFirstBatch = false; - m_PoolQueue.push(PTVector()); + m_PoolTask.push(PTVector()); } - if (!m_IsParsing && m_PoolQueue.empty()) + if (!m_IsParsing && m_PoolTask.empty()) { Manager::Get()->GetLogManager()->DebugLog(_T("Parse file failed!")); - return false; + break; } if (m_IsParsing) m_Pool.AddTask(thread, true); else - m_PoolQueue.back().push_back(thread); + m_PoolTask.back().push_back(thread); } - else if (m_IsUpFront && wxThread::IsMain()) + else if (m_IsUpFront) { - if (isLocal) // local include files + if (isLocal) // Parsing up-front files { + TRACE(_T("Parse() : Parsing up-front header, %s"), bufferOrFilename.wx_str()); result = thread->Parse(); delete thread; break; } - else // global include files + else // Add task when parsing up-front files { - TRACE(_T("Parse() : Parsing %s"), buffOrFile.wx_str()); - m_PoolQueue.push(PTVector()); - m_PoolQueue.back().push_back(thread); + TRACE(_T("Parse() : Add task for up-front header, %s"), bufferOrFilename.wx_str()); + m_PoolTask.push(PTVector()); + m_PoolTask.back().push_back(thread); } } @@ -694,12 +728,12 @@ while (!m_Pool.Done()) wxMilliSleep(20); - while (!m_PoolQueue.empty()) + while (!m_PoolTask.empty()) { - PTVector& v = m_PoolQueue.front(); + PTVector& v = m_PoolTask.front(); for (PTVector::const_iterator it = v.begin(); it != v.end(); ++it) delete *it; - m_PoolQueue.pop(); + m_PoolTask.pop(); } } @@ -772,42 +806,43 @@ if (m_IgnoreThreadEvents || !m_IsParsing) return; - if (!m_PoolQueue.empty()) - { + // Do next task + if (!m_PoolTask.empty()) m_BatchTimer.Start(1, wxTIMER_ONE_SHOT); - } + #if !CC_PARSER_PROFILE_TEST - else if (!m_UpFrontHeaders.IsEmpty()) + // Reparse system up-front headers + else if (!m_SystemUpFrontHeaders.IsEmpty()) { // Part.1 Set m_IsParsing to false m_IsParsing = false; // Part.2 Remove all up-front headers in token tree - for (size_t i = 0; i < m_UpFrontHeaders.GetCount(); ++i) - RemoveFile(m_UpFrontHeaders[i]); + for (size_t i = 0; i < m_SystemUpFrontHeaders.GetCount(); ++i) + RemoveFile(m_SystemUpFrontHeaders[i]); // Part.3 Prepare parsing PrepareParsing(); // Part.4 Re-parse all the up-front headers - for (size_t i = 0; i < m_UpFrontHeaders.GetCount(); ++i) - AddParse(m_UpFrontHeaders[i]); + for (size_t i = 0; i < m_SystemUpFrontHeaders.GetCount(); ++i) + AddParse(m_SystemUpFrontHeaders[i]); // Part.5 Clear - m_UpFrontHeaders.Clear(); + m_SystemUpFrontHeaders.Clear(); // Part.6 Start parsing StartParsing(); } #endif + + // Finish all task, then we need post a Parse_END event else { - if (m_NeedsReparse) - m_NeedsReparse = false; - - EndStopWatch(); + m_NeedsReparse = false; m_IsParsing = false; m_IsBatchParseDone = true; + EndStopWatch(); PostParserEvent(m_ParsingType, PARSER_END); m_ParsingType = ptUndefined; } @@ -907,23 +942,32 @@ void Parser::OnBatchTimer(wxTimerEvent& event) { - if (!m_IsParsing) - m_IsParsing = true; - if (!m_StopWatchRunning) { StartStopWatch(); PostParserEvent(m_ParsingType, PARSER_START); } - if (!m_PoolQueue.empty()) + // Add parse by sub thread + if (!m_UpFrontHeaders.IsEmpty() || !m_BatchParseFiles.IsEmpty()) { + AddParseThread* thread = new AddParseThread(this); + m_Pool.AddTask(thread, true); + return; + } + + // Setting parse flag when all task added + else if (!m_IsParsing) + m_IsParsing = true; + + if (!m_PoolTask.empty()) + { m_Pool.BatchBegin(); - PTVector& v = m_PoolQueue.front(); + PTVector& v = m_PoolTask.front(); for (PTVector::const_iterator it = v.begin(); it != v.end(); ++it) m_Pool.AddTask(*it, true); - m_PoolQueue.pop(); + m_PoolTask.pop(); m_Pool.BatchEnd(); } Index: src/plugins/codecompletion/Makefile.am =================================================================== --- src/plugins/codecompletion/Makefile.am (revision 6574) +++ src/plugins/codecompletion/Makefile.am (working copy) @@ -2,7 +2,8 @@ INCLUDES = $(WX_CXXFLAGS) \ -I$(top_srcdir)/src/include \ - -I$(top_srcdir)/src/sdk/wxscintilla/include + -I$(top_srcdir)/src/sdk/wxscintilla/include \ + -I$(top_srcdir)/src/include/mozilla_chardet pluginlibdir = $(pkglibdir)/plugins @@ -18,6 +19,7 @@ classbrowser.cpp \ classbrowserbuilderthread.cpp \ codecompletion.cpp \ + coderefactoring.cpp \ insertclassmethoddlg.cpp \ nativeparser.cpp \ selectincludefile.cpp \ @@ -34,6 +36,7 @@ classbrowser.h \ classbrowserbuilderthread.h \ codecompletion.h \ + coderefactoring.h \ insertclassmethoddlg.h \ nativeparser.h \ selectincludefile.h \ Index: src/sdk/editormanager.cpp =================================================================== --- src/sdk/editormanager.cpp (revision 6574) +++ src/sdk/editormanager.cpp (working copy) @@ -2600,7 +2600,7 @@ if (count > 0) { - static_cast(m_pSearchLog)->SetBasePath(data->searchPath); + m_pSearchLog->SetBasePath(data->searchPath); if (Manager::Get()->GetConfigManager(_T("message_manager"))->ReadBool(_T("/auto_show_search"), true)) { CodeBlocksLogEvent evtSwitch(cbEVT_SWITCH_TO_LOG_WINDOW, m_pSearchLog); @@ -2609,7 +2609,7 @@ Manager::Get()->ProcessEvent(evtSwitch); Manager::Get()->ProcessEvent(evtShow); } - static_cast(m_pSearchLog)->FocusEntry(oldcount); + m_pSearchLog->FocusEntry(oldcount); } else { @@ -2626,7 +2626,7 @@ { msg.Printf(_("not found in %d files"), filesList.GetCount()); LogSearch(_T(""), -1, msg ); - static_cast(m_pSearchLog)->FocusEntry(oldcount); + m_pSearchLog->FocusEntry(oldcount); } } Index: src/include/editormanager.h =================================================================== --- src/include/editormanager.h (revision 6574) +++ src/include/editormanager.h (working copy) @@ -38,6 +38,7 @@ class ListCtrlLogger; class LoaderBase; struct EditorManagerInternalData; +class SearchResultsLog; WX_DECLARE_STRING_HASH_MAP(wxString, AutoCompleteMap); @@ -144,6 +145,8 @@ /** Check if one of the open files has been modified outside the IDE. If so, ask to reload it. */ void CheckForExternallyModifiedFiles(); + SearchResultsLog* GetSearchResultLogger() const { return m_pSearchLog; } + void OnGenericContextMenuHandler(wxCommandEvent& event); void OnPageChanged(wxAuiNotebookEvent& event); void OnPageChanging(wxAuiNotebookEvent& event); @@ -202,7 +205,7 @@ size_t m_nNotebookStackSize; cbFindReplaceData* m_LastFindReplaceData; EditorColourSet* m_Theme; - ListCtrlLogger* m_pSearchLog; + SearchResultsLog* m_pSearchLog; int m_SearchLogIndex; int m_Zoom; bool m_isCheckingForExternallyModifiedFiles; Index: src/src/main.cpp =================================================================== --- src/src/main.cpp (revision 6574) +++ src/src/main.cpp (working copy) @@ -2477,9 +2477,14 @@ wxBusyCursor useless; wxPaintEvent e; ProcessEvent(e); - +#if !wxCHECK_VERSION(2, 8, 11) + Freeze(); +#endif for (unsigned int i = 0; i < files.GetCount(); ++i) success &= OpenGeneric(files[i]); +#if !wxCHECK_VERSION(2, 8, 11) + Thaw(); +#endif } return success; } Index: src/CodeBlocks-unix.cbp =================================================================== --- src/CodeBlocks-unix.cbp (revision 6574) +++ src/CodeBlocks-unix.cbp (working copy) @@ -256,6 +256,7 @@