📄 codecompletion.cpp
字号:
/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003 Yiannis An. Mandravellos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL : http://www.codeblocks.org
*
* $Id: codecompletion.cpp,v 1.20.2.1 2005/10/25 07:59:01 mandrav Exp $
* $Date: 2005/10/25 07:59:01 $
*/
#include <sdk.h>
#include "codecompletion.h"
#include <wx/mimetype.h>
#include <wx/filename.h>
#include <wx/regex.h>
#include <wx/xrc/xmlres.h>
#include <wx/fs_zip.h>
#include <wx/msgdlg.h>
#include <manager.h>
#include <configmanager.h>
#include <messagemanager.h>
#include <projectmanager.h>
#include <editormanager.h>
#include <sdk_events.h>
#include <incrementalselectlistdlg.h>
#include "insertclassmethoddlg.h"
#include "ccoptionsdlg.h"
#include "parser/parser.h"
#include "cclist.h"
CB_IMPLEMENT_PLUGIN(CodeCompletion);
// menu IDS
// just because we don't know other plugins' used identifiers,
// we use wxNewId() to generate a guaranteed unique ID ;), instead of enum
// (don't forget that, especially in a plugin)
int idMenuCodeComplete = wxNewId();
int idMenuShowCallTip = wxNewId();
int idMenuGotoFunction = wxNewId();
int idEditorSubMenu = wxNewId();
int idClassMethod = wxNewId();
int idGotoDeclaration = wxNewId();
int idOpenIncludeFile = wxNewId();
BEGIN_EVENT_TABLE(CodeCompletion, cbCodeCompletionPlugin)
EVT_UPDATE_UI_RANGE(idMenuCodeComplete, idMenuGotoFunction, CodeCompletion::OnUpdateUI)
EVT_MENU(idMenuCodeComplete, CodeCompletion::OnCodeComplete)
EVT_MENU(idMenuShowCallTip, CodeCompletion::OnShowCallTip)
EVT_MENU(idMenuGotoFunction, CodeCompletion::OnGotoFunction)
EVT_MENU(idClassMethod, CodeCompletion::OnClassMethod)
EVT_MENU(idGotoDeclaration, CodeCompletion::OnGotoDeclaration)
EVT_MENU(idOpenIncludeFile, CodeCompletion::OnOpenIncludeFile)
EVT_EDITOR_AUTOCOMPLETE(CodeCompletion::OnCodeComplete)
EVT_EDITOR_CALLTIP(CodeCompletion::OnShowCallTip)
EVT_EDITOR_USERLIST_SELECTION(CodeCompletion::OnUserListSelection)
EVT_EDITOR_SAVE(CodeCompletion::OnReparseActiveEditor)
EVT_PROJECT_OPEN(CodeCompletion::OnProjectOpened)
EVT_PROJECT_ACTIVATE(CodeCompletion::OnProjectActivated)
EVT_PROJECT_CLOSE(CodeCompletion::OnProjectClosed)
EVT_PROJECT_FILE_ADDED(CodeCompletion::OnProjectFileAdded)
EVT_PROJECT_FILE_REMOVED(CodeCompletion::OnProjectFileRemoved)
EVT_CCLIST_CODECOMPLETE(CodeCompletion::OnCodeComplete)
END_EVENT_TABLE()
CodeCompletion::CodeCompletion()
{
wxFileSystem::AddHandler(new wxZipFSHandler);
wxXmlResource::Get()->InitAllHandlers();
wxString resPath = ConfigManager::Get()->Read(_T("data_path"), wxEmptyString);
wxXmlResource::Get()->Load(resPath + _T("/code_completion.zip#zip:*.xrc"));
m_PluginInfo.name = _T("CodeCompletion");
m_PluginInfo.title = _("Code completion");
m_PluginInfo.version = _T("0.1");
m_PluginInfo.description = _("This plugin provides a class browser for your projects "
"and code-completion inside the editor\n\n"
"Note: Only C/C++ language is supported by this plugin...");
m_PluginInfo.author = _T("Yiannis An. Mandravellos");
m_PluginInfo.authorEmail = _T("info@codeblocks.org");
m_PluginInfo.authorWebsite = _T("www.codeblocks.org");
m_PluginInfo.thanksTo = _T("");
m_PluginInfo.hasConfigure = true;
m_PageIndex = -1;
m_EditMenu = 0L;
m_SearchMenu = 0L;
ConfigManager::AddConfiguration(m_PluginInfo.title, _T("/code_completion"));
}
CodeCompletion::~CodeCompletion()
{
}
int CodeCompletion::Configure()
{
CCOptionsDlg dlg(Manager::Get()->GetAppWindow());
if (dlg.ShowModal() == wxID_OK)
{
m_NativeParsers.RereadParserOptions();
}
return 0;
}
void CodeCompletion::BuildMenu(wxMenuBar* menuBar)
{
// if not attached, exit
if (!m_IsAttached)
return;
// if (m_EditMenu)
// return; // already set-up
int pos = menuBar->FindMenu(_("&Edit"));
if (pos != wxNOT_FOUND)
{
m_EditMenu = menuBar->GetMenu(pos);
m_EditMenu->AppendSeparator();
m_EditMenu->Append(idMenuCodeComplete, _("Complete code\tCtrl-Space"));
m_EditMenu->Append(idMenuShowCallTip, _("Show call tip\tCtrl-Shift-Space"));
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Could not find Edit menu!"));
pos = menuBar->FindMenu(_("Sea&rch"));
if (pos != wxNOT_FOUND)
{
m_SearchMenu = menuBar->GetMenu(pos);
m_SearchMenu->Append(idMenuGotoFunction, _("Goto function...\tCtrl-Alt-G"));
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Could not find Search menu!"));
}
void CodeCompletion::BuildModuleMenu(const ModuleType type, wxMenu* menu, const wxString& arg)
{
// if not attached, exit
if (!menu || !m_IsAttached)
return;
if (type == mtEditorManager)
{
cbStyledTextCtrl* control = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor()->GetControl();
if (control)
{
int pos = control->GetCurrentPos();
wxString line = control->GetLine(control->LineFromPosition(pos));
wxRegEx reg(_T("^[ \t]*#[ \t]*include[ \t]+[\"<]([^\">]+)[\">]"));
wxString inc;
if (reg.Matches(line))
inc = reg.GetMatch(line, 1);
m_LastIncludeFile.Clear();
if (!inc.IsEmpty())
{
wxString msg;
msg.Printf(_("Open #include file: '%s'"), inc.c_str());
menu->Insert(0, idOpenIncludeFile, msg);
menu->Insert(1, wxID_SEPARATOR, wxEmptyString);
m_LastIncludeFile = inc;
}
else // either #include or keyword-search
{
int ws = control->WordStartPosition(pos, true);
int we = control->WordEndPosition(pos, true);
wxString txt = control->GetTextRange(ws, we);
m_LastKeyword.Clear();
if (!txt.IsEmpty())
{
wxString msg;
msg.Printf(_("Find declaration of: '%s'"), txt.c_str());
menu->Insert(0, idGotoDeclaration, msg);
menu->Insert(1, wxID_SEPARATOR, wxEmptyString);
m_LastKeyword = txt;
}
}
}
int insertId = menu->FindItem(_("Insert..."));
if (insertId != wxNOT_FOUND)
{
wxMenuItem* insertMenu = menu->FindItem(insertId, NULL);
if (insertMenu)
{
wxMenu* subMenu = insertMenu->GetSubMenu();
if (subMenu)
{
subMenu->Append(idClassMethod, _("Class method declaration/implementation..."));
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Could not find Insert menu 3!"));
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Could not find Insert menu 2!"));
}
else
Manager::Get()->GetMessageManager()->DebugLog(_("Could not find Insert menu!"));
}
}
bool CodeCompletion::BuildToolBar(wxToolBar* toolBar)
{
// no need for toolbar items
return false;
}
void CodeCompletion::OnAttach()
{
m_NativeParsers.CreateClassBrowser();
// parse all active projects
ProjectManager* prjMan = Manager::Get()->GetProjectManager();
for (unsigned int i = 0; i < prjMan->GetProjects()->GetCount(); ++i)
m_NativeParsers.AddParser(prjMan->GetProjects()->Item(i));
}
void CodeCompletion::OnRelease(bool appShutDown)
{
m_NativeParsers.RemoveClassBrowser(appShutDown);
m_NativeParsers.ClearParsers();
CCList::Free();
/* TODO (mandrav#1#): Delete separator line too... */
if (m_EditMenu)
{
m_EditMenu->Delete(idMenuCodeComplete);
m_EditMenu->Delete(idMenuShowCallTip);
}
if (m_SearchMenu)
m_SearchMenu->Delete(idMenuGotoFunction);
}
int CodeCompletion::CodeComplete()
{
if (!m_IsAttached)
return -1;
EditorManager* edMan = Manager::Get()->GetEditorManager();
if (!edMan)
return -2;
cbEditor* ed = edMan->GetBuiltinActiveEditor();
if (!ed)
return -3;
FileType ft = FileTypeOf(ed->GetShortName());
if ( ft != ftHeader && ft != ftSource) // only parse source/header files
return -4;
Parser* parser = m_NativeParsers.FindParserFromActiveEditor();
if (!parser)
{
Manager::Get()->GetMessageManager()->DebugLog(_("Active editor has no associated parser ?!?"));
return -4;
}
if (m_NativeParsers.MarkItemsByAI(parser->Options().useSmartSense))
{
CCList::Free(); // free any previously open cc list
CCList::Get(this, ed->GetControl(), parser)->Show();
return 0;
}
return -5;
}
void CodeCompletion::CodeCompleteIncludes()
{
if (!m_IsAttached)
return;
cbProject* pPrj = Manager::Get()->GetProjectManager()->GetActiveProject();
if (!pPrj)
return;
EditorManager* edMan = Manager::Get()->GetEditorManager();
if (!edMan)
return;
cbEditor* ed = edMan->GetBuiltinActiveEditor();
if (!ed)
return;
Parser* parser = m_NativeParsers.FindParserFromActiveEditor();
bool caseSens = parser ? parser->Options().caseSensitive : false;
FileType ft = FileTypeOf(ed->GetShortName());
if ( ft != ftHeader && ft != ftSource) // only parse source/header files
return;
int pos = ed->GetControl()->GetCurrentPos();
int lineStartPos = ed->GetControl()->PositionFromLine(ed->GetControl()->GetCurrentLine());
wxString line = ed->GetControl()->GetLine(ed->GetControl()->GetCurrentLine());
//Manager::Get()->GetMessageManager()->DebugLog("#include cc for \"%s\"", line.c_str());
line.Trim();
if (line.IsEmpty() || !line.StartsWith(_T("#include")))
return;
// find opening quote (" or <)
int idx = pos - lineStartPos;
int found = -1;
wxString filename;
while (idx > 0)
{
wxChar c = line.GetChar(idx);
if (c == _T('>'))
return; // the quote is closed already...
else if (c == _T('"') || c == _T('<'))
{
if (found != -1)
return; // the already found quote was the closing one...
found = idx + 1;
}
else if (c != _T(' ') && c != _T('\t') && !found)
filename << c;
--idx;
}
// take care: found might point at the end of the string (out of bounds)
// in this case: #include "(<-code-completion at this point)
//Manager::Get()->GetMessageManager()->DebugLog("#include using \"%s\" (starting at %d)", filename.c_str(), found);
if (found == -1)
return;
// fill a list of matching project files
wxArrayString files;
for (int i = 0; i < pPrj->GetFilesCount(); ++i)
{
ProjectFile* pf = pPrj->GetFile(i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -