Code::Blocks  SVN r11506
codecompletion.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11505 $
6  * $Id: codecompletion.cpp 11505 2018-10-20 14:29:48Z ollydbg $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/codecompletion.cpp $
8  */
9 
10 #include <sdk.h>
11 
12 #ifndef CB_PRECOMP
13  #include <algorithm>
14  #include <iterator>
15  #include <set> // for handling unique items in some places
16 
17  #include <wx/choicdlg.h>
18  #include <wx/choice.h>
19  #include <wx/dir.h>
20  #include <wx/filename.h>
21  #include <wx/fs_zip.h>
22  #include <wx/menu.h>
23  #include <wx/mimetype.h>
24  #include <wx/msgdlg.h>
25  #include <wx/regex.h>
26  #include <wx/tipwin.h>
27  #include <wx/toolbar.h>
28  #include <wx/utils.h>
29  #include <wx/xrc/xmlres.h>
30  #include <wx/wxscintilla.h>
31 
32  #include <cbeditor.h>
33  #include <configmanager.h>
34  #include <editorcolourset.h>
35  #include <editormanager.h>
36  #include <globals.h>
37  #include <logmanager.h>
38  #include <macrosmanager.h>
39  #include <manager.h>
40  #include <projectmanager.h>
41  #include <sdk_events.h>
42 #endif
43 
44 #include <wx/tokenzr.h>
45 #include <wx/html/htmlwin.h>
46 
47 #include <cbstyledtextctrl.h>
48 #include <editor_hooks.h>
49 #include <filegroupsandmasks.h>
50 #include <multiselectdlg.h>
51 
52 #include "codecompletion.h"
53 
54 #include "ccoptionsdlg.h"
55 #include "ccoptionsprjdlg.h"
56 #include "insertclassmethoddlg.h"
57 #include "selectincludefile.h"
58 #include "parser/ccdebuginfo.h"
59 #include "parser/cclogger.h"
60 #include "parser/parser.h"
61 #include "parser/tokenizer.h"
62 #include "doxygen_parser.h" // for DocumentationPopup and DoxygenParser
63 #include "gotofunctiondlg.h"
64 
65 #define CC_CODECOMPLETION_DEBUG_OUTPUT 0
66 
67 // let the global debug macro overwrite the local debug macro value
68 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
69  #undef CC_CODECOMPLETION_DEBUG_OUTPUT
70  #define CC_CODECOMPLETION_DEBUG_OUTPUT CC_GLOBAL_DEBUG_OUTPUT
71 #endif
72 
73 #if CC_CODECOMPLETION_DEBUG_OUTPUT == 1
74  #define TRACE(format, args...) \
75  CCLogger::Get()->DebugLog(F(format, ##args))
76  #define TRACE2(format, args...)
77 #elif CC_CODECOMPLETION_DEBUG_OUTPUT == 2
78  #define TRACE(format, args...) \
79  do \
80  { \
81  if (g_EnableDebugTrace) \
82  CCLogger::Get()->DebugLog(F(format, ##args)); \
83  } \
84  while (false)
85  #define TRACE2(format, args...) \
86  CCLogger::Get()->DebugLog(F(format, ##args))
87 #else
88  #define TRACE(format, args...)
89  #define TRACE2(format, args...)
90 #endif
91 
93 static wxString g_GlobalScope(_T("<global>"));
94 
95 // this auto-registers the plugin
96 namespace
97 {
98  PluginRegistrant<CodeCompletion> reg(_T("CodeCompletion"));
99 }
100 
102 {
103  // compare method for the sort algorithm for our FunctionScope struct
105  {
106  int result = wxStricmp(fs1.Scope, fs2.Scope);
107  if (result == 0)
108  {
109  result = wxStricmp(fs1.Name, fs2.Name);
110  if (result == 0)
111  result = fs1.StartLine - fs2.StartLine;
112  }
113 
114  return result < 0;
115  }
116 
118  {
119  int result = wxStricmp(fs1.Scope, fs2.Scope);
120  if (result == 0)
121  result = wxStricmp(fs1.Name, fs2.Name);
122 
123  return result == 0;
124  }
125 
126  inline bool LessNameSpace(const NameSpace& ns1, const NameSpace& ns2)
127  {
128  return ns1.Name < ns2.Name;
129  }
130 
131  inline bool EqualNameSpace(const NameSpace& ns1, const NameSpace& ns2)
132  {
133  return ns1.Name == ns2.Name;
134  }
135 
142  inline wxChar GetLastNonWhitespaceChar(cbStyledTextCtrl* control, int position)
143  {
144  if (!control)
145  return 0;
146 
147  while (--position > 0)
148  {
149  const int style = control->GetStyleAt(position);
150  if (control->IsComment(style))
151  continue;
152 
153  const wxChar ch = control->GetCharAt(position);
154  if (ch <= _T(' '))
155  continue;
156 
157  return ch;
158  }
159 
160  return 0;
161  }
162 
167  inline wxChar GetNextNonWhitespaceChar(cbStyledTextCtrl* control, int position)
168  {
169  if (!control)
170  return 0;
171 
172  const int totalLength = control->GetLength();
173  --position;
174  while (++position < totalLength)
175  {
176  const int style = control->GetStyleAt(position);
177  if (control->IsComment(style))
178  continue;
179 
180  const wxChar ch = control->GetCharAt(position);
181  if (ch <= _T(' '))
182  continue;
183 
184  return ch;
185  }
186 
187  return 0;
188  }
189 
191  inline int CompareStringLen(const wxString& first, const wxString& second)
192  {
193  return second.Len() - first.Len();
194  }
195 
202  inline bool TestIncludeLine(wxString const &line)
203  {
204  size_t index = line.find(_T('#'));
205  if (index == wxString::npos)
206  return false;
207  ++index;
208 
209  for (; index < line.length(); ++index)
210  {
211  if (line[index] != _T(' ') && line[index] != _T('\t'))
212  {
213  if (line.Mid(index, 7) == _T("include"))
214  return true;
215  break;
216  }
217  }
218  return false;
219  }
220 
226  inline bool EditorHasNameUnderCursor(wxString& NameUnderCursor, bool& IsInclude)
227  {
228  bool ReturnValue = false;
229  if (cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor())
230  {
231  cbStyledTextCtrl* control = ed->GetControl();
232  const int pos = control->GetCurrentPos();
233  const wxString line = control->GetLine(control->LineFromPosition(pos));
234  const wxRegEx reg(_T("^[ \t]*#[ \t]*include[ \t]+[\"<]([^\">]+)[\">]"));
235  wxString inc;
236  if (reg.Matches(line))
237  inc = reg.GetMatch(line, 1);
238 
239  if (!inc.IsEmpty())
240  {
241  NameUnderCursor = inc;
242  ReturnValue = true;
243  IsInclude = true;
244  }
245  else
246  {
247  const int start = control->WordStartPosition(pos, true);
248  const int end = control->WordEndPosition(pos, true);
249  const wxString word = control->GetTextRange(start, end);
250  if (!word.IsEmpty())
251  {
252  NameUnderCursor.Clear();
253  NameUnderCursor << word;
254  ReturnValue = true;
255  IsInclude = false;
256  }
257  }
258  }
259  return ReturnValue;
260  }
263  {
265  unsigned line;
266  };
267 
274  static wxString AutocompGetName(const wxString& selected)
275  {
276  size_t nameEnd = selected.find_first_of(_T("(: "));
277  return selected.substr(0,nameEnd);
278  }
279 
280 }//namespace CodeCompletionHelper
281 
282 // empty bitmap for use as C++ keywords icon in code-completion list
283 /* XPM */
284 static const char * cpp_keyword_xpm[] = {
285 "16 16 2 1",
286 " c None",
287 ". c #04049B",
288 " ",
289 " ....... ",
290 " ......... ",
291 " .. .. ",
292 ".. ",
293 ".. .. .. ",
294 ".. .. .. ",
295 ".. ...... ......",
296 ".. ...... ......",
297 ".. .. .. ",
298 ".. .. .. ",
299 ".. .. ",
300 "... .. ",
301 " ......... ",
302 " ....... ",
303 " "};
304 
305 // bitmap for use as D keywords icon in code-completion list
306 /* XPM */
307 static const char *d_keyword_xpm[] = {
308 /* width height num_colors chars_per_pixel */
309 " 14 14 6 1",
310 /* colors */
311 " c none",
312 ". c #fefefe",
313 "# c #e43a3a",
314 "a c #e40000",
315 "b c #e48f8f",
316 "c c #8f0000",
317 /* pixels */
318 " ",
319 " ",
320 " .#aaaa#b. ",
321 " baabb#aa# ",
322 " ba# baa# ",
323 " ba# bcab ",
324 " ba# #a# ",
325 " ba# bac ",
326 " ba# ba# ",
327 " ba# bc# ",
328 " ba# #cb ",
329 " bcc ac# ",
330 " #aa###ac# ",
331 " cccccc#b "
332 };
333 
334 
335 // bitmap for other-than-C++ keywords
336 // it's pretty nice actually :)
337 /* XPM */
338 static const char * unknown_keyword_xpm[] = {
339 "16 16 7 1",
340 " c None",
341 ". c #FF8800",
342 "+ c #FF8D0B",
343 "@ c #FF9115",
344 "# c #FFA948",
345 "$ c #FFC686",
346 "% c #FFFFFF",
347 " ",
348 " ",
349 " .... ",
350 " ........ ",
351 " ..+@+..... ",
352 " .+#$#+.... ",
353 " ..@$%$@..... ",
354 " ..+#$#+..... ",
355 " ...+@+...... ",
356 " ............ ",
357 " .......... ",
358 " .......... ",
359 " ........ ",
360 " .... ",
361 " ",
362 " "};
363 
364 // bitmap for #include file listings
365 /* XPM */
366 static const char* header_file_xpm[] = {
367 "16 16 9 1",
368 " c None",
369 "+ c #D23E39",
370 "$ c #CF0C0A",
371 "@ c #CB524B",
372 "& c #E2D8D8",
373 "# c #C7C7C4",
374 "_ c #E4B9B5",
375 "- c #F7F9F7",
376 "= c #EBE9E7",
377 " ######### ",
378 " #=-----#### ",
379 " #--------=## ",
380 " #--------=-# ",
381 " #--=@_-----# ",
382 " #--=+_-----# ",
383 " #--=++@_---# ",
384 " #--&$@@$=--# ",
385 " #--&$__$&=-# ",
386 " #--&$__$&=-# ",
387 " #--&$__$&=-# ",
388 " #-==#=&#==-# ",
389 " #-========-# ",
390 " #----=====-# ",
391 " ############ ",
392 " "};
393 
394 // menu IDs
395 // just because we don't know other plugins' used identifiers,
396 // we use wxNewId() to generate a guaranteed unique ID ;), instead of enum
397 // (don't forget that, especially in a plugin)
398 // used in the wxFrame's main menu
399 int idMenuGotoFunction = wxNewId();
400 int idMenuGotoPrevFunction = wxNewId();
401 int idMenuGotoNextFunction = wxNewId();
402 int idMenuGotoDeclaration = wxNewId();
403 int idMenuGotoImplementation = wxNewId();
404 int idMenuOpenIncludeFile = wxNewId();
405 int idMenuFindReferences = wxNewId();
406 int idMenuRenameSymbols = wxNewId();
407 int idViewClassBrowser = wxNewId();
408 // used in context menu
409 int idCurrentProjectReparse = wxNewId();
410 int idSelectedProjectReparse = wxNewId();
411 int idSelectedFileReparse = wxNewId();
412 int idEditorSubMenu = wxNewId();
413 int idClassMethod = wxNewId();
414 int idUnimplementedClassMethods = wxNewId();
415 int idGotoDeclaration = wxNewId();
416 int idGotoImplementation = wxNewId();
417 int idOpenIncludeFile = wxNewId();
418 
419 int idRealtimeParsingTimer = wxNewId();
420 int idToolbarTimer = wxNewId();
421 int idProjectSavedTimer = wxNewId();
422 int idReparsingTimer = wxNewId();
423 int idEditorActivatedTimer = wxNewId();
424 
425 // all the below delay time is in milliseconds units
426 // when the user enables the parsing while typing option, this is the time delay when parsing
427 // would happen after the editor has changed.
428 #define REALTIME_PARSING_DELAY 500
429 
430 // there are many reasons to trigger the refreshing of CC toolbar. But to avoid refreshing
431 // the toolbar too often, we add a timer to delay the refresh, this is just like a mouse dwell
432 // event, which means we do the real job when the editor is stable for a while (no event
433 // happens in the delay time period).
434 #define TOOLBAR_REFRESH_DELAY 150
435 
436 // the time delay between an editor activated event and the updating of the CC toolbar.
437 // Note that we are only interest in a stable activated editor, so if another editor is activated
438 // during the time delay, the timer will be restarted.
439 #define EDITOR_ACTIVATED_DELAY 300
440 
441 BEGIN_EVENT_TABLE(CodeCompletion, cbCodeCompletionPlugin)
442  EVT_UPDATE_UI_RANGE(idMenuGotoFunction, idCurrentProjectReparse, CodeCompletion::OnUpdateUI)
443 
444  EVT_MENU(idMenuGotoFunction, CodeCompletion::OnGotoFunction )
445  EVT_MENU(idMenuGotoPrevFunction, CodeCompletion::OnGotoPrevFunction )
446  EVT_MENU(idMenuGotoNextFunction, CodeCompletion::OnGotoNextFunction )
447  EVT_MENU(idMenuGotoDeclaration, CodeCompletion::OnGotoDeclaration )
448  EVT_MENU(idMenuGotoImplementation, CodeCompletion::OnGotoDeclaration )
449  EVT_MENU(idMenuFindReferences, CodeCompletion::OnFindReferences )
450  EVT_MENU(idMenuRenameSymbols, CodeCompletion::OnRenameSymbols )
451  EVT_MENU(idClassMethod, CodeCompletion::OnClassMethod )
452  EVT_MENU(idUnimplementedClassMethods, CodeCompletion::OnUnimplementedClassMethods)
453  EVT_MENU(idGotoDeclaration, CodeCompletion::OnGotoDeclaration )
454  EVT_MENU(idGotoImplementation, CodeCompletion::OnGotoDeclaration )
455  EVT_MENU(idOpenIncludeFile, CodeCompletion::OnOpenIncludeFile )
456  EVT_MENU(idMenuOpenIncludeFile, CodeCompletion::OnOpenIncludeFile )
457 
458  EVT_MENU(idViewClassBrowser, CodeCompletion::OnViewClassBrowser )
459  EVT_MENU(idCurrentProjectReparse, CodeCompletion::OnCurrentProjectReparse )
460  EVT_MENU(idSelectedProjectReparse, CodeCompletion::OnSelectedProjectReparse)
461  EVT_MENU(idSelectedFileReparse, CodeCompletion::OnSelectedFileReparse )
462 
463  // CC's toolbar
464  EVT_CHOICE(XRCID("chcCodeCompletionScope"), CodeCompletion::OnScope )
465  EVT_CHOICE(XRCID("chcCodeCompletionFunction"), CodeCompletion::OnFunction)
466 END_EVENT_TABLE()
467 
469  m_InitDone(false),
470  m_CodeRefactoring(m_NativeParser),
471  m_EditorHookId(0),
472  m_TimerRealtimeParsing(this, idRealtimeParsingTimer),
473  m_TimerToolbar(this, idToolbarTimer),
474  m_TimerProjectSaved(this, idProjectSavedTimer),
475  m_TimerReparsing(this, idReparsingTimer),
476  m_TimerEditorActivated(this, idEditorActivatedTimer),
477  m_LastEditor(0),
478  m_ToolBar(0),
479  m_Function(0),
480  m_Scope(0),
481  m_ToolbarNeedRefresh(true),
482  m_ToolbarNeedReparse(false),
483  m_CurrentLine(0),
484  m_NeedReparse(false),
485  m_CurrentLength(-1),
486  m_NeedsBatchColour(true),
487  m_CCMaxMatches(16384),
488  m_CCAutoAddParentheses(true),
489  m_CCDetectImplementation(false),
490  m_CCEnableHeaders(false),
491  m_CCEnablePlatformCheck(true),
492  m_SystemHeadersThreadCS(),
493  m_DocHelper(this)
494 {
495  // CCLogger are the log event bridges, those events were finally handled by its parent, here
496  // it is the CodeCompletion plugin ifself.
498 
499  if (!Manager::LoadResource(_T("codecompletion.zip")))
500  NotifyMissingFile(_T("codecompletion.zip"));
501 
502  // handling events send from CCLogger
503  Connect(g_idCCLogger, wxEVT_COMMAND_MENU_SELECTED, CodeBlocksThreadEventHandler(CodeCompletion::OnCCLogger) );
505 
506  // the two events below were generated from NativeParser, as currently, CodeCompletionPlugin is
507  // set as the next event handler for m_NativeParser, so it get chance to handle them.
508  Connect(ParserCommon::idParserStart, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CodeCompletion::OnParserStart) );
509  Connect(ParserCommon::idParserEnd, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CodeCompletion::OnParserEnd) );
510 
511  Connect(idRealtimeParsingTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnRealtimeParsingTimer));
512  Connect(idToolbarTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnToolbarTimer) );
513  Connect(idProjectSavedTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnProjectSavedTimer) );
514  Connect(idReparsingTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnReparsingTimer) );
515  Connect(idEditorActivatedTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnEditorActivatedTimer));
516 
517  Connect(idSystemHeadersThreadMessage, wxEVT_COMMAND_MENU_SELECTED,
519  Connect(idSystemHeadersThreadFinish, wxEVT_COMMAND_MENU_SELECTED,
521 }
522 
524 {
525  Disconnect(g_idCCLogger, wxEVT_COMMAND_MENU_SELECTED, CodeBlocksThreadEventHandler(CodeCompletion::OnCCLogger));
526  Disconnect(g_idCCDebugLogger, wxEVT_COMMAND_MENU_SELECTED, CodeBlocksThreadEventHandler(CodeCompletion::OnCCDebugLogger));
527  Disconnect(ParserCommon::idParserStart, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CodeCompletion::OnParserStart));
528  Disconnect(ParserCommon::idParserEnd, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CodeCompletion::OnParserEnd));
529 
530  Disconnect(idRealtimeParsingTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnRealtimeParsingTimer));
531  Disconnect(idToolbarTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnToolbarTimer) );
532  Disconnect(idProjectSavedTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnProjectSavedTimer) );
533  Disconnect(idReparsingTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnReparsingTimer) );
534  Disconnect(idEditorActivatedTimer, wxEVT_TIMER, wxTimerEventHandler(CodeCompletion::OnEditorActivatedTimer));
535 
536  Disconnect(idSystemHeadersThreadMessage, wxEVT_COMMAND_MENU_SELECTED,
538  Disconnect(idSystemHeadersThreadFinish, wxEVT_COMMAND_MENU_SELECTED,
540 
541  // clean up all the running thread
542  while (!m_SystemHeadersThreads.empty())
543  {
544  SystemHeadersThread* thread = m_SystemHeadersThreads.front();
545  if (thread->IsAlive() && thread->IsRunning())
546  thread->Wait();
547  delete thread;
548  m_SystemHeadersThreads.pop_front();
549  }
550 }
551 
553 {
554  m_EditMenu = 0;
555  m_SearchMenu = 0;
556  m_ViewMenu = 0;
557  m_ProjectMenu = 0;
558  // toolbar related variables
559  m_ToolBar = 0;
560  m_Function = 0;
561  m_Scope = 0;
562  m_FunctionsScope.clear();
563  m_NameSpaces.clear();
564  m_AllFunctionsScopes.clear();
565  m_ToolbarNeedRefresh = true; // by default
566 
567  m_LastFile.clear();
568 
569  // read options from configure file
570  RereadOptions();
571 
572  // Events which m_NativeParser does not handle will go to the the next event
573  // handler which is the instance of a CodeCompletion.
574  m_NativeParser.SetNextHandler(this);
575 
576  m_NativeParser.CreateClassBrowser();
577 
578  // hook to editors
579  // both ccmanager and cc have hooks, but they don't conflict. ccmanager are mainly
580  // hooking to the event such as key stroke or mouse dwell events, so the code completion, call tip
581  // and tool tip will be handled in ccmanager. The other cases such as caret movement triggers
582  // updating the CC's toolbar, modifying the editor causing the real time content reparse will be
583  // handled inside cc's own editor hook.
585  m_EditorHookId = EditorHooks::RegisterHook(myhook);
586 
587  // register event sinks
588  Manager* pm = Manager::Get();
589 
591 
593 
600 
605 
606  m_DocHelper.OnAttach();
607 }
608 
609 void CodeCompletion::OnRelease(bool appShutDown)
610 {
611  m_NativeParser.RemoveClassBrowser(appShutDown);
612  m_NativeParser.ClearParsers();
613 
614  // remove chained handler
615  m_NativeParser.SetNextHandler(nullptr);
616 
617  // unregister hook
618  // 'true' will delete the functor too
619  EditorHooks::UnregisterHook(m_EditorHookId, true);
620 
621  // remove registered event sinks
623 
624  m_FunctionsScope.clear();
625  m_NameSpaces.clear();
626  m_AllFunctionsScopes.clear();
627  m_ToolbarNeedRefresh = false;
628 
629 /* TODO (mandrav#1#): Delete separator line too... */
630  if (m_EditMenu)
631  m_EditMenu->Delete(idMenuRenameSymbols);
632 
633  if (m_SearchMenu)
634  {
635  m_SearchMenu->Delete(idMenuGotoFunction);
636  m_SearchMenu->Delete(idMenuGotoPrevFunction);
637  m_SearchMenu->Delete(idMenuGotoNextFunction);
638  m_SearchMenu->Delete(idMenuGotoDeclaration);
639  m_SearchMenu->Delete(idMenuGotoImplementation);
640  m_SearchMenu->Delete(idMenuFindReferences);
641  m_SearchMenu->Delete(idMenuOpenIncludeFile);
642  }
643 
644  m_DocHelper.OnRelease();
645 }
646 
648 {
649  return new CCOptionsDlg(parent, &m_NativeParser, this, &m_DocHelper);
650 }
651 
653 {
654  return new CCOptionsProjectDlg(parent, project, &m_NativeParser);
655 }
656 
658 {
659  // if not attached, exit
660  if (!IsAttached())
661  return;
662 
663  int pos = menuBar->FindMenu(_("&Edit"));
664  if (pos != wxNOT_FOUND)
665  {
666  m_EditMenu = menuBar->GetMenu(pos);
667  m_EditMenu->AppendSeparator();
668  m_EditMenu->Append(idMenuRenameSymbols, _("Rename symbols\tAlt-N"));
669  }
670  else
671  CCLogger::Get()->DebugLog(_T("Could not find Edit menu!"));
672 
673  pos = menuBar->FindMenu(_("Sea&rch"));
674  if (pos != wxNOT_FOUND)
675  {
676  m_SearchMenu = menuBar->GetMenu(pos);
677  m_SearchMenu->Append(idMenuGotoFunction, _("Goto function...\tCtrl-Shift-G"));
678  m_SearchMenu->Append(idMenuGotoPrevFunction, _("Goto previous function\tCtrl-PgUp"));
679  m_SearchMenu->Append(idMenuGotoNextFunction, _("Goto next function\tCtrl-PgDn"));
680  m_SearchMenu->Append(idMenuGotoDeclaration, _("Goto declaration\tCtrl-Shift-."));
681  m_SearchMenu->Append(idMenuGotoImplementation, _("Goto implementation\tCtrl-."));
682  m_SearchMenu->Append(idMenuFindReferences, _("Find references\tAlt-."));
683  m_SearchMenu->Append(idMenuOpenIncludeFile, _("Open include file\tCtrl-Shift-."));
684  }
685  else
686  CCLogger::Get()->DebugLog(_T("Could not find Search menu!"));
687 
688  // add the classbrowser window in the "View" menu
689  int idx = menuBar->FindMenu(_("&View"));
690  if (idx != wxNOT_FOUND)
691  {
692  m_ViewMenu = menuBar->GetMenu(idx);
693  wxMenuItemList& items = m_ViewMenu->GetMenuItems();
694  bool inserted = false;
695 
696  // find the first separator and insert before it
697  for (size_t i = 0; i < items.GetCount(); ++i)
698  {
699  if (items[i]->IsSeparator())
700  {
701  m_ViewMenu->InsertCheckItem(i, idViewClassBrowser, _("Symbols browser"), _("Toggle displaying the symbols browser"));
702  inserted = true;
703  break;
704  }
705  }
706 
707  // not found, just append
708  if (!inserted)
709  m_ViewMenu->AppendCheckItem(idViewClassBrowser, _("Symbols browser"), _("Toggle displaying the symbols browser"));
710  }
711  else
712  CCLogger::Get()->DebugLog(_T("Could not find View menu!"));
713 
714  // add Reparse item in the "Project" menu
715  idx = menuBar->FindMenu(_("&Project"));
716  if (idx != wxNOT_FOUND)
717  {
718  m_ProjectMenu = menuBar->GetMenu(idx);
719  wxMenuItemList& items = m_ProjectMenu->GetMenuItems();
720  bool inserted = false;
721 
722  // find the first separator and insert before it
723  for (size_t i = items.GetCount() - 1; i > 0; --i)
724  {
725  if (items[i]->IsSeparator())
726  {
727  m_ProjectMenu->InsertSeparator(i);
728  m_ProjectMenu->Insert(i + 1, idCurrentProjectReparse, _("Reparse current project"), _("Reparse of the final switched project"));
729  inserted = true;
730  break;
731  }
732  }
733 
734  // not found, just append
735  if (!inserted)
736  {
737  m_ProjectMenu->AppendSeparator();
738  m_ProjectMenu->Append(idCurrentProjectReparse, _("Reparse current project"), _("Reparse of the final switched project"));
739  }
740  }
741  else
742  CCLogger::Get()->DebugLog(_T("Could not find Project menu!"));
743 }
744 
745 void CodeCompletion::BuildModuleMenu(const ModuleType type, wxMenu* menu, const FileTreeData* data)
746 {
747  // if not attached, exit
748  if (!menu || !IsAttached() || !m_InitDone)
749  return;
750 
751  if (type == mtEditorManager)
752  {
753  if (cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor())
754  {
755  if ( !IsProviderFor(ed) )
756  return;
757  }
758 
759  wxString NameUnderCursor;
760  bool IsInclude = false;
761  const bool nameUnderCursor = CodeCompletionHelper::EditorHasNameUnderCursor(NameUnderCursor, IsInclude);
762  if (nameUnderCursor)
763  {
764  PluginManager *pluginManager = Manager::Get()->GetPluginManager();
765 
766  if (IsInclude)
767  {
768  wxString msg;
769  msg.Printf(_("Open #include file: '%s'"), NameUnderCursor.wx_str());
770  menu->Insert(0, idOpenIncludeFile, msg);
772  pluginManager->RegisterFindMenuItems(true, 2);
773  }
774  else
775  {
776  int initialPos = pluginManager->GetFindMenuItemFirst();
777  int pos = initialPos;
778  wxString msg;
779  msg.Printf(_("Find declaration of: '%s'"), NameUnderCursor.wx_str());
780  menu->Insert(pos++, idGotoDeclaration, msg);
781 
782  msg.Printf(_("Find implementation of: '%s'"), NameUnderCursor.wx_str());
783  menu->Insert(pos++, idGotoImplementation, msg);
784 
785  if (m_NativeParser.GetParser().Done())
786  {
787  msg.Printf(_("Find references of: '%s'"), NameUnderCursor.wx_str());
788  menu->Insert(pos++, idMenuFindReferences, msg);
789  }
790  pluginManager->RegisterFindMenuItems(false, pos - initialPos);
791  }
792  }
793 
794  const int insertId = menu->FindItem(_("Insert/Refactor"));
795  if (insertId != wxNOT_FOUND)
796  {
797  if (wxMenuItem* insertMenu = menu->FindItem(insertId, 0))
798  {
799  if (wxMenu* subMenu = insertMenu->GetSubMenu())
800  {
801  subMenu->Append(idClassMethod, _("Class method declaration/implementation..."));
802  subMenu->Append(idUnimplementedClassMethods, _("All class methods without implementation..."));
803 
804  subMenu->AppendSeparator();
805 
806  const bool enableRename = (m_NativeParser.GetParser().Done() && nameUnderCursor && !IsInclude);
807  subMenu->Append(idMenuRenameSymbols, _("Rename symbols"), _("Rename symbols under cursor"));
808  subMenu->Enable(idMenuRenameSymbols, enableRename);
809  }
810  else
811  CCLogger::Get()->DebugLog(_T("Could not find Insert menu 3!"));
812  }
813  else
814  CCLogger::Get()->DebugLog(_T("Could not find Insert menu 2!"));
815  }
816  else
817  CCLogger::Get()->DebugLog(_T("Could not find Insert menu!"));
818  }
819  else if (type == mtProjectManager)
820  {
821  if (data)
822  {
823  if (data->GetKind() == FileTreeData::ftdkProject)
824  {
825  size_t position = menu->GetMenuItemCount();
826  int id = menu->FindItem(_("Build"));
827  if (id != wxNOT_FOUND)
828  menu->FindChildItem(id, &position);
829  menu->Insert(position, idSelectedProjectReparse, _("Reparse this project"),
830  _("Reparse current actived project"));
831  }
832  else if (data->GetKind() == FileTreeData::ftdkFile)
833  menu->Append(idSelectedFileReparse, _("Reparse this file"), _("Reparse current selected file"));
834  }
835  }
836 }
837 
839 {
840  // load the toolbar resource
841  Manager::Get()->AddonToolBar(toolBar,_T("codecompletion_toolbar"));
842  // get the wxChoice control pointers
843  m_Function = XRCCTRL(*toolBar, "chcCodeCompletionFunction", wxChoice);
844  m_Scope = XRCCTRL(*toolBar, "chcCodeCompletionScope", wxChoice);
845 
846  m_ToolBar = toolBar;
847 
848  // set the wxChoice and best toolbar size
849  UpdateToolBar();
850 
851  // disable the wxChoices
852  EnableToolbarTools(false);
853 
854  return true;
855 }
856 
858 {
859  EditorColourSet *colour_set = ed->GetColourSet();
860  if (colour_set && ed->GetLanguage() == colour_set->GetHighlightLanguage(wxT("C/C++")))
861  return ccpsActive;
862 
863  switch (ParserCommon::FileType(ed->GetFilename()))
864  {
867  return ccpsActive;
868 
870  default:
871  break;
872  }
873  return ccpsUniversal;
874 }
875 
876 std::vector<CodeCompletion::CCToken> CodeCompletion::GetAutocompList(bool isAuto, cbEditor* ed, int& tknStart, int& tknEnd)
877 {
878  std::vector<CCToken> tokens;
879 
880  if (!IsAttached() || !m_InitDone)
881  return tokens;
882 
883  cbStyledTextCtrl* stc = ed->GetControl();
884  const int style = stc->GetStyleAt(tknEnd);
885  const wxChar curChar = stc->GetCharAt(tknEnd - 1);
886 
887  if (isAuto) // filter illogical cases of auto-launch
888  {
889  // AutocompList can be prompt after user typed "::" or "->"
890  // or if in preprocessor directive, after user typed "<" or "\"" or "/"
891  if ( ( curChar == wxT(':') // scope operator
892  && stc->GetCharAt(tknEnd - 2) != wxT(':') )
893  || ( curChar == wxT('>') // '->'
894  && stc->GetCharAt(tknEnd - 2) != wxT('-') )
895  || ( wxString(wxT("<\"/")).Find(curChar) != wxNOT_FOUND // #include directive
896  && !stc->IsPreprocessor(style) ) )
897  {
898  return tokens;
899  }
900  }
901 
902  const int lineIndentPos = stc->GetLineIndentPosition(stc->GetCurrentLine());
903  const wxChar lineFirstChar = stc->GetCharAt(lineIndentPos);
904 
905  if (lineFirstChar == wxT('#'))
906  {
907  const int startPos = stc->WordStartPosition(lineIndentPos + 1, true);
908  const int endPos = stc->WordEndPosition(lineIndentPos + 1, true);
909  const wxString str = stc->GetTextRange(startPos, endPos);
910 
911  if (str == wxT("include") && tknEnd > endPos)
912  {
913  DoCodeCompleteIncludes(ed, tknStart, tknEnd, tokens);
914  }
915  else if (endPos >= tknEnd && tknEnd > lineIndentPos)
916  DoCodeCompletePreprocessor(tknStart, tknEnd, ed, tokens);
917  else if ( ( str == wxT("define")
918  || str == wxT("if")
919  || str == wxT("ifdef")
920  || str == wxT("ifndef")
921  || str == wxT("elif")
922  || str == wxT("elifdef")
923  || str == wxT("elifndef")
924  || str == wxT("undef") )
925  && tknEnd > endPos )
926  {
927  DoCodeComplete(tknEnd, ed, tokens, true);
928  }
929  return tokens;
930  }
931  else if (curChar == wxT('#'))
932  return tokens;
933  else if (lineFirstChar == wxT(':') && curChar == _T(':'))
934  return tokens;
935 
936  if ( stc->IsString(style)
937  || stc->IsComment(style)
938  || stc->IsCharacter(style)
939  || stc->IsPreprocessor(style) )
940  {
941  return tokens;
942  }
943 
944  DoCodeComplete(tknEnd, ed, tokens);
945  return tokens;
946 }
947 
948 void CodeCompletion::DoCodeComplete(int caretPos, cbEditor* ed, std::vector<CCToken>& tokens, bool preprocessorOnly)
949 {
950  const bool caseSens = m_NativeParser.GetParser().Options().caseSensitive;
951  cbStyledTextCtrl* stc = ed->GetControl();
952 
953  TokenIdxSet result;
954  if ( m_NativeParser.MarkItemsByAI(result, m_NativeParser.GetParser().Options().useSmartSense, true, caseSens, caretPos)
955  || m_NativeParser.LastAISearchWasGlobal() ) // enter even if no match (code-complete C++ keywords)
956  {
957  if (s_DebugSmartSense)
958  CCLogger::Get()->DebugLog(F(wxT("%lu results"), static_cast<unsigned long>(result.size())));
959  TRACE(F(wxT("%lu results"), static_cast<unsigned long>(result.size())));
960 
961  if (result.size() <= m_CCMaxMatches)
962  {
963  if (s_DebugSmartSense)
964  CCLogger::Get()->DebugLog(wxT("Generating tokens list..."));
965 
966  wxImageList* ilist = m_NativeParser.GetImageList();
967  stc->ClearRegisteredImages();
968 
969  tokens.reserve(result.size());
970  std::set<int> alreadyRegistered;
971  StringSet uniqueStrings; // ignore keywords with same name as parsed tokens
972 
973  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
974 
976 
977  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
978  {
979  const Token* token = tree->at(*it);
980  if (!token || token->m_Name.IsEmpty())
981  continue;
982 
983  if (preprocessorOnly && token->m_TokenKind != tkMacroDef)
984  continue;
985 
986  int iidx = m_NativeParser.GetTokenKindImage(token);
987  if (alreadyRegistered.find(iidx) == alreadyRegistered.end())
988  {
989  stc->RegisterImage(iidx, ilist->GetBitmap(iidx));
990  alreadyRegistered.insert(iidx);
991  }
992 
993  wxString dispStr;
994  if (token->m_TokenKind & tkAnyFunction)
995  {
996  if (m_DocHelper.IsEnabled())
997  dispStr = wxT("(): ") + token->m_FullType;
998  else
999  dispStr = token->GetFormattedArgs() << _T(": ") << token->m_FullType;
1000  }
1001  else if (token->m_TokenKind == tkVariable)
1002  dispStr = wxT(": ") + token->m_FullType;
1003  tokens.push_back(CCToken(token->m_Index, token->m_Name + dispStr, token->m_Name, token->m_IsTemp ? 0 : 5, iidx));
1004  uniqueStrings.insert(token->m_Name);
1005 
1006  if (token->m_TokenKind == tkNamespace && token->m_Aliases.size())
1007  {
1008  for (size_t i = 0; i < token->m_Aliases.size(); ++i)
1009  {
1010  // dispStr will currently be empty, but contain something in the future...
1011  tokens.push_back(CCToken(token->m_Index, token->m_Aliases[i] + dispStr, token->m_Aliases[i], 5, iidx));
1012  uniqueStrings.insert(token->m_Aliases[i]);
1013  }
1014  }
1015  }
1016 
1018 
1019  if (m_NativeParser.LastAISearchWasGlobal() && !preprocessorOnly)
1020  {
1021  // empty or partial search phrase: add theme keywords in search list
1022  if (s_DebugSmartSense)
1023  CCLogger::Get()->DebugLog(_T("Last AI search was global: adding theme keywords in list"));
1024 
1025  EditorColourSet* colour_set = ed->GetColourSet();
1026  if (colour_set)
1027  {
1028  wxString lastSearch = m_NativeParser.LastAIGlobalSearch().Lower();
1029  int iidx = ilist->GetImageCount();
1030  FileType fTp = FileTypeOf(ed->GetShortName());
1031  bool isC = (fTp == ftHeader || fTp == ftSource|| fTp == ftTemplateSource);
1032  // theme keywords
1033  HighlightLanguage lang = ed->GetLanguage();
1034  if (lang == HL_NONE)
1035  lang = colour_set->GetLanguageForFilename(ed->GetFilename());
1036  wxString strLang = colour_set->GetLanguageName(lang);
1037  // if its sourcecode/header file and a known fileformat, show the corresponding icon
1038  if (isC && strLang == wxT("C/C++"))
1039  stc->RegisterImage(iidx, wxBitmap(cpp_keyword_xpm));
1040  else if (isC && strLang == wxT("D"))
1041  stc->RegisterImage(iidx, wxBitmap(d_keyword_xpm));
1042  else
1043  stc->RegisterImage(iidx, wxBitmap(unknown_keyword_xpm));
1044  // the first two keyword sets are the primary and secondary keywords (for most lexers at least)
1045  // but this is now configurable in global settings
1046  for (int i = 0; i <= wxSCI_KEYWORDSET_MAX; ++i)
1047  {
1048  if (!m_LexerKeywordsToInclude[i])
1049  continue;
1050 
1051  wxString keywords = colour_set->GetKeywords(lang, i);
1052  wxStringTokenizer tkz(keywords, wxT(" \t\r\n"), wxTOKEN_STRTOK);
1053  while (tkz.HasMoreTokens())
1054  {
1055  wxString kw = tkz.GetNextToken();
1056  if ( kw.Lower().StartsWith(lastSearch)
1057  && uniqueStrings.find(kw) == uniqueStrings.end() )
1058  {
1059  tokens.push_back(CCToken(wxNOT_FOUND, kw, iidx));
1060  }
1061  }
1062  }
1063  }
1064  }
1065  }
1066  else if (!stc->CallTipActive())
1067  {
1068  wxString msg = _("Too many results.\n"
1069  "Please edit results' limit in code-completion options,\n"
1070  "or type at least one more character to narrow the scope down.");
1071  stc->CallTipShow(stc->GetCurrentPos(), msg);
1072  }
1073  }
1074  else if (!stc->CallTipActive())
1075  {
1076  if (s_DebugSmartSense)
1077  CCLogger::Get()->DebugLog(wxT("0 results"));
1078 
1079  if (!m_NativeParser.GetParser().Done())
1080  {
1081  wxString msg = _("The Parser is still parsing files.");
1082  stc->CallTipShow(stc->GetCurrentPos(), msg);
1083  msg += m_NativeParser.GetParser().NotDoneReason();
1084  CCLogger::Get()->DebugLog(msg);
1085  }
1086  }
1087 }
1088 
1089 void CodeCompletion::DoCodeCompletePreprocessor(int tknStart, int tknEnd, cbEditor* ed, std::vector<CCToken>& tokens)
1090 {
1091  cbStyledTextCtrl* stc = ed->GetControl();
1092  if (stc->GetLexer() != wxSCI_LEX_CPP)
1093  {
1094  const FileType fTp = FileTypeOf(ed->GetShortName());
1095  if ( fTp != ftSource
1096  && fTp != ftHeader
1097  && fTp != ftTemplateSource
1098  && fTp != ftResource )
1099  {
1100  return; // not C/C++
1101  }
1102  }
1103  const wxString text = stc->GetTextRange(tknStart, tknEnd);
1104 
1105  wxStringVec macros;
1106  macros.push_back(wxT("define"));
1107  macros.push_back(wxT("elif"));
1108  macros.push_back(wxT("elifdef"));
1109  macros.push_back(wxT("elifndef"));
1110  macros.push_back(wxT("else"));
1111  macros.push_back(wxT("endif"));
1112  macros.push_back(wxT("error"));
1113  macros.push_back(wxT("if"));
1114  macros.push_back(wxT("ifdef"));
1115  macros.push_back(wxT("ifndef"));
1116  macros.push_back(wxT("include"));
1117  macros.push_back(wxT("line"));
1118  macros.push_back(wxT("pragma"));
1119  macros.push_back(wxT("undef"));
1120  const wxString idxStr = F(wxT("\n%d"), PARSER_IMG_MACRO_DEF);
1121  for (size_t i = 0; i < macros.size(); ++i)
1122  {
1123  if (text.IsEmpty() || macros[i][0] == text[0]) // ignore tokens that start with a different letter
1124  tokens.push_back(CCToken(wxNOT_FOUND, macros[i], PARSER_IMG_MACRO_DEF));
1125  }
1126  stc->ClearRegisteredImages();
1128  m_NativeParser.GetImageList()->GetBitmap(PARSER_IMG_MACRO_DEF));
1129 }
1130 
1131 void CodeCompletion::DoCodeCompleteIncludes(cbEditor* ed, int& tknStart, int tknEnd, std::vector<CCToken>& tokens)
1132 {
1133  if (!m_CCEnableHeaders)
1134  return;
1135 
1136  const wxString curFile(ed->GetFilename());
1137  const wxString curPath(wxFileName(curFile).GetPath());
1138 
1139  FileType ft = FileTypeOf(ed->GetShortName());
1140  if ( ft != ftHeader && ft != ftSource && ft != ftTemplateSource) // only parse source/header files
1141  return;
1142 
1143  cbStyledTextCtrl* stc = ed->GetControl();
1144  const int lineStartPos = stc->PositionFromLine(stc->GetCurrentLine());
1145  wxString line = stc->GetCurLine();
1146  line.Trim();
1147  if (line.IsEmpty() || !CodeCompletionHelper::TestIncludeLine(line))
1148  return;
1149 
1150  int keyPos = line.Find(wxT('"'));
1151  if (keyPos == wxNOT_FOUND || keyPos >= tknEnd - lineStartPos)
1152  keyPos = line.Find(wxT('<'));
1153  if (keyPos == wxNOT_FOUND || keyPos >= tknEnd - lineStartPos)
1154  return;
1155  ++keyPos;
1156 
1157  // now, we are after the quote prompt, "filename" is the text we already typed after the
1158  // #include directive, such as #include <abc| , so that we need to prompt all the header files
1159  // which has the prefix "abc"
1160  wxString filename = line.SubString(keyPos, tknEnd - lineStartPos - 1);
1161  filename.Replace(wxT("\\"), wxT("/"), true);
1162  if (!filename.empty() && (filename.Last() == wxT('"') || filename.Last() == wxT('>')))
1163  filename.RemoveLast();
1164 
1165  size_t maxFiles = m_CCMaxMatches;
1166  if (filename.IsEmpty() && maxFiles > 3000)
1167  maxFiles = 3000; // do not try to collect too many files if there is no context (prevent hang)
1168 
1169  // fill a list of matching files
1170  StringSet files;
1171 
1172  cbProject* project = m_NativeParser.GetProjectByEditor(ed);
1173 
1174  // since we are going to access the m_SystemHeadersMap, we add a locker here
1175  // here we collect all the header files names which is under "system include search dirs"
1176 #if wxCHECK_VERSION(3, 0, 0)
1177  if (m_SystemHeadersThreadCS.TryEnter())
1178  {
1179 #else
1180  {
1181  m_SystemHeadersThreadCS.Enter();
1182 #endif // wxCHECK_VERSION(3, 0, 0)
1183  // if the project get modified, fetch the dirs again, otherwise, use cached dirs
1184  wxArrayString& incDirs = GetSystemIncludeDirs(project, project ? project->GetModified() : true);
1185  for (size_t i = 0; i < incDirs.GetCount(); ++i)
1186  {
1187  // shm_it means system_header_map_iterator
1188  SystemHeadersMap::const_iterator shm_it = m_SystemHeadersMap.find(incDirs[i]);
1189  if (shm_it != m_SystemHeadersMap.end())
1190  {
1191  const StringSet& headers = shm_it->second;
1192  for (StringSet::const_iterator ss_it = headers.begin(); ss_it != headers.end(); ++ss_it)
1193  {
1194  const wxString& file = *ss_it;
1195  // if find a value matches already typed "filename", add to the result
1196  if (file.StartsWith(filename))
1197  {
1198  files.insert(file);
1199  if (files.size() > maxFiles)
1200  break; // exit inner loop
1201  }
1202  }
1203  if (files.size() > maxFiles)
1204  break; // exit outer loop
1205  }
1206  }
1207  m_SystemHeadersThreadCS.Leave();
1208  }
1209 
1210  // #include "
1211  if (project)
1212  {
1213 #if wxCHECK_VERSION(3, 0, 0)
1214  if (m_SystemHeadersThreadCS.TryEnter())
1215  {
1216 #else
1217  {
1218  m_SystemHeadersThreadCS.Enter();
1219 #endif // wxCHECK_VERSION(3, 0, 0)
1220  wxArrayString buildTargets;
1221  ProjectFile* pf = project ? project->GetFileByFilename(curFile, false) : 0;
1222  if (pf)
1223  buildTargets = pf->buildTargets;
1224 
1225  const wxArrayString localIncludeDirs = GetLocalIncludeDirs(project, buildTargets);
1226  for (FilesList::const_iterator it = project->GetFilesList().begin();
1227  it != project->GetFilesList().end(); ++it)
1228  {
1229  pf = *it;
1230  if (pf && FileTypeOf(pf->relativeFilename) == ftHeader)
1231  {
1232  wxString file = pf->file.GetFullPath();
1233  wxString header;
1234  for (size_t j = 0; j < localIncludeDirs.GetCount(); ++j)
1235  {
1236  const wxString& dir = localIncludeDirs[j];
1237  if (file.StartsWith(dir))
1238  {
1239  header = file.Mid(dir.Len());
1240  header.Replace(wxT("\\"), wxT("/"));
1241  break;
1242  }
1243  }
1244 
1245  if (header.IsEmpty())
1246  {
1247  if (pf->buildTargets != buildTargets)
1248  continue;
1249 
1250  wxFileName fn(file);
1251  fn.MakeRelativeTo(curPath);
1252  header = fn.GetFullPath(wxPATH_UNIX);
1253  }
1254 
1255  if (header.StartsWith(filename))
1256  {
1257  files.insert(header);
1258  if (files.size() > maxFiles)
1259  break;
1260  }
1261  }
1262  }
1263  m_SystemHeadersThreadCS.Leave();
1264  }
1265  }
1266 
1267  if (!files.empty())
1268  {
1269  tknStart = lineStartPos + keyPos;
1270  tokens.reserve(files.size());
1271  for (StringSet::const_iterator ssIt = files.begin(); ssIt != files.end(); ++ssIt)
1272  tokens.push_back(CCToken(wxNOT_FOUND, *ssIt, 0));
1273  stc->ClearRegisteredImages();
1274  stc->RegisterImage(0, wxBitmap(header_file_xpm));
1275  }
1276 }
1277 
1278 std::vector<CodeCompletion::CCCallTip> CodeCompletion::GetCallTips(int pos, int style, cbEditor* ed, int& argsPos)
1279 {
1280  std::vector<CCCallTip> tips;
1281  if (!IsAttached() || !m_InitDone || style == wxSCI_C_WXSMITH || !m_NativeParser.GetParser().Done())
1282  return tips;
1283 
1284  int typedCommas = 0;
1285  wxArrayString items;
1286  argsPos = m_NativeParser.GetCallTips(items, typedCommas, ed, pos);
1287  StringSet uniqueTips; // check against this before inserting a new tip in the list
1288  for (size_t i = 0; i < items.GetCount(); ++i)
1289  {
1290  // allow only unique, non-empty items with equal or more commas than what the user has already typed
1291  if ( uniqueTips.find(items[i]) == uniqueTips.end() // unique
1292  && !items[i].IsEmpty() // non-empty
1293  && typedCommas <= m_NativeParser.CountCommas(items[i], 0) ) // commas satisfied
1294  {
1295  uniqueTips.insert(items[i]);
1296  int hlStart = wxSCI_INVALID_POSITION;
1297  int hlEnd = wxSCI_INVALID_POSITION;
1298  m_NativeParser.GetCallTipHighlight(items[i], &hlStart, &hlEnd, typedCommas);
1299  tips.push_back(CCCallTip(items[i], hlStart, hlEnd));
1300  }
1301  }
1302  return tips;
1303 }
1304 
1306 {
1307  return m_DocHelper.GenerateHTML(token.id, m_NativeParser.GetParser().GetTokenTree());
1308 }
1309 
1310 std::vector<CodeCompletion::CCToken> CodeCompletion::GetTokenAt(int pos, cbEditor* ed, bool& WXUNUSED(allowCallTip))
1311 {
1312  std::vector<CCToken> tokens;
1313  if (!IsAttached() || !m_InitDone)
1314  return tokens;
1315 
1316  // ignore comments, strings, preprocessors, etc
1317  cbStyledTextCtrl* stc = ed->GetControl();
1318  const int style = stc->GetStyleAt(pos);
1319  if ( stc->IsString(style)
1320  || stc->IsComment(style)
1321  || stc->IsCharacter(style)
1322  || stc->IsPreprocessor(style) )
1323  {
1324  return tokens;
1325  }
1326 
1327  TokenIdxSet result;
1328  int endOfWord = stc->WordEndPosition(pos, true);
1329  if (m_NativeParser.MarkItemsByAI(result, true, false, true, endOfWord))
1330  {
1331  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
1332 
1334 
1335  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
1336  {
1337  const Token* token = tree->at(*it);
1338  if (token)
1339  {
1340  tokens.push_back(CCToken(*it, token->DisplayName()));
1341  if (tokens.size() > 32)
1342  break;
1343  }
1344  }
1345 
1347  }
1348 
1349  return tokens;
1350 }
1351 
1352 wxString CodeCompletion::OnDocumentationLink(wxHtmlLinkEvent& event, bool& dismissPopup)
1353 {
1354  return m_DocHelper.OnDocumentationLink(event, dismissPopup);
1355 }
1356 
1358 {
1360  cbStyledTextCtrl* stc = ed->GetControl();
1361 
1362  int curPos = stc->GetCurrentPos();
1363  int startPos = stc->WordStartPosition(curPos, true);
1364  if ( itemText.GetChar(0) == _T('~') // special handle for dtor
1365  && startPos > 0
1366  && stc->GetCharAt(startPos - 1) == _T('~'))
1367  {
1368  --startPos;
1369  }
1370  bool needReparse = false;
1371 
1372  if (stc->IsPreprocessor(stc->GetStyleAt(curPos)))
1373  {
1374  curPos = stc->GetLineEndPosition(stc->GetCurrentLine()); // delete rest of line
1375  bool addComment = (itemText == wxT("endif"));
1376  for (int i = stc->GetCurrentPos(); i < curPos; ++i)
1377  {
1378  if (stc->IsComment(stc->GetStyleAt(i)))
1379  {
1380  curPos = i; // preserve line comment
1381  if (wxIsspace(stc->GetCharAt(i - 1)))
1382  --curPos; // preserve a space before the comment
1383  addComment = false;
1384  break;
1385  }
1386  }
1387  if (addComment) // search backwards for the #if*
1388  {
1389  wxRegEx ppIf(wxT("^[ \t]*#[ \t]*if"));
1390  wxRegEx ppEnd(wxT("^[ \t]*#[ \t]*endif"));
1391  int depth = -1;
1392  for (int ppLine = stc->GetCurrentLine() - 1; ppLine >= 0; --ppLine)
1393  {
1394  if (stc->GetLine(ppLine).Find(wxT('#')) != wxNOT_FOUND) // limit testing due to performance cost
1395  {
1396  if (ppIf.Matches(stc->GetLine(ppLine))) // ignore else's, elif's, ...
1397  ++depth;
1398  else if (ppEnd.Matches(stc->GetLine(ppLine)))
1399  --depth;
1400  }
1401  if (depth == 0)
1402  {
1403  wxRegEx pp(wxT("^[ \t]*#[ \t]*[a-z]*([ \t]+([a-zA-Z0-9_]+)|())"));
1404  pp.Matches(stc->GetLine(ppLine));
1405  if (!pp.GetMatch(stc->GetLine(ppLine), 2).IsEmpty())
1406  itemText.Append(wxT(" // ") + pp.GetMatch(stc->GetLine(ppLine), 2));
1407  break;
1408  }
1409  }
1410  }
1411  needReparse = true;
1412 
1413  int pos = startPos - 1;
1414  wxChar ch = stc->GetCharAt(pos);
1415  while (ch != _T('<') && ch != _T('"') && ch != _T('#') && (pos>0))
1416  ch = stc->GetCharAt(--pos);
1417  if (ch == _T('<') || ch == _T('"'))
1418  startPos = pos + 1;
1419 
1420  if (ch == _T('"'))
1421  itemText << _T('"');
1422  else if (ch == _T('<'))
1423  itemText << _T('>');
1424  }
1425  else
1426  {
1427  const int endPos = stc->WordEndPosition(curPos, true);
1428  const wxString& alreadyText = stc->GetTextRange(curPos, endPos);
1429  if (!alreadyText.IsEmpty() && itemText.EndsWith(alreadyText))
1430  curPos = endPos;
1431  }
1432 
1433  int positionModificator = 0;
1434  bool insideParentheses = false;
1435  if (token.id != -1 && m_CCAutoAddParentheses)
1436  {
1437  CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1438 
1439  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
1440  const Token* tkn = tree->at(token.id);
1441 
1442  if (!tkn)
1443  { CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex) }
1444  else
1445  {
1446  bool addParentheses = tkn->m_TokenKind & tkAnyFunction;
1447  if (!addParentheses && (tkn->m_TokenKind & tkMacroDef))
1448  {
1449  if (tkn->m_Args.size() > 0)
1450  addParentheses = true;
1451  }
1452  // cache args to avoid locking
1453  wxString tokenArgs = tkn->GetStrippedArgs();
1454 
1455  CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1456 
1457  if (addParentheses)
1458  {
1459  bool insideFunction = true;
1460  if (m_CCDetectImplementation)
1461  {
1462  ccSearchData searchData = { stc, ed->GetFilename() };
1463  int funcToken;
1464  if (m_NativeParser.FindCurrentFunctionStart(&searchData, 0, 0, &funcToken) == -1)
1465  {
1466  // global scope
1467  itemText += tokenArgs;
1468  insideFunction = false;
1469  }
1470  else // Found something, but result may be false positive.
1471  {
1472  CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1473 
1474  const Token* parent = tree->at(funcToken);
1475  // Make sure that parent is not container (class, etc)
1476  if (parent && (parent->m_TokenKind & tkAnyFunction) == 0)
1477  {
1478  // class scope
1479  itemText += tokenArgs;
1480  insideFunction = false;
1481  }
1482 
1483  CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1484  }
1485  }
1486 
1487  if (insideFunction)
1488  {
1489  // Inside block
1490  // Check if there are brace behind the target
1491  if (stc->GetCharAt(curPos) != _T('('))
1492  {
1493  itemText += _T("()");
1494  if (tokenArgs.size() > 2) // more than '()'
1495  {
1496  positionModificator = -1;
1497  insideParentheses = true;
1498  }
1499  }
1500  else
1501  positionModificator = 1; // Set caret after '('
1502  }
1503  }
1504  } // if tkn
1505  } // if token.id
1506 
1507  stc->SetTargetStart(startPos);
1508  stc->SetTargetEnd(curPos);
1509 
1510  stc->AutoCompCancel();
1511  if (stc->GetTextRange(startPos, curPos) != itemText)
1512  stc->ReplaceTarget(itemText);
1513  stc->GotoPos(startPos + itemText.Length() + positionModificator);
1514 
1515  if (insideParentheses)
1516  {
1517  stc->EnableTabSmartJump();
1518  int tooltipMode = Manager::Get()->GetConfigManager(wxT("ccmanager"))->ReadInt(wxT("/tooltip_mode"), 1);
1519  if (tooltipMode != 3) // keybound only
1520  {
1521  CodeBlocksEvent evt(cbEVT_SHOW_CALL_TIP);
1522  Manager::Get()->ProcessEvent(evt);
1523  }
1524  }
1525 
1526  if (needReparse)
1527  {
1528  TRACE(_T("CodeCompletion::EditorEventHook: Starting m_TimerRealtimeParsing."));
1529  m_TimerRealtimeParsing.Start(1, wxTIMER_ONE_SHOT);
1530  }
1531  stc->ChooseCaretX();
1532 }
1533 
1534 wxArrayString CodeCompletion::GetLocalIncludeDirs(cbProject* project, const wxArrayString& buildTargets)
1535 {
1536  wxArrayString dirs;
1537  // Do not try to operate include directories if the project is not for this platform
1538  if (m_CCEnablePlatformCheck && !project->SupportsCurrentPlatform())
1539  return dirs;
1540  // add project level compiler include search paths
1541  const wxString prjPath = project->GetCommonTopLevelPath();
1542  GetAbsolutePath(prjPath, project->GetIncludeDirs(), dirs);
1543  // add target level compiler include search paths
1544  for (size_t i = 0; i < buildTargets.GetCount(); ++i)
1545  {
1546  ProjectBuildTarget* tgt = project->GetBuildTarget(buildTargets[i]);
1547  // Do not try to operate include directories if the target is not for this platform
1548  if ( !m_CCEnablePlatformCheck || tgt->SupportsCurrentPlatform() )
1549  {
1550  GetAbsolutePath(prjPath, tgt->GetIncludeDirs(), dirs);
1551  }
1552  }
1553 
1554  // if a path has prefix with the project's path, it is a local include search dir
1555  // other wise, it is a system level include search dir, we try to collect all the system dirs
1556  wxArrayString sysDirs;
1557  for (size_t i = 0; i < dirs.GetCount();)
1558  {
1559  // if the dir with the prefix of project path, then it is a "local dir"
1560  if (dirs[i].StartsWith(prjPath))
1561  ++i;
1562  else // otherwise, it is a "system dir", so add to "sysDirs"
1563  {
1564  if (m_SystemHeadersMap.find(dirs[i]) == m_SystemHeadersMap.end())
1565  sysDirs.Add(dirs[i]);
1566  // remove the system dir in dirs
1567  dirs.RemoveAt(i);
1568  }
1569  }
1570 
1571  if (!sysDirs.IsEmpty())
1572  {
1573  // create a worker thread associate with "sysDirs", then put it in a queue.
1574  SystemHeadersThread* thread = new SystemHeadersThread(this, &m_SystemHeadersThreadCS,
1575  m_SystemHeadersMap, sysDirs);
1576  m_SystemHeadersThreads.push_back(thread);
1577  // if the batch parsing is done, and no system header scanning thread is running
1578  // just run it, other wise, this thread will run after the batch thread finishes.
1579  if (!m_SystemHeadersThreads.front()->IsRunning() && m_NativeParser.Done())
1580  thread->Run();
1581  }
1582 
1584  return dirs; //return all the local dirs
1585 }
1586 
1588 {
1589  static cbProject* lastProject = nullptr;
1590  static wxArrayString incDirs;
1591 
1592  if (!force && project == lastProject) // force == false means we can use the cached dirs
1593  return incDirs;
1594  else
1595  {
1596  incDirs.Clear();
1597  lastProject = project;
1598  }
1599 
1600  wxString prjPath;
1601  if (project)
1602  prjPath = project->GetCommonTopLevelPath();
1603 
1604  ParserBase* parser = m_NativeParser.GetParserByProject(project);
1605  if (!parser)
1606  return incDirs;
1607 
1608  incDirs = parser->GetIncludeDirs();
1609  // we try to remove the dirs which belong to the project
1610  for (size_t i = 0; i < incDirs.GetCount();)
1611  {
1612  if (incDirs[i].Last() != wxFILE_SEP_PATH)
1613  incDirs[i].Append(wxFILE_SEP_PATH);
1614  // the dirs which have prjPath prefix are local dirs, so they should be removed
1615  if (project && incDirs[i].StartsWith(prjPath))
1616  incDirs.RemoveAt(i);
1617  else
1618  ++i;
1619  }
1620 
1621  return incDirs;
1622 }
1623 
1624 void CodeCompletion::GetAbsolutePath(const wxString& basePath, const wxArrayString& targets, wxArrayString& dirs)
1625 {
1626  for (size_t i = 0; i < targets.GetCount(); ++i)
1627  {
1628  wxString includePath = targets[i];
1629  Manager::Get()->GetMacrosManager()->ReplaceMacros(includePath);
1630  wxFileName fn(includePath, wxEmptyString);
1631  if (fn.IsRelative())
1632  {
1633  const wxArrayString oldDirs = fn.GetDirs();
1634  fn.SetPath(basePath);
1635  for (size_t j = 0; j < oldDirs.GetCount(); ++j)
1636  fn.AppendDir(oldDirs[j]);
1637  }
1638 
1639  // Detect if this directory is for the file system root and skip it. Sometimes macro
1640  // replacements create such paths and we don't want to scan whole disks because of this.
1641  if (fn.IsAbsolute() && fn.GetDirCount() == 0)
1642  continue;
1643 
1644  const wxString path = fn.GetFullPath();
1645  if (dirs.Index(path) == wxNOT_FOUND)
1646  dirs.Add(path);
1647  }
1648 }
1649 
1651 {
1652  if (!IsAttached() || !m_InitDone)
1653  {
1654  event.Skip();
1655  return;
1656  }
1657 
1658  if ( !IsProviderFor(editor) )
1659  {
1660  event.Skip();
1661  return;
1662  }
1663 
1664  cbStyledTextCtrl* control = editor->GetControl();
1665 
1666  if (event.GetEventType() == wxEVT_SCI_CHARADDED)
1667  { TRACE(_T("wxEVT_SCI_CHARADDED")); }
1668  else if (event.GetEventType() == wxEVT_SCI_CHANGE)
1669  { TRACE(_T("wxEVT_SCI_CHANGE")); }
1670  else if (event.GetEventType() == wxEVT_SCI_MODIFIED)
1671  { TRACE(_T("wxEVT_SCI_MODIFIED")); }
1672  else if (event.GetEventType() == wxEVT_SCI_AUTOCOMP_SELECTION)
1673  { TRACE(_T("wxEVT_SCI_AUTOCOMP_SELECTION")); }
1674  else if (event.GetEventType() == wxEVT_SCI_AUTOCOMP_CANCELLED)
1675  { TRACE(_T("wxEVT_SCI_AUTOCOMP_CANCELLED")); }
1676 
1677  // if the user is modifying the editor, then CC should try to reparse the editor's content
1678  // and update the token tree.
1679  if ( m_NativeParser.GetParser().Options().whileTyping
1680  && ( (event.GetModificationType() & wxSCI_MOD_INSERTTEXT)
1681  || (event.GetModificationType() & wxSCI_MOD_DELETETEXT) ) )
1682  {
1683  m_NeedReparse = true;
1684  }
1685 
1686  if (control->GetCurrentLine() != m_CurrentLine)
1687  {
1688  // reparsing the editor only happens in the condition that the caret's line number
1689  // is changed.
1690  if (m_NeedReparse)
1691  {
1692  TRACE(_T("CodeCompletion::EditorEventHook: Starting m_TimerRealtimeParsing."));
1693  m_TimerRealtimeParsing.Start(REALTIME_PARSING_DELAY, wxTIMER_ONE_SHOT);
1694  m_CurrentLength = control->GetLength();
1695  m_NeedReparse = false;
1696  }
1697  // wxEVT_SCI_UPDATEUI will be sent on caret's motion, but we are only interested in the
1698  // cases where line number is changed. Then we need to update the CC's toolbar.
1699  if (event.GetEventType() == wxEVT_SCI_UPDATEUI)
1700  {
1701  m_ToolbarNeedRefresh = true;
1702  TRACE(_T("CodeCompletion::EditorEventHook: Starting m_TimerToolbar."));
1703  if (m_TimerEditorActivated.IsRunning())
1704  m_TimerToolbar.Start(EDITOR_ACTIVATED_DELAY + 1, wxTIMER_ONE_SHOT);
1705  else
1706  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
1707  }
1708  }
1709 
1710  // allow others to handle this event
1711  event.Skip();
1712 }
1713 
1715 {
1716  // Keep this in sync with CCOptionsDlg::CCOptionsDlg and CCOptionsDlg::OnApply
1717 
1718  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
1719 
1720  m_LexerKeywordsToInclude[0] = cfg->ReadBool(_T("/lexer_keywords_set1"), true);
1721  m_LexerKeywordsToInclude[1] = cfg->ReadBool(_T("/lexer_keywords_set2"), true);
1722  m_LexerKeywordsToInclude[2] = cfg->ReadBool(_T("/lexer_keywords_set3"), false);
1723  m_LexerKeywordsToInclude[3] = cfg->ReadBool(_T("/lexer_keywords_set4"), false);
1724  m_LexerKeywordsToInclude[4] = cfg->ReadBool(_T("/lexer_keywords_set5"), false);
1725  m_LexerKeywordsToInclude[5] = cfg->ReadBool(_T("/lexer_keywords_set6"), false);
1726  m_LexerKeywordsToInclude[6] = cfg->ReadBool(_T("/lexer_keywords_set7"), false);
1727  m_LexerKeywordsToInclude[7] = cfg->ReadBool(_T("/lexer_keywords_set8"), false);
1728  m_LexerKeywordsToInclude[8] = cfg->ReadBool(_T("/lexer_keywords_set9"), false);
1729 
1730  // for CC
1731  m_CCMaxMatches = cfg->ReadInt(_T("/max_matches"), 16384);
1732  m_CCAutoAddParentheses = cfg->ReadBool(_T("/auto_add_parentheses"), true);
1733  m_CCDetectImplementation = cfg->ReadBool(_T("/detect_implementation"), false); //depends on auto_add_parentheses
1734  m_CCFillupChars = cfg->Read(_T("/fillup_chars"), wxEmptyString);
1735  m_CCEnableHeaders = cfg->ReadBool(_T("/enable_headers"), true);
1736  m_CCEnablePlatformCheck = cfg->ReadBool(_T("/platform_check"), true);
1737 
1738  // update the CC toolbar option, and tick the timer for toolbar
1739  // NOTE (ollydbg#1#12/06/14): why?
1740  if (m_ToolBar)
1741  {
1742  UpdateToolBar();
1744  Manager::Get()->ProcessEvent(evt);
1745  m_ToolbarNeedReparse = true;
1746  TRACE(_T("CodeCompletion::RereadOptions: Starting m_TimerToolbar."));
1747  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
1748  }
1749 
1750  m_DocHelper.RereadOptions(cfg);
1751 }
1752 
1754 {
1755  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
1756  const bool showScope = cfg->ReadBool(_T("/scope_filter"), true);
1757  const int scopeLength = cfg->ReadInt(_T("/toolbar_scope_length"), 280);
1758  const int functionLength = cfg->ReadInt(_T("/toolbar_function_length"), 660);
1759 
1760  if (showScope && !m_Scope)
1761  {
1762  // Show the scope choice
1763  m_Scope = new wxChoice(m_ToolBar, XRCID("chcCodeCompletionScope"), wxPoint(0, 0), wxSize(scopeLength, -1), 0, 0);
1764  m_ToolBar->InsertControl(0, m_Scope);
1765  }
1766  else if (!showScope && m_Scope)
1767  {
1768  // Hide the scope choice
1769  m_ToolBar->DeleteTool(m_Scope->GetId());
1770  m_Scope = nullptr;
1771  }
1772  else if (m_Scope)
1773  {
1774  // Just apply new size to scope choice
1775  m_Scope->SetSize(wxSize(scopeLength, -1));
1776  }
1777 
1778  m_Function->SetSize(wxSize(functionLength, -1));
1779 
1780  m_ToolBar->Realize();
1781  m_ToolBar->SetInitialSize();
1782 }
1783 
1785 {
1786  wxString NameUnderCursor;
1787  bool IsInclude = false;
1788  const bool HasNameUnderCursor = CodeCompletionHelper::EditorHasNameUnderCursor(NameUnderCursor, IsInclude);
1789 
1790  const bool HasEd = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor() != 0;
1791  if (m_EditMenu)
1792  {
1793  const bool RenameEnable = HasNameUnderCursor && !IsInclude && m_NativeParser.GetParser().Done();
1794  m_EditMenu->Enable(idMenuRenameSymbols, RenameEnable);
1795  }
1796 
1797  if (m_SearchMenu)
1798  {
1799  m_SearchMenu->Enable(idMenuGotoFunction, HasEd);
1800  m_SearchMenu->Enable(idMenuGotoPrevFunction, HasEd);
1801  m_SearchMenu->Enable(idMenuGotoNextFunction, HasEd);
1802 
1803  const bool GotoEnable = HasNameUnderCursor && !IsInclude;
1804  m_SearchMenu->Enable(idMenuGotoDeclaration, GotoEnable);
1805  m_SearchMenu->Enable(idMenuGotoImplementation, GotoEnable);
1806  const bool FindEnable = HasNameUnderCursor && !IsInclude && m_NativeParser.GetParser().Done();
1807  m_SearchMenu->Enable(idMenuFindReferences, FindEnable);
1808  const bool IncludeEnable = HasNameUnderCursor && IsInclude;
1809  m_SearchMenu->Enable(idMenuOpenIncludeFile, IncludeEnable);
1810  }
1811 
1812  if (m_ViewMenu)
1813  {
1814  bool isVis = IsWindowReallyShown((wxWindow*)m_NativeParser.GetClassBrowser());
1815  m_ViewMenu->Check(idViewClassBrowser, isVis);
1816  }
1817 
1818  if (m_ProjectMenu)
1819  {
1820  cbProject* project = m_NativeParser.GetCurrentProject();
1821  m_ProjectMenu->Enable(idCurrentProjectReparse, project);
1822  }
1823 
1824  // must do...
1825  event.Skip();
1826 }
1827 
1829 {
1830 #if wxCHECK_VERSION(3, 0, 0)
1831  cbMessageBox(_("The symbols browser is disabled in wx3.x builds.\n"
1832  "We've done this because it causes crashes."), _("Information"), wxICON_INFORMATION);
1833  return;
1834 #else
1835  if (!Manager::Get()->GetConfigManager(_T("code_completion"))->ReadBool(_T("/use_symbols_browser"), true))
1836  {
1837  cbMessageBox(_("The symbols browser is disabled in code-completion options.\n"
1838  "Please enable it there first..."), _("Information"), wxICON_INFORMATION);
1839  return;
1840  }
1842  evt.pWindow = (wxWindow*)m_NativeParser.GetClassBrowser();
1843  Manager::Get()->ProcessEvent(evt);
1844 #endif // wxCHECK_VERSION
1845 }
1846 
1848 {
1850  cbEditor* ed = edMan->GetBuiltinActiveEditor();
1851  if (!ed)
1852  return;
1853 
1854  TRACE(_T("OnGotoFunction"));
1855 
1856  m_NativeParser.GetParser().ParseBufferForFunctions(ed->GetControl()->GetText());
1857 
1858 
1859  TokenTree* tree = m_NativeParser.GetParser().GetTempTokenTree();
1860 
1862 
1863  if (tree->empty())
1864  {
1865  cbMessageBox(_("No functions parsed in this file..."));
1867  }
1868  else
1869  {
1870  GotoFunctionDlg::Iterator iterator;
1871 
1872  for (size_t i = 0; i < tree->size(); i++)
1873  {
1874  Token* token = tree->at(i);
1875  if (token && token->m_TokenKind & tkAnyFunction)
1876  {
1878  // We need to clone the internal data of the strings to make them thread safe.
1879  ft.displayName = wxString(token->DisplayName().c_str());
1880  ft.name = wxString(token->m_Name.c_str());
1881  ft.line = token->m_Line;
1882  ft.implLine = token->m_ImplLine;
1883  if (!token->m_FullType.empty())
1884  ft.paramsAndreturnType = wxString((token->m_Args + wxT(" -> ") + token->m_FullType).c_str());
1885  else
1886  ft.paramsAndreturnType = wxString(token->m_Args.c_str());
1887  ft.funcName = wxString((token->GetNamespace() + token->m_Name).c_str());
1888 
1889  iterator.AddToken(ft);
1890  }
1891  }
1892 
1893  tree->clear();
1894 
1896 
1897  iterator.Sort();
1898  GotoFunctionDlg dlg(Manager::Get()->GetAppWindow(), &iterator);
1899  PlaceWindow(&dlg);
1900  if (dlg.ShowModal() == wxID_OK)
1901  {
1902  int selection = dlg.GetSelection();
1903  if (selection != wxNOT_FOUND) {
1904  const GotoFunctionDlg::FunctionToken *ft = iterator.GetToken(selection);
1905  if (ed && ft)
1906  {
1907  TRACE(F(_T("OnGotoFunction() : Token '%s' found at line %u."), ft->name.wx_str(), ft->line));
1908  ed->GotoTokenPosition(ft->implLine - 1, ft->name);
1909  }
1910  }
1911  }
1912  }
1913 }
1914 
1916 {
1917  GotoFunctionPrevNext(); // prev function
1918 }
1919 
1921 {
1922  GotoFunctionPrevNext(true); // next function
1923 }
1924 
1926 {
1927  DoClassMethodDeclImpl();
1928 }
1929 
1931 {
1932  DoAllMethodsImpl();
1933 }
1934 
1936 {
1938  cbEditor* editor = edMan->GetBuiltinActiveEditor();
1939  if (!editor)
1940  return;
1941 
1942  TRACE(_T("OnGotoDeclaration"));
1943 
1944  const int pos = editor->GetControl()->GetCurrentPos();
1945  const int startPos = editor->GetControl()->WordStartPosition(pos, true);
1946  const int endPos = editor->GetControl()->WordEndPosition(pos, true);
1947  wxString target;
1948  // if there is a tilde "~", the token can either be a destructor or an Bitwise NOT (One's
1949  // Complement) operator
1950  bool isDestructor = false;
1951  if (CodeCompletionHelper::GetLastNonWhitespaceChar(editor->GetControl(), startPos) == _T('~'))
1952  isDestructor = true;
1953  target << editor->GetControl()->GetTextRange(startPos, endPos);
1954  if (target.IsEmpty())
1955  return;
1956 
1957  // prepare a boolean filter for declaration/implementation
1958  bool isDecl = event.GetId() == idGotoDeclaration || event.GetId() == idMenuGotoDeclaration;
1959  bool isImpl = event.GetId() == idGotoImplementation || event.GetId() == idMenuGotoImplementation;
1960 
1961  // get the matching set
1962  TokenIdxSet result;
1963  m_NativeParser.MarkItemsByAI(result, true, false, true, endPos);
1964 
1965  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
1966 
1968 
1969  // handle destructor function, first we try to see if it is a destructor, we simply do a semantic
1970  // check of the token under cursor, otherwise, it is a variable.
1971  if (isDestructor)
1972  {
1973  TokenIdxSet tmp = result;
1974  result.clear();
1975 
1976  for (TokenIdxSet::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
1977  {
1978  const Token* token = tree->at(*it);
1979  if (token && token->m_TokenKind == tkClass)
1980  {
1981  token = tree->at(tree->TokenExists(_T("~") + target, token->m_Index, tkDestructor));
1982  if (token)
1983  result.insert(token->m_Index);
1984  }
1985  }
1986 
1987  // no destructor found, this could be a variable.
1988  if (result.empty())
1989  result = tmp;
1990  }
1991  else // handle constructor and functions
1992  {
1993  // AAA * p = new AAA();
1994  // ^^^--------------------------case1:go to class definition kind tokens
1995  // ^^^------------case2:go to function kind tokens such as constructors
1996  // if a token is followed by a '(', it is regarded as a function
1997  const bool isFunction = CodeCompletionHelper::GetNextNonWhitespaceChar(editor->GetControl(), endPos) == _T('(');
1998  // copy the token index set for a fall back case later
1999  TokenIdxSet savedResult = result;
2000  // loop the result, and strip unrelated tokens
2001  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end();)
2002  {
2003  const Token* token = tree->at(*it);
2004  if (isFunction && token && token->m_TokenKind == tkClass)
2005  result.erase(it++); // a class kind token is removed since we need a function
2006  else if (!isFunction && token && token->m_TokenKind == tkConstructor)
2007  result.erase(it++); // a constructor token is removed since we don't need a function
2008  else
2009  ++it;
2010  }
2011  // fall back: restore the saved result in a special case that a class doesn't have a constructor
2012  // defined (implicitly defined by compiler)
2013  // E.g. hover on case2 go to class AAA token since no AAA::AAA(); is defined or declared.
2014  if (!result.size())
2015  result = savedResult;
2016  }
2017 
2018  // handle function overloading
2019  if (result.size() > 1)
2020  {
2021  const size_t curLine = editor->GetControl()->GetCurrentLine() + 1;
2022  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
2023  {
2024  const Token* token = tree->at(*it);
2025  if (token && (token->m_Line == curLine || token->m_ImplLine == curLine) )
2026  {
2027  const int theOnlyOne = *it;
2028  result.clear();
2029  result.insert(theOnlyOne);
2030  break;
2031  }
2032  }
2033  }
2034 
2035  // data for the choice dialog
2036  std::deque<CodeCompletionHelper::GotoDeclarationItem> foundItems;
2037  wxArrayString selections;
2038 
2039  wxString editorFilename;
2040  unsigned editorLine = -1;
2041  bool tokenFound = false;
2042 
2043  // one match
2044  if (result.size() == 1)
2045  {
2046  Token* token = NULL;
2047  Token* sel = tree->at(*(result.begin()));
2048  if ( (isImpl && !sel->GetImplFilename().IsEmpty())
2049  || (isDecl && !sel->GetFilename().IsEmpty()) )
2050  {
2051  token = sel;
2052  }
2053  if (token)
2054  {
2055  // FIXME: implement this correctly, because now it is not showing full results
2058  && ( event.GetId() == idGotoDeclaration
2059  || event.GetId() == idGotoImplementation ) )
2060  {
2061  // FIXME: this code can lead to a deadlock (because of double locking from single thread)
2062  CCDebugInfo info(nullptr, &m_NativeParser.GetParser(), token);
2063  info.ShowModal();
2064  }
2065  else if (isImpl)
2066  {
2067  editorFilename = token->GetImplFilename();
2068  editorLine = token->m_ImplLine - 1;
2069  }
2070  else if (isDecl)
2071  {
2072  editorFilename = token->GetFilename();
2073  editorLine = token->m_Line - 1;
2074  }
2075 
2076  tokenFound = true;
2077  }
2078  }
2079  // if more than one match, display a selection dialog
2080  else if (result.size() > 1)
2081  {
2082  // TODO: we could parse the line containing the text so
2083  // if namespaces were included, we could limit the results (and be more accurate)
2084  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
2085  {
2086  const Token* token = tree->at(*it);
2087  if (token)
2088  {
2090 
2091  if (isImpl)
2092  {
2093  item.filename = token->GetImplFilename();
2094  item.line = token->m_ImplLine - 1;
2095  }
2096  else if (isDecl)
2097  {
2098  item.filename = token->GetFilename();
2099  item.line = token->m_Line - 1;
2100  }
2101 
2102  // only match tokens that have filename info
2103  if (!item.filename.empty())
2104  {
2105  selections.Add(token->DisplayName());
2106  foundItems.push_back(item);
2107  }
2108  }
2109  }
2110  }
2111 
2113 
2114  if (selections.GetCount() > 1)
2115  {
2116  int sel = cbGetSingleChoiceIndex(_("Please make a selection:"), _("Multiple matches"), selections,
2117  Manager::Get()->GetAppWindow(), wxSize(400, 400));
2118  if (sel == -1)
2119  return;
2120 
2121  const CodeCompletionHelper::GotoDeclarationItem &item = foundItems[sel];
2122  editorFilename = item.filename;
2123  editorLine = item.line;
2124  tokenFound = true;
2125  }
2126  else if (selections.GetCount() == 1)
2127  {
2128  // number of selections can be < result.size() due to the if tests, so in case we fall
2129  // back on 1 entry no need to show a selection
2130  const CodeCompletionHelper::GotoDeclarationItem &item = foundItems.front();
2131  editorFilename = item.filename;
2132  editorLine = item.line;
2133  tokenFound = true;
2134  }
2135 
2136  // do we have a token?
2137  if (tokenFound)
2138  {
2139  cbEditor* targetEditor = edMan->Open(editorFilename);
2140  if (targetEditor)
2141  targetEditor->GotoTokenPosition(editorLine, target);
2142  else
2143  {
2144  if (isImpl)
2145  cbMessageBox(wxString::Format(_("Implementation not found: %s"), target.wx_str()),
2146  _("Warning"), wxICON_WARNING);
2147  else if (isDecl)
2148  cbMessageBox(wxString::Format(_("Declaration not found: %s"), target.wx_str()),
2149  _("Warning"), wxICON_WARNING);
2150  }
2151  }
2152  else
2153  cbMessageBox(wxString::Format(_("Not found: %s"), target.wx_str()), _("Warning"), wxICON_WARNING);
2154 }
2155 
2157 {
2158  m_CodeRefactoring.FindReferences();
2159 }
2160 
2162 {
2163  m_CodeRefactoring.RenameSymbols();
2164 }
2165 
2167 {
2168  wxString lastIncludeFileFrom;
2170  if (editor)
2171  lastIncludeFileFrom = editor->GetFilename();
2172 
2173  // check one more time because menu entries are enabled only when it makes sense
2174  // but the shortcut accelerator can always be executed
2175  bool MoveOn = false;
2176  wxString NameUnderCursor;
2177  bool IsInclude = false;
2178  if (CodeCompletionHelper::EditorHasNameUnderCursor(NameUnderCursor, IsInclude))
2179  {
2180  if (IsInclude)
2181  MoveOn = true;
2182  }
2183 
2184  if (!MoveOn)
2185  return; // nothing under cursor or thing under cursor is not an include
2186 
2187  TRACE(_T("OnOpenIncludeFile"));
2188 
2189  wxArrayString foundSet = m_NativeParser.GetParser().FindFileInIncludeDirs(NameUnderCursor); // search in all parser's include dirs
2190 
2191  // look in the same dir as the source file
2192  wxFileName fname = NameUnderCursor;
2193  wxFileName base = lastIncludeFileFrom;
2194  NormalizePath(fname, base.GetPath());
2195  if (wxFileExists(fname.GetFullPath()) )
2196  foundSet.Add(fname.GetFullPath());
2197 
2198  // search for the file in project files
2199  cbProject* project = m_NativeParser.GetProjectByEditor(editor);
2200  if (project)
2201  {
2202  for (FilesList::const_iterator it = project->GetFilesList().begin();
2203  it != project->GetFilesList().end(); ++it)
2204  {
2205  ProjectFile* pf = *it;
2206  if (!pf)
2207  continue;
2208 
2209  if ( IsSuffixOfPath(NameUnderCursor, pf->file.GetFullPath()) )
2210  foundSet.Add(pf->file.GetFullPath());
2211  }
2212  }
2213 
2214  // Remove duplicates
2215  for (int i = 0; i < (int)foundSet.Count() - 1; i++)
2216  {
2217  for (int j = i + 1; j < (int)foundSet.Count(); )
2218  {
2219  if (foundSet.Item(i) == foundSet.Item(j))
2220  foundSet.RemoveAt(j);
2221  else
2222  j++;
2223  }
2224  }
2225 
2226  wxString selectedFile;
2227  if (foundSet.GetCount() > 1)
2228  { // more than 1 hit : let the user choose
2229  SelectIncludeFile Dialog(Manager::Get()->GetAppWindow());
2230  Dialog.AddListEntries(foundSet);
2231  PlaceWindow(&Dialog);
2232  if (Dialog.ShowModal() == wxID_OK)
2233  selectedFile = Dialog.GetIncludeFile();
2234  else
2235  return; // user cancelled the dialog...
2236  }
2237  else if (foundSet.GetCount() == 1)
2238  selectedFile = foundSet[0];
2239 
2240  if (!selectedFile.IsEmpty())
2241  {
2243  edMan->Open(selectedFile);
2244  return;
2245  }
2246 
2247  cbMessageBox(wxString::Format(_("Not found: %s"), NameUnderCursor.c_str()), _("Warning"), wxICON_WARNING);
2248 }
2249 
2251 {
2252  m_NativeParser.ReparseCurrentProject();
2253  event.Skip();
2254 }
2255 
2257 {
2258  m_NativeParser.ReparseSelectedProject();
2259  event.Skip();
2260 }
2261 
2263 {
2265  if (!tree)
2266  return;
2267 
2269  if (!treeItem.IsOk())
2270  return;
2271 
2272  const FileTreeData* data = static_cast<FileTreeData*>(tree->GetItemData(treeItem));
2273  if (!data)
2274  return;
2275 
2276  if (data->GetKind() == FileTreeData::ftdkFile)
2277  {
2278  cbProject* project = data->GetProject();
2279  ProjectFile* pf = data->GetProjectFile();
2280  if (pf && m_NativeParser.ReparseFile(project, pf->file.GetFullPath()))
2281  {
2282  CCLogger::Get()->DebugLog(_T("Reparsing the selected file ") +
2283  pf->file.GetFullPath());
2284  }
2285  }
2286 
2287  event.Skip();
2288 }
2289 
2291 {
2292  if (!m_InitDone)
2293  DoParseOpenedProjectAndActiveEditor();
2294 
2295  event.Skip();
2296 }
2297 
2299 {
2300  // EVT_WORKSPACE_CHANGED is a powerful event, it's sent after any project
2301  // has finished loading or closing. It's the *LAST* event to be sent when
2302  // the workspace has been changed. So it's the ideal time to parse files
2303  // and update your widgets.
2304  if (IsAttached() && m_InitDone)
2305  {
2307  // if we receive a workspace changed event, but the project is NULL, this means two condition
2308  // could happen.
2309  // (1) the user try to close the application, so we don't need to update the UI here.
2310  // (2) the user just open a new project after cb started up
2311  if (project)
2312  {
2313  if (!m_NativeParser.GetParserByProject(project))
2314  m_NativeParser.CreateParser(project);
2315 
2316  // Update the Function toolbar
2317  TRACE(_T("CodeCompletion::OnWorkspaceChanged: Starting m_TimerToolbar."));
2318  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
2319 
2320  // Update the class browser
2321  if (m_NativeParser.GetParser().ClassBrowserOptions().displayFilter == bdfProject)
2322  m_NativeParser.UpdateClassBrowser();
2323  }
2324  }
2325  event.Skip();
2326 }
2327 
2329 {
2330  // The Class browser shouldn't be updated if we're in the middle of loading/closing
2331  // a project/workspace, because the class browser would need to be updated again.
2332  // So we need to update it with the EVT_WORKSPACE_CHANGED event, which gets
2333  // triggered after everything's finished loading/closing.
2334  if (!ProjectManager::IsBusy() && IsAttached() && m_InitDone)
2335  {
2336  cbProject* project = event.GetProject();
2337  if (project && !m_NativeParser.GetParserByProject(project) && project->GetFilesCount() > 0)
2338  m_NativeParser.CreateParser(project);
2339 
2340  if (m_NativeParser.GetParser().ClassBrowserOptions().displayFilter == bdfProject)
2341  m_NativeParser.UpdateClassBrowser();
2342  }
2343 
2344  m_NeedsBatchColour = true;
2345 
2346  event.Skip();
2347 }
2348 
2350 {
2351  // After this, the Class Browser needs to be updated. It will happen
2352  // when we receive the next EVT_PROJECT_ACTIVATED event.
2353  if (IsAttached() && m_InitDone)
2354  {
2355  cbProject* project = event.GetProject();
2356  if (project && m_NativeParser.GetParserByProject(project))
2357  {
2358  // there may be some pending files to be reparsed in m_ReparsingMap
2359  // so just remove them
2360  ReparsingMap::iterator it = m_ReparsingMap.find(project);
2361  if (it != m_ReparsingMap.end())
2362  m_ReparsingMap.erase(it);
2363 
2364  // remove the Parser instance associated with the project
2365  m_NativeParser.DeleteParser(project);
2366  }
2367  }
2368  event.Skip();
2369 }
2370 
2372 {
2373  // reparse project (compiler search dirs might have changed)
2374  m_TimerProjectSaved.SetClientData(event.GetProject());
2375  // we need more time for waiting wxExecute in NativeParser::AddCompilerPredefinedMacros
2376  TRACE(_T("CodeCompletion::OnProjectSaved: Starting m_TimerProjectSaved."));
2377  m_TimerProjectSaved.Start(200, wxTIMER_ONE_SHOT);
2378 
2379  event.Skip();
2380 }
2381 
2383 {
2384  if (IsAttached() && m_InitDone)
2385  m_NativeParser.AddFileToParser(event.GetProject(), event.GetString());
2386  event.Skip();
2387 }
2388 
2390 {
2391  if (IsAttached() && m_InitDone)
2392  m_NativeParser.RemoveFileFromParser(event.GetProject(), event.GetString());
2393  event.Skip();
2394 }
2395 
2397 {
2398  if (IsAttached() && m_InitDone)
2399  {
2400  // TODO (Morten#5#) make sure the event.GetProject() is valid.
2401  cbProject* project = event.GetProject();
2402  wxString filename = event.GetString();
2403  if (!project)
2404  project = m_NativeParser.GetProjectByFilename(filename);
2405  if (project && m_NativeParser.ReparseFile(project, filename))
2406  CCLogger::Get()->DebugLog(_T("Reparsing when file changed: ") + filename);
2407  }
2408  event.Skip();
2409 }
2410 
2412 {
2413  if (!ProjectManager::IsBusy() && IsAttached() && m_InitDone && event.GetEditor())
2414  {
2415  cbProject* project = event.GetProject();
2416 
2417  // we know which project the editor belongs to, so put a (project, file) pair to the
2418  // m_ReparsingMap
2419  ReparsingMap::iterator it = m_ReparsingMap.find(project);
2420  if (it == m_ReparsingMap.end())
2421  it = m_ReparsingMap.insert(std::make_pair(project, wxArrayString())).first;
2422 
2423  const wxString& filename = event.GetEditor()->GetFilename();
2424  if (it->second.Index(filename) == wxNOT_FOUND)
2425  it->second.Add(filename);
2426 
2427  // start the timer, so that it will be handled in timer event handler
2428  TRACE(_T("CodeCompletion::OnEditorSave: Starting m_TimerReparsing."));
2429  m_TimerReparsing.Start(EDITOR_ACTIVATED_DELAY + it->second.GetCount() * 10, wxTIMER_ONE_SHOT);
2430  }
2431 
2432  event.Skip();
2433 }
2434 
2436 {
2437  if (!Manager::IsAppShuttingDown() && IsAttached() && m_InitDone)
2438  {
2440  if (ed)
2441  {
2442  FunctionsScopePerFile* funcdata = &(m_AllFunctionsScopes[ed->GetFilename()]);
2443  funcdata->parsed = false;
2444  }
2445  }
2446 
2447  event.Skip();
2448 }
2449 
2451 {
2452  TRACE(_T("CodeCompletion::OnEditorActivated(): Enter"));
2453 
2454  if (!ProjectManager::IsBusy() && IsAttached() && m_InitDone && event.GetEditor())
2455  {
2456  m_LastEditor = Manager::Get()->GetEditorManager()->GetBuiltinEditor(event.GetEditor());
2457 
2458  TRACE(_T("CodeCompletion::OnEditorActivated(): Starting m_TimerEditorActivated."));
2459  m_TimerEditorActivated.Start(EDITOR_ACTIVATED_DELAY, wxTIMER_ONE_SHOT);
2460 
2461  if (m_TimerToolbar.IsRunning())
2462  m_TimerToolbar.Stop();
2463  }
2464 
2465  event.Skip();
2466  TRACE(_T("CodeCompletion::OnEditorActivated(): Leave"));
2467 }
2468 
2470 {
2472  if (!edm)
2473  {
2474  event.Skip();
2475  return;
2476  }
2477 
2478  wxString activeFile;
2479  EditorBase* eb = edm->GetActiveEditor();
2480  if (eb)
2481  activeFile = eb->GetFilename();
2482 
2483  TRACE(_T("CodeCompletion::OnEditorClosed(): Closed editor's file is %s"), activeFile.wx_str());
2484 
2485  if (m_LastEditor == event.GetEditor())
2486  {
2487  m_LastEditor = nullptr;
2488  if (m_TimerEditorActivated.IsRunning())
2489  m_TimerEditorActivated.Stop();
2490  }
2491 
2492  // tell m_NativeParser that a builtin editor was closed
2493  if ( edm->GetBuiltinEditor(event.GetEditor()) )
2494  m_NativeParser.OnEditorClosed(event.GetEditor());
2495 
2496  m_LastFile.Clear();
2497 
2498  // we need to clear CC toolbar only when we are closing last editor
2499  // in other situations OnEditorActivated does this job
2500  // If no editors were opened, or a non-buildin-editor was active, disable the CC toolbar
2501  if (edm->GetEditorsCount() == 0 || !edm->GetActiveEditor() || !edm->GetActiveEditor()->IsBuiltinEditor())
2502  {
2503  EnableToolbarTools(false);
2504 
2505  // clear toolbar when closing last editor
2506  if (m_Scope)
2507  m_Scope->Clear();
2508  if (m_Function)
2509  m_Function->Clear();
2510 
2511  cbEditor* ed = edm->GetBuiltinEditor(event.GetEditor());
2513  if (ed)
2514  filename = ed->GetFilename();
2515 
2516  m_AllFunctionsScopes[filename].m_FunctionsScope.clear();
2517  m_AllFunctionsScopes[filename].m_NameSpaces.clear();
2518  m_AllFunctionsScopes[filename].parsed = false;
2519  if (m_NativeParser.GetParser().ClassBrowserOptions().displayFilter == bdfFile)
2520  m_NativeParser.UpdateClassBrowser();
2521  }
2522 
2523  event.Skip();
2524 }
2525 
2527 {
2529  Manager::Get()->GetLogManager()->Log(event.GetString());
2530 }
2531 
2533 {
2535  Manager::Get()->GetLogManager()->DebugLog(event.GetString());
2536 }
2537 
2539 {
2540  cbProject* project = static_cast<cbProject*>(event.GetClientData());
2541  ParserCommon::ParserState state = static_cast<ParserCommon::ParserState>(event.GetInt());
2542  // Parser::OnBatchTimer will send this Parser Start event
2543  // If it starts a full parsing(ptCreateParser), we should prepare some data for the header
2544  // file clawler
2545  if (state == ParserCommon::ptCreateParser)
2546  {
2547  if (m_CCEnableHeaders)
2548  {
2549  wxArrayString& dirs = GetSystemIncludeDirs(project, true); // true means update the cache
2550  SystemHeadersThread* thread = new SystemHeadersThread(this, &m_SystemHeadersThreadCS, m_SystemHeadersMap, dirs);
2551  m_SystemHeadersThreads.push_back(thread);
2552  }
2553 
2555  if (m_NativeParser.GetProjectByEditor(editor) == project)
2556  EnableToolbarTools(false);
2557  }
2558 }
2559 
2561 {
2562  ParserCommon::ParserState state = static_cast<ParserCommon::ParserState>(event.GetInt());
2563 
2564  // ParserCommon::ptCreateParser means a full parsing stage is done, so it is the time to
2565  // start the header file clawler
2566  if (state == ParserCommon::ptCreateParser)
2567  {
2568  if ( m_CCEnableHeaders
2569  && !m_SystemHeadersThreads.empty()
2570  && !m_SystemHeadersThreads.front()->IsRunning()
2571  && m_NativeParser.Done() )
2572  {
2573  m_SystemHeadersThreads.front()->Run();
2574  }
2575  }
2576 
2578  cbEditor* editor = edMan->GetBuiltinActiveEditor();
2579  if (editor)
2580  {
2581  m_ToolbarNeedReparse = true;
2582  TRACE(_T("CodeCompletion::OnParserEnd: Starting m_TimerToolbar."));
2583  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
2584  }
2585 
2586  if (m_NeedsBatchColour)
2587  {
2588  for (int edIdx = edMan->GetEditorsCount() - 1; edIdx >= 0; --edIdx)
2589  {
2590  editor = edMan->GetBuiltinEditor(edIdx);
2591  if (editor)
2592  UpdateEditorSyntax(editor);
2593  }
2594  m_NeedsBatchColour = false;
2595  }
2596 
2597  event.Skip();
2598 }
2599 
2601 {
2602  CCLogger::Get()->DebugLog(event.GetString());
2603 }
2604 
2606 {
2607  if (m_SystemHeadersThreads.empty())
2608  return;
2609  // wait for the current thread died, and remove it from the thread list, then try to run another
2610  // thread
2611  SystemHeadersThread* thread = static_cast<SystemHeadersThread*>(event.GetClientData());
2612 
2613  // remove the already finished SystemHeadersThread
2614  if (thread == m_SystemHeadersThreads.front())
2615  {
2616  if (!event.GetString().IsEmpty())
2617  CCLogger::Get()->DebugLog(event.GetString());
2618  // In the case of receiving the finish event, the thread should already die, if not
2619  // we just wait the thread to die. we expect this don't take much time, otherwise, it
2620  // hangs (blocks) here.
2621  if (thread->IsAlive() && thread->IsRunning())
2622  thread->Wait();
2623  delete thread;
2624  m_SystemHeadersThreads.pop_front();
2625  }
2626 
2627  // start to run the remaining threads
2628  if ( m_CCEnableHeaders
2629  && !m_SystemHeadersThreads.empty()
2630  && !m_SystemHeadersThreads.front()->IsRunning()
2631  && m_NativeParser.Done() )
2632  {
2633  m_SystemHeadersThreads.front()->Run();
2634  }
2635 }
2636 
2638 {
2639  if (!IsAttached() || !m_InitDone)
2640  return -1;
2641 
2643  cbEditor* ed = edMan->GetBuiltinActiveEditor();
2644  if (!ed)
2645  return -3;
2646 
2647  FileType ft = FileTypeOf(ed->GetShortName());
2648  if ( ft != ftHeader && ft != ftSource && ft != ftTemplateSource) // only parse source/header files
2649  return -4;
2650 
2651  if (!m_NativeParser.GetParser().Done())
2652  {
2653  wxString msg = _("The Parser is still parsing files.");
2654  msg += m_NativeParser.GetParser().NotDoneReason();
2655  CCLogger::Get()->DebugLog(msg);
2656  return -5;
2657  }
2658 
2659  int success = -6;
2660 
2661 // TokenTree* tree = m_NativeParser.GetParser().GetTokenTree(); // The one used inside InsertClassMethodDlg
2662 
2664 
2665  // open the insert class dialog
2666  wxString filename = ed->GetFilename();
2667  InsertClassMethodDlg dlg(Manager::Get()->GetAppWindow(), &m_NativeParser.GetParser(), filename);
2668  PlaceWindow(&dlg);
2669  if (dlg.ShowModal() == wxID_OK)
2670  {
2671  cbStyledTextCtrl* control = ed->GetControl();
2672  int pos = control->GetCurrentPos();
2673  int line = control->LineFromPosition(pos);
2674  control->GotoPos(control->PositionFromLine(line));
2675 
2676  wxArrayString result = dlg.GetCode();
2677  for (unsigned int i = 0; i < result.GetCount(); ++i)
2678  {
2679  pos = control->GetCurrentPos();
2680  line = control->LineFromPosition(pos);
2681  // get the indent string from previous line
2682  wxString str = ed->GetLineIndentString(line - 1) + result[i];
2683  MatchCodeStyle(str, control->GetEOLMode(), ed->GetLineIndentString(line - 1), control->GetUseTabs(), control->GetTabWidth());
2684  control->SetTargetStart(pos);
2685  control->SetTargetEnd(pos);
2686  control->ReplaceTarget(str);
2687  control->GotoPos(pos + str.Length());// - 3);
2688  }
2689  success = 0;
2690  }
2691 
2693 
2694  return success;
2695 }
2696 
2698 {
2699  if (!IsAttached() || !m_InitDone)
2700  return -1;
2701 
2703  cbEditor* ed = edMan->GetBuiltinActiveEditor();
2704  if (!ed)
2705  return -3;
2706 
2707  FileType ft = FileTypeOf(ed->GetShortName());
2708  if ( ft != ftHeader && ft != ftSource && ft != ftTemplateSource) // only parse source/header files
2709  return -4;
2710 
2711  wxArrayString paths = m_NativeParser.GetAllPathsByFilename(ed->GetFilename());
2712  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
2713 
2715 
2716  // get all filenames' indices matching our mask
2717  TokenFileSet result;
2718  for (size_t i = 0; i < paths.GetCount(); ++i)
2719  {
2720  CCLogger::Get()->DebugLog(_T("CodeCompletion::DoAllMethodsImpl(): Trying to find matches for: ") + paths[i]);
2721  TokenFileSet result_file;
2722  tree->GetFileMatches(paths[i], result_file, true, true);
2723  for (TokenFileSet::const_iterator it = result_file.begin(); it != result_file.end(); ++it)
2724  result.insert(*it);
2725  }
2726 
2727  if (result.empty())
2728  {
2730 
2731  cbMessageBox(_("Could not find any file match in parser's database."), _("Warning"), wxICON_WARNING);
2732  return -5;
2733  }
2734 
2735  // loop matching files, loop tokens in file and get list of un-implemented functions
2736  wxArrayString arr; // for selection (keeps strings)
2737  wxArrayInt arrint; // for selection (keeps indices)
2738  typedef std::map<int, std::pair<int, wxString> > ImplMap;
2739  ImplMap im;
2740  for (TokenFileSet::const_iterator itf = result.begin(); itf != result.end(); ++itf)
2741  {
2742  const TokenIdxSet* tokens = tree->GetTokensBelongToFile(*itf);
2743  if (!tokens) continue;
2744 
2745  // loop tokens in file
2746  for (TokenIdxSet::const_iterator its = tokens->begin(); its != tokens->end(); ++its)
2747  {
2748  const Token* token = tree->at(*its);
2749  if ( token // valid token
2750  && (token->m_TokenKind & (tkFunction | tkConstructor | tkDestructor)) // is method
2751  && token->m_ImplLine == 0 ) // is un-implemented
2752  {
2753  im[token->m_Line] = std::make_pair(*its, token->DisplayName());
2754  }
2755  }
2756  }
2757 
2758  for (ImplMap::const_iterator it = im.begin(); it != im.end(); ++it)
2759  {
2760  arrint.Add(it->second.first);
2761  arr.Add(it->second.second);
2762  }
2763 
2764  if (arr.empty())
2765  {
2767 
2768  cbMessageBox(_("No classes declared or no un-implemented class methods found."), _("Warning"), wxICON_WARNING);
2769  return -5;
2770  }
2771 
2772  int success = -5;
2773 
2774  // select tokens
2775  MultiSelectDlg dlg(Manager::Get()->GetAppWindow(), arr, true);
2776  if (dlg.ShowModal() == wxID_OK)
2777  {
2778  cbStyledTextCtrl* control = ed->GetControl();
2779  int pos = control->GetCurrentPos();
2780  int line = control->LineFromPosition(pos);
2781  control->GotoPos(control->PositionFromLine(line));
2782 
2783  bool addDoxgenComment = Manager::Get()->GetConfigManager(_T("code_completion"))->ReadBool(_T("/add_doxgen_comment"), false);
2784 
2785  wxArrayInt indices = dlg.GetSelectedIndices();
2786  for (size_t i = 0; i < indices.GetCount(); ++i)
2787  {
2788  const Token* token = tree->at(arrint[indices[i]]);
2789  if (!token)
2790  continue;
2791 
2792  pos = control->GetCurrentPos();
2793  line = control->LineFromPosition(pos);
2794 
2795  // actual code generation
2796  wxString str;
2797  if (i > 0)
2798  str << _T("\n");
2799  else
2800  str << ed->GetLineIndentString(line - 1);
2801  if (addDoxgenComment)
2802  str << _T("/** @brief ") << token->m_Name << _T("\n *\n * @todo: document this function\n */\n");
2803  wxString type = token->m_FullType;
2804  if (!type.IsEmpty())
2805  {
2806  // "int *" or "int &" -> "int*" or "int&"
2807  if ( (type.Last() == _T('&') || type.Last() == _T('*'))
2808  && type[type.Len() - 2] == _T(' '))
2809  {
2810  type[type.Len() - 2] = type.Last();
2811  type.RemoveLast();
2812  }
2813  str << type << _T(" ");
2814  }
2815  if (token->m_ParentIndex != -1)
2816  {
2817  const Token* parent = tree->at(token->m_ParentIndex);
2818  if (parent)
2819  str << parent->m_Name << _T("::");
2820  }
2821  str << token->m_Name << token->GetStrippedArgs();
2822  if (token->m_IsConst)
2823  str << _T(" const");
2824  if (token->m_IsNoExcept)
2825  str << _T(" noexcept");
2826  str << _T("\n{\n\t\n}\n");
2827 
2828  MatchCodeStyle(str, control->GetEOLMode(), ed->GetLineIndentString(line - 1), control->GetUseTabs(), control->GetTabWidth());
2829 
2830  // add code in editor
2831  control->SetTargetStart(pos);
2832  control->SetTargetEnd(pos);
2833  control->ReplaceTarget(str);
2834  control->GotoPos(pos + str.Length());
2835  }
2836  if (!indices.IsEmpty())
2837  {
2838  pos = control->GetCurrentPos();
2839  line = control->LineFromPosition(pos);
2840  control->GotoPos(control->GetLineEndPosition(line - 2));
2841  }
2842  success = 0;
2843  }
2844 
2846 
2847  return success;
2848 }
2849 
2850 void CodeCompletion::MatchCodeStyle(wxString& str, int eolStyle, const wxString& indent, bool useTabs, int tabSize)
2851 {
2852  str.Replace(wxT("\n"), GetEOLStr(eolStyle) + indent);
2853  if (!useTabs)
2854  str.Replace(wxT("\t"), wxString(wxT(' '), tabSize));
2855  if (!indent.IsEmpty())
2856  str.RemoveLast(indent.Length());
2857 }
2858 
2859 // help method in finding the function position in the vector for the function containing the current line
2860 void CodeCompletion::FunctionPosition(int &scopeItem, int &functionItem) const
2861 {
2862  scopeItem = -1;
2863  functionItem = -1;
2864 
2865  for (unsigned int idxSc = 0; idxSc < m_ScopeMarks.size(); ++idxSc)
2866  {
2867  // this is the start and end of a scope
2868  unsigned int start = m_ScopeMarks[idxSc];
2869  unsigned int end = (idxSc + 1 < m_ScopeMarks.size()) ? m_ScopeMarks[idxSc + 1] : m_FunctionsScope.size();
2870 
2871  // the scope could have many functions, so loop on the functions
2872  for (int idxFn = 0; start + idxFn < end; ++idxFn)
2873  {
2874  const FunctionScope fs = m_FunctionsScope[start + idxFn];
2875  if (m_CurrentLine >= fs.StartLine && m_CurrentLine <= fs.EndLine)
2876  {
2877  scopeItem = idxSc;
2878  functionItem = idxFn;
2879  }
2880  }
2881  }
2882 }
2883 
2884 void CodeCompletion::GotoFunctionPrevNext(bool next /* = false */)
2885 {
2887  cbEditor* ed = edMan->GetBuiltinActiveEditor();
2888  if (!ed)
2889  return;
2890 
2891  int current_line = ed->GetControl()->GetCurrentLine();
2892 
2893  if (!m_FunctionsScope.size())
2894  return;
2895 
2896  // search previous/next function from current line, default: previous
2897  int line = -1;
2898  unsigned int best_func = 0;
2899  bool found_best_func = false;
2900  for (unsigned int idx_func=0; idx_func<m_FunctionsScope.size(); ++idx_func)
2901  {
2902  int best_func_line = m_FunctionsScope[best_func].StartLine;
2903  int func_start_line = m_FunctionsScope[idx_func].StartLine;
2904  if (next)
2905  {
2906  if (best_func_line > current_line) // candidate: is after current line
2907  {
2908  if ( (func_start_line > current_line ) // another candidate
2909  && (func_start_line < best_func_line) ) // decide which is more near
2910  { best_func = idx_func; found_best_func = true; }
2911  }
2912  else if (func_start_line > current_line) // candidate: is after current line
2913  { best_func = idx_func; found_best_func = true; }
2914  }
2915  else // prev
2916  {
2917  if (best_func_line < current_line) // candidate: is before current line
2918  {
2919  if ( (func_start_line < current_line ) // another candidate
2920  && (func_start_line > best_func_line) ) // decide which is closer
2921  { best_func = idx_func; found_best_func = true; }
2922  }
2923  else if (func_start_line < current_line) // candidate: is before current line
2924  { best_func = idx_func; found_best_func = true; }
2925  }
2926  }
2927 
2928  if (found_best_func)
2929  { line = m_FunctionsScope[best_func].StartLine; }
2930  else if ( next && m_FunctionsScope[best_func].StartLine>current_line)
2931  { line = m_FunctionsScope[best_func].StartLine; }
2932  else if (!next && m_FunctionsScope[best_func].StartLine<current_line)
2933  { line = m_FunctionsScope[best_func].StartLine; }
2934 
2935  if (line != -1)
2936  {
2937  ed->GotoLine(line);
2938  ed->SetFocus();
2939  }
2940 }
2941 
2942 // help method in finding the namespace position in the vector for the namespace containing the current line
2944 {
2945  int pos = -1;
2946  int startLine = -1;
2947  for (unsigned int idxNs = 0; idxNs < m_NameSpaces.size(); ++idxNs)
2948  {
2949  const NameSpace& ns = m_NameSpaces[idxNs];
2950  if (m_CurrentLine >= ns.StartLine && m_CurrentLine <= ns.EndLine && ns.StartLine > startLine)
2951  {
2952  // got one, maybe there might be a better fitting namespace
2953  // (embedded namespaces) so keep on looking
2954  pos = static_cast<int>(idxNs);
2955  startLine = ns.StartLine;
2956  }
2957  }
2958 
2959  return pos;
2960 }
2961 
2963 {
2964  int sel = m_Scope->GetSelection();
2965  if (sel != -1 && sel < static_cast<int>(m_ScopeMarks.size()))
2966  UpdateFunctions(sel);
2967 }
2968 
2970 {
2971  int selSc = (m_Scope) ? m_Scope->GetSelection() : 0;
2972  if (selSc != -1 && selSc < static_cast<int>(m_ScopeMarks.size()))
2973  {
2974  int idxFn = m_ScopeMarks[selSc] + m_Function->GetSelection();
2975  if (idxFn != -1 && idxFn < static_cast<int>(m_FunctionsScope.size()))
2976  {
2978  if (ed)
2979  ed->GotoTokenPosition(m_FunctionsScope[idxFn].StartLine,
2980  m_FunctionsScope[idxFn].ShortName);
2981  }
2982  }
2983 }
2984 
3051 {
3052  TRACE(_T("ParseFunctionsAndFillToolbar() : m_ToolbarNeedReparse=%d, m_ToolbarNeedRefresh=%d, "),
3053  m_ToolbarNeedReparse?1:0, m_ToolbarNeedRefresh?1:0);
3055  if (!edMan) // Closing the app?
3056  return;
3057 
3058  cbEditor* ed = edMan->GetBuiltinActiveEditor();
3059  if (!ed || !ed->GetControl())
3060  {
3061  if (m_Function)
3062  m_Function->Clear();
3063  if (m_Scope)
3064  m_Scope->Clear();
3065 
3066  EnableToolbarTools(false);
3067  m_LastFile.Clear();
3068  return;
3069  }
3070 
3071  const wxString filename = ed->GetFilename();
3072  if (filename.IsEmpty())
3073  return;
3074 
3075  bool fileParseFinished = m_NativeParser.GetParser().IsFileParsed(filename);
3076 
3077  // FunctionsScopePerFile contains all the function and namespace information for
3078  // a specified file, m_AllFunctionsScopes[filename] will implicitly insert an new element in
3079  // the map if no such key(filename) is found.
3080  FunctionsScopePerFile* funcdata = &(m_AllFunctionsScopes[filename]);
3081 
3082  // *** Part 1: Parse the file (if needed) ***
3083  if (m_ToolbarNeedReparse || !funcdata->parsed)
3084  {
3085  if (m_ToolbarNeedReparse)
3086  m_ToolbarNeedReparse = false;
3087 
3088  funcdata->m_FunctionsScope.clear();
3089  funcdata->m_NameSpaces.clear();
3090 
3091  // collect the function implementation information, just find the specified tokens in the TokenTree
3092  TokenIdxSet result;
3093  m_NativeParser.GetParser().FindTokensInFile(filename, result,
3095  if (!result.empty())
3096  funcdata->parsed = true; // if the file did have some containers, flag it as parsed
3097  else
3098  fileParseFinished = false; // this indicates the batch parser does not finish parsing for the current file
3099 
3100  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
3101 
3103 
3104  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
3105  {
3106  const Token* token = tree->at(*it);
3107  if (token && token->m_ImplLine != 0)
3108  {
3109  FunctionScope fs;
3110  fs.StartLine = token->m_ImplLine - 1;
3111  fs.EndLine = token->m_ImplLineEnd - 1;
3112  const size_t fileIdx = tree->InsertFileOrGetIndex(filename);
3113  if (token->m_TokenKind & tkAnyFunction && fileIdx == token->m_ImplFileIdx)
3114  {
3115  fs.Scope = token->GetNamespace();
3116  if (fs.Scope.IsEmpty())
3117  fs.Scope = g_GlobalScope;
3118  wxString result_str = token->m_Name;
3119  fs.ShortName = result_str;
3120  result_str << token->GetFormattedArgs();
3121  if (!token->m_BaseType.IsEmpty())
3122  result_str << _T(" : ") << token->m_BaseType;
3123  fs.Name = result_str;
3124  funcdata->m_FunctionsScope.push_back(fs);
3125  }
3126  else if (token->m_TokenKind & (tkEnum | tkClass | tkNamespace))
3127  {
3128  fs.Scope = token->GetNamespace() + token->m_Name + _T("::");
3129  funcdata->m_FunctionsScope.push_back(fs);
3130  }
3131  }
3132  }
3133 
3135 
3136  FunctionsScopeVec& functionsScopes = funcdata->m_FunctionsScope;
3137  NameSpaceVec& nameSpaces = funcdata->m_NameSpaces;
3138 
3139  // collect the namespace information in the current file, this is done by running a parserthread
3140  // on the editor's buffer
3141  m_NativeParser.GetParser().ParseBufferForNamespaces(ed->GetControl()->GetText(), nameSpaces);
3142  std::sort(nameSpaces.begin(), nameSpaces.end(), CodeCompletionHelper::LessNameSpace);
3143 
3144  // copy the namespace information collected in ParseBufferForNamespaces() to
3145  // the functionsScopes, note that the element type FunctionScope has a constructor
3146  // FunctionScope(const NameSpace& ns), type conversion is done automatically
3147  std::copy(nameSpaces.begin(), nameSpaces.end(), back_inserter(functionsScopes));
3148  std::sort(functionsScopes.begin(), functionsScopes.end(), CodeCompletionHelper::LessFunctionScope);
3149 
3150  // remove consecutive duplicates
3151  FunctionsScopeVec::const_iterator it;
3152  it = unique(functionsScopes.begin(), functionsScopes.end(), CodeCompletionHelper::EqualFunctionScope);
3153  functionsScopes.resize(it - functionsScopes.begin());
3154 
3155  TRACE(F(_T("Found %lu namespace locations"), static_cast<unsigned long>(nameSpaces.size())));
3156 #if CC_CODECOMPLETION_DEBUG_OUTPUT == 1
3157  for (unsigned int i = 0; i < nameSpaces.size(); ++i)
3158  CCLogger::Get()->DebugLog(F(_T("\t%s (%d:%d)"),
3159  nameSpaces[i].Name.wx_str(), nameSpaces[i].StartLine, nameSpaces[i].EndLine));
3160 #endif
3161 
3162  if (!m_ToolbarNeedRefresh)
3163  m_ToolbarNeedRefresh = true;
3164  }
3165 
3166  // *** Part 2: Fill the toolbar ***
3167  m_FunctionsScope = funcdata->m_FunctionsScope;
3168  m_NameSpaces = funcdata->m_NameSpaces;
3169 
3170  m_ScopeMarks.clear();
3171  unsigned int fsSize = m_FunctionsScope.size();
3172  if (!m_FunctionsScope.empty())
3173  {
3174  m_ScopeMarks.push_back(0);
3175 
3176  if (m_Scope) // show scope wxChoice
3177  {
3178  wxString lastScope = m_FunctionsScope[0].Scope;
3179  for (unsigned int idx = 1; idx < fsSize; ++idx)
3180  {
3181  const wxString& currentScope = m_FunctionsScope[idx].Scope;
3182 
3183  // if the scope name has changed, push a new index
3184  if (lastScope != currentScope)
3185  {
3186  m_ScopeMarks.push_back(idx);
3187  lastScope = currentScope;
3188  }
3189  }
3190  }
3191  }
3192 
3193  TRACE(F(_T("Parsed %lu functionscope items"), static_cast<unsigned long>(m_FunctionsScope.size())));
3194 #if CC_CODECOMPLETION_DEBUG_OUTPUT == 1
3195  for (unsigned int i = 0; i < m_FunctionsScope.size(); ++i)
3196  CCLogger::Get()->DebugLog(F(_T("\t%s%s (%d:%d)"),
3197  m_FunctionsScope[i].Scope.wx_str(), m_FunctionsScope[i].Name.wx_str(),
3198  m_FunctionsScope[i].StartLine, m_FunctionsScope[i].EndLine));
3199 #endif
3200 
3201  // Does the toolbar need a refresh?
3202  if (m_ToolbarNeedRefresh || m_LastFile != filename)
3203  {
3204  // Update the last editor and changed flag...
3205  if (m_ToolbarNeedRefresh)
3206  m_ToolbarNeedRefresh = false;
3207  if (m_LastFile != filename)
3208  {
3209  TRACE(_T("ParseFunctionsAndFillToolbar() : Update last file is %s"), filename.wx_str());
3210  m_LastFile = filename;
3211  }
3212 
3213  // ...and refresh the toolbars.
3214  m_Function->Clear();
3215 
3216  if (m_Scope)
3217  {
3218  m_Scope->Freeze();
3219  m_Scope->Clear();
3220 
3221  // add to the choice controls
3222  for (unsigned int idxSc = 0; idxSc < m_ScopeMarks.size(); ++idxSc)
3223  {
3224  int idxFn = m_ScopeMarks[idxSc];
3225  const FunctionScope& fs = m_FunctionsScope[idxFn];
3226  m_Scope->Append(fs.Scope);
3227  }
3228 
3229  m_Scope->Thaw();
3230  }
3231  else
3232  {
3233  m_Function->Freeze();
3234 
3235  for (unsigned int idxFn = 0; idxFn < m_FunctionsScope.size(); ++idxFn)
3236  {
3237  const FunctionScope& fs = m_FunctionsScope[idxFn];
3238  if (fs.Name != wxEmptyString)
3239  m_Function->Append(fs.Scope + fs.Name);
3240  else if (fs.Scope.EndsWith(wxT("::")))
3241  m_Function->Append(fs.Scope.substr(0, fs.Scope.length()-2));
3242  else
3243  m_Function->Append(fs.Scope);
3244  }
3245 
3246  m_Function->Thaw();
3247  }
3248  }
3249 
3250  // Find the current function and update
3251  FindFunctionAndUpdate(ed->GetControl()->GetCurrentLine());
3252 
3253  // Control the toolbar state, if the batch parser does not finish parsing the file, no need to update CC toolbar.
3254  EnableToolbarTools(fileParseFinished);
3255 }
3256 
3258 {
3259  if (currentLine == -1)
3260  return;
3261 
3262  m_CurrentLine = currentLine;
3263 
3264  int selSc, selFn;
3265  FunctionPosition(selSc, selFn);
3266 
3267  if (m_Scope)
3268  {
3269  if (selSc != -1 && selSc != m_Scope->GetSelection())
3270  {
3271  m_Scope->SetSelection(selSc);
3272  UpdateFunctions(selSc);
3273  }
3274  else if (selSc == -1)
3275  m_Scope->SetSelection(-1);
3276  }
3277 
3278  if (selFn != -1 && selFn != m_Function->GetSelection())
3279  m_Function->SetSelection(selFn);
3280  else if (selFn == -1)
3281  {
3282  m_Function->SetSelection(-1);
3283 
3284  wxChoice* choice = (m_Scope) ? m_Scope : m_Function;
3285 
3286  int NsSel = NameSpacePosition();
3287  if (NsSel != -1)
3288  choice->SetStringSelection(m_NameSpaces[NsSel].Name);
3289  else if (!m_Scope)
3290  choice->SetSelection(-1);
3291  else
3292  {
3293  choice->SetStringSelection(g_GlobalScope);
3294  wxCommandEvent evt(wxEVT_COMMAND_CHOICE_SELECTED, XRCID("chcCodeCompletionScope"));
3295  wxPostEvent(this, evt);
3296  }
3297  }
3298 }
3299 
3300 void CodeCompletion::UpdateFunctions(unsigned int scopeItem)
3301 {
3302  m_Function->Freeze();
3303  m_Function->Clear();
3304 
3305  unsigned int idxEnd = (scopeItem + 1 < m_ScopeMarks.size()) ? m_ScopeMarks[scopeItem + 1] : m_FunctionsScope.size();
3306  for (unsigned int idxFn = m_ScopeMarks[scopeItem]; idxFn < idxEnd; ++idxFn)
3307  {
3308  const wxString &name = m_FunctionsScope[idxFn].Name;
3309  m_Function->Append(name);
3310  }
3311 
3312  m_Function->Thaw();
3313 }
3314 
3316 {
3317  if (m_Scope)
3318  m_Scope->Enable(enable);
3319  if (m_Function)
3320  m_Function->Enable(enable);
3321 }
3322 
3324 {
3325  // Let the app startup before parsing
3326  // This is to prevent the Splash Screen from delaying so much. By adding
3327  // the timer, the splash screen is closed and Code::Blocks doesn't take
3328  // so long in starting.
3329  m_InitDone = true;
3330 
3331  // Dreaded DDE-open bug related: do not touch the following lines unless for a good reason
3332 
3333  // parse any projects opened through DDE or the command-line
3335  if (curProject && !m_NativeParser.GetParserByProject(curProject))
3336  m_NativeParser.CreateParser(curProject);
3337 
3338  // parse any files opened through DDE or the command-line
3340  if (editor)
3341  m_NativeParser.OnEditorActivated(editor);
3342 }
3343 
3345 {
3346  if (!Manager::Get()->GetConfigManager(wxT("code_completion"))->ReadBool(wxT("/semantic_keywords"), false))
3347  return;
3348  if (!ed)
3350  if (!ed || ed->GetControl()->GetLexer() != wxSCI_LEX_CPP)
3351  return;
3352 
3353  TokenIdxSet result;
3354  int flags = tkAnyContainer | tkAnyFunction;
3355  if (ed->GetFilename().EndsWith(wxT(".c")))
3356  flags |= tkVariable;
3357  m_NativeParser.GetParser().FindTokensInFile(ed->GetFilename(), result, flags);
3358  TokenTree* tree = m_NativeParser.GetParser().GetTokenTree();
3359 
3360  std::set<wxString> varList;
3361  TokenIdxSet parsedTokens;
3362 
3364  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
3365  {
3366  Token* token = tree->at(*it);
3367  if (!token)
3368  continue;
3369  if (token->m_TokenKind == tkVariable) // global var - only added in C
3370  {
3371  varList.insert(token->m_Name);
3372  continue;
3373  }
3374  else if (token->m_TokenKind & tkAnyFunction) // find parent class
3375  {
3376  if (token->m_ParentIndex == wxNOT_FOUND)
3377  continue;
3378  else
3379  token = tree->at(token->m_ParentIndex);
3380  }
3381  if (!token || parsedTokens.find(token->m_Index) != parsedTokens.end())
3382  continue; // no need to check the same token multiple times
3383  parsedTokens.insert(token->m_Index);
3384  for (TokenIdxSet::const_iterator chIt = token->m_Children.begin();
3385  chIt != token->m_Children.end(); ++chIt)
3386  {
3387  const Token* chToken = tree->at(*chIt);
3388  if (chToken && chToken->m_TokenKind == tkVariable)
3389  {
3390  varList.insert(chToken->m_Name);
3391  }
3392  }
3393  // inherited members
3394  if (token->m_Ancestors.empty())
3395  tree->RecalcInheritanceChain(token);
3396  for (TokenIdxSet::const_iterator ancIt = token->m_Ancestors.begin();
3397  ancIt != token->m_Ancestors.end(); ++ancIt)
3398  {
3399  const Token* ancToken = tree->at(*ancIt);
3400  if (!ancToken || parsedTokens.find(ancToken->m_Index) != parsedTokens.end())
3401  continue;
3402  for (TokenIdxSet::const_iterator chIt = ancToken->m_Children.begin();
3403  chIt != ancToken->m_Children.end(); ++chIt)
3404  {
3405  const Token* chToken = tree->at(*chIt);
3406  if ( chToken && chToken->m_TokenKind == tkVariable
3407  && chToken->m_Scope != tsPrivate) // cannot inherit these...
3408  {
3409  varList.insert(chToken->m_Name);
3410  }
3411  }
3412  }
3413  }
3415 
3417  if (!colour_set)
3418  return;
3419 
3420  wxString keywords = colour_set->GetKeywords(ed->GetLanguage(), 3);
3421  for (std::set<wxString>::const_iterator keyIt = varList.begin();
3422  keyIt != varList.end(); ++keyIt)
3423  {
3424  keywords += wxT(" ") + *keyIt;
3425  }
3426  ed->GetControl()->SetKeyWords(3, keywords);
3427  ed->GetControl()->Colourise(0, -1);
3428 }
3429 
3431 {
3432  TRACE(_T("CodeCompletion::OnToolbarTimer(): Enter"));
3433 
3434  if (!ProjectManager::IsBusy())
3435  ParseFunctionsAndFillToolbar();
3436  else
3437  {
3438  TRACE(_T("CodeCompletion::OnToolbarTimer(): Starting m_TimerToolbar."));
3439  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
3440  }
3441 
3442  TRACE(_T("CodeCompletion::OnToolbarTimer(): Leave"));
3443 }
3444 
3446 {
3448  if (!editor)
3449  return;
3450 
3451  TRACE(_T("OnRealtimeParsingTimer"));
3452 
3453  // the real time parsing timer event has arrived, but the document size has changed, in this
3454  // case, we should fire another timer event, and do the parsing job later
3455  const int curLen = editor->GetControl()->GetLength();
3456  if (curLen != m_CurrentLength)
3457  {
3458  m_CurrentLength = curLen;
3459  TRACE(_T("CodeCompletion::OnRealtimeParsingTimer: Starting m_TimerRealtimeParsing."));
3460  m_TimerRealtimeParsing.Start(REALTIME_PARSING_DELAY, wxTIMER_ONE_SHOT);
3461  return;
3462  }
3463 
3464  cbProject* project = m_NativeParser.GetProjectByEditor(editor);
3465  if (project && !project->GetFileByFilename(m_LastFile, false, true))
3466  return;
3467  if (m_NativeParser.ReparseFile(project, m_LastFile))
3468  CCLogger::Get()->DebugLog(_T("Reparsing when typing for editor ") + m_LastFile);
3469 }
3470 
3472 {
3473  cbProject* project = static_cast<cbProject*>(m_TimerProjectSaved.GetClientData());
3474  m_TimerProjectSaved.SetClientData(NULL);
3475 
3476  ProjectsArray* projs = Manager::Get()->GetProjectManager()->GetProjects();
3477  if (projs->Index(project) == wxNOT_FOUND)
3478  return;
3479 
3480  if (IsAttached() && m_InitDone && project)
3481  {
3482  TRACE(_T("OnProjectSavedTimer"));
3483  if (project && m_NativeParser.GetParserByProject(project))
3484  {
3485  ReparsingMap::iterator it = m_ReparsingMap.find(project);
3486  if (it != m_ReparsingMap.end())
3487  m_ReparsingMap.erase(it);
3488  if (m_NativeParser.DeleteParser(project))
3489  {
3490  CCLogger::Get()->DebugLog(_T("Reparsing project."));
3491  m_NativeParser.CreateParser(project);
3492  }
3493  }
3494  }
3495 }
3496 
3498 {
3499  if (ProjectManager::IsBusy() || !IsAttached() || !m_InitDone)
3500  {
3501  m_ReparsingMap.clear();
3502  CCLogger::Get()->DebugLog(_T("Reparsing files failed!"));
3503  return;
3504  }
3505 
3506  TRACE(_T("OnReparsingTimer"));
3507 
3508  ReparsingMap::iterator it = m_ReparsingMap.begin();
3509  if (it != m_ReparsingMap.end() && m_NativeParser.Done())
3510  {
3511  cbProject* project = it->first;
3512  wxArrayString& files = it->second;
3513  if (!project)
3514  project = m_NativeParser.GetProjectByFilename(files[0]);
3515 
3516  if (project && Manager::Get()->GetProjectManager()->IsProjectStillOpen(project))
3517  {
3518  wxString curFile;
3520  if (editor)
3521  curFile = editor->GetFilename();
3522 
3523  size_t reparseCount = 0;
3524  while (!files.IsEmpty())
3525  {
3526  if (m_NativeParser.ReparseFile(project, files.Last()))
3527  {
3528  ++reparseCount;
3529  TRACE(_T("OnReparsingTimer: Reparsing file : ") + files.Last());
3530  if (files.Last() == curFile)
3531  {
3532  m_ToolbarNeedReparse = true;
3533  TRACE(_T("CodeCompletion::OnReparsingTimer: Starting m_TimerToolbar."));
3534  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
3535  }
3536  }
3537 
3538  files.RemoveAt(files.GetCount() - 1);
3539  }
3540 
3541  if (reparseCount)
3542  CCLogger::Get()->DebugLog(F(_T("Re-parsed %lu files."), static_cast<unsigned long>(reparseCount)));
3543  }
3544 
3545  if (files.IsEmpty())
3546  m_ReparsingMap.erase(it);
3547  }
3548 
3549  if (!m_ReparsingMap.empty())
3550  {
3551  TRACE(_T("CodeCompletion::OnReparsingTimer: Starting m_TimerReparsing."));
3552  m_TimerReparsing.Start(EDITOR_ACTIVATED_DELAY, wxTIMER_ONE_SHOT);
3553  }
3554 }
3555 
3557 {
3558  // the m_LastEditor variable was updated in CodeCompletion::OnEditorActivated, after that,
3559  // the editor-activated-timer was started. So, here in the timer handler, we need to check
3560  // whether the saved editor and the current editor are the same, otherwise, no need to update
3561  // the toolbar, because there must be another editor activated before the timer hits.
3562  // Note: only the builtin editor was considered.
3564  if (!editor || editor != m_LastEditor)
3565  {
3566  TRACE(_T("CodeCompletion::OnEditorActivatedTimer(): Not a builtin editor."));
3567  //m_LastEditor = nullptr;
3568  EnableToolbarTools(false);
3569  return;
3570  }
3571 
3572  const wxString& curFile = editor->GetFilename();
3573  // if the same file was activated, no need to update the toolbar
3574  if ( !m_LastFile.IsEmpty() && m_LastFile == curFile )
3575  {
3576  TRACE(_T("CodeCompletion::OnEditorActivatedTimer(): Same as the last activated file(%s)."), curFile.wx_str());
3577  return;
3578  }
3579 
3580  TRACE(_T("CodeCompletion::OnEditorActivatedTimer(): Need to notify NativeParser and Refresh toolbar."));
3581 
3582  m_NativeParser.OnEditorActivated(editor);
3583  TRACE(_T("CodeCompletion::OnEditorActivatedTimer: Starting m_TimerToolbar."));
3584  m_TimerToolbar.Start(TOOLBAR_REFRESH_DELAY, wxTIMER_ONE_SHOT);
3585  TRACE(_T("CodeCompletion::OnEditorActivatedTimer(): Current activated file is %s"), curFile.wx_str());
3586  UpdateEditorSyntax();
3587 }
const TokenIdxSet * GetTokensBelongToFile(size_t fileIdx) const
Definition: tokentree.h:196
ProjectFile * GetFileByFilename(const wxString &filename, bool isRelative=true, bool isUnixFilename=false)
Access a file of the project.
Definition: cbproject.cpp:1049
virtual cbConfigurationPanel * GetConfigurationPanel(wxWindow *parent)
CC&#39;s config dialog.
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
bool GetUseTabs() const
Retrieve whether tabs will be used in indentation.
destructor class member function
Definition: token.h:51
virtual const wxString & GetShortName() const
Returns the editor&#39;s short name.
Definition: editorbase.h:58
int TokenExists(const wxString &name, int parent, short int kindMask)
query tokens by names
Definition: tokentree.cpp:141
bool CallTipActive()
Is there an active call tip?
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
void OnSystemHeadersThreadFinish(CodeBlocksThreadEvent &event)
void OnEditorActivated(CodeBlocksEvent &event)
wxString GetLanguageName(HighlightLanguage lang)
variable
Definition: token.h:57
EVTIMPORT const wxEventType cbEVT_PROJECT_FILE_ADDED
Definition: sdk_events.cpp:104
namespace
Definition: token.h:34
int EndLine
function body (implementation) end line
int m_ParentIndex
Parent Token index.
Definition: token.h:265
void OnSystemHeadersThreadMessage(CodeBlocksThreadEvent &event)
receive event from SystemHeadersThread
int WordEndPosition(int pos, bool onlyWordCharacters)
Get position of end of word.
collect all the header files, so they can be used in auto suggestion after #include<| directive...
int wxNewId()
Base class for code-completion plugins.
Definition: cbplugin.h:732
PluginManager * GetPluginManager() const
Definition: manager.cpp:444
bool EqualFunctionScope(const CodeCompletion::FunctionScope &fs1, const CodeCompletion::FunctionScope &fs2)
constructor class member function
Definition: token.h:48
void OnFunction(wxCommandEvent &event)
Toolbar select event.
class or struct
Definition: token.h:37
EVTIMPORT const wxEventType cbEVT_HIDE_DOCK_WINDOW
Definition: sdk_events.cpp:132
void OnReparsingTimer(wxTimerEvent &event)
delayed for re-parsing
wxString relativeFilename
The relative (to the project) filename of this file.
Definition: projectfile.h:131
virtual void OnAttach()
Any descendent plugin should override this virtual method and perform any necessary initialization...
int StartLine
Definition: parserthread.h:30
wxString GetFormattedArgs() const
remove all &#39; &#39; in the original function argument string
Definition: token.cpp:199
Token * at(int idx)
Definition: tokentree.h:51
#define wxICON_WARNING
bool wxIsspace(const wxUniChar &c)
static bool LoadResource(const wxString &file)
Definition: manager.cpp:499
virtual cbConfigurationPanel * GetProjectConfigurationPanel(wxWindow *parent, cbProject *project)
CC&#39;s config dialog which show in the project options panel.
wxString m_BaseType
this is what the parser believes is the actual return value: e.g.
Definition: token.h:185
void clear()
Definition: tokentree.cpp:74
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
CCProviderStatus
Level of functionality a CC plugin is able to provide.
Definition: cbplugin.h:738
int ReadInt(const wxString &name, int defaultVal=0)
static CCLogger * Get()
Definition: cclogger.cpp:60
bool IsOk() const
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
bool IsComment(int style)
Is style classified as comment for current language?
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
#define EDITOR_ACTIVATED_DELAY
std::vector< FunctionScope > FunctionsScopeVec
vector containing all the function information of a single source file
wxString substr(size_t nStart=0, size_t nLen=npos) const
bool IsRunning() const
std::set< size_t, std::less< size_t > > TokenFileSet
Definition: token.h:19
void GetAbsolutePath(const wxString &basePath, const wxArrayString &targets, wxArrayString &dirs)
search target file names (mostly relative names) under basePath, then return the absolute dirs the re...
#define PARSER_IMG_MACRO_DEF
Definition: parser.h:43
void OnOpenIncludeFile(wxCommandEvent &event)
open the include file under the caret position
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
wxString Lower() const
virtual void DoAutocomplete(const CCToken &token, cbEditor *ed)
Callback for inserting the selected autocomplete entry into the editor.
bool LessFunctionScope(const CodeCompletion::FunctionScope &fs1, const CodeCompletion::FunctionScope &fs2)
static bool IsAppShuttingDown()
Definition: manager.cpp:333
wxArrayString & GetSystemIncludeDirs(cbProject *project, bool force)
get the whole search dirs except the ones locally belong to the c::b project, note this function is u...
int StartLine
function body (implementation) start line
size_t length() const
container like tokens, those tokens can have children tokens
Definition: token.h:70
virtual bool BuildToolBar(wxToolBar *toolBar)
build CC Toolbar
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
Definition: cbproject.h:685
bool wxFileExists(const wxString &filename)
void GotoLine(int line, bool centerOnScreen=true) override
Move the caret at the specified line.
Definition: cbeditor.cpp:2223
wxWindow * pWindow
The window to dock.
Definition: sdk_events.h:137
wxFileName file
The full filename of this file.
Definition: projectfile.h:126
Structure representing an individual calltip with an optional highlighted range.
Definition: cbplugin.h:782
void EditorEventHook(cbEditor *editor, wxScintillaEvent &event)
handle all the editor event
void DoCodeComplete(int caretPos, cbEditor *ed, std::vector< CCToken > &tokens, bool preprocessorOnly=false)
fill the tokens with correct code complete words
void OnEditorActivatedTimer(wxTimerEvent &event)
delayed running of editor activated event, only the last activated editor should be considered ...
wxString GetFilename() const
get a full path of the file which contains the current Token
Definition: token.cpp:185
bool GotoTokenPosition(int line, const wxString &tokenName)
Move the caret at the specified line.
Definition: cbeditor.cpp:2240
wxBitmap GetBitmap(int index) const
int GetLineIndentPosition(int line) const
Retrieve the position before the first non indentation character on a line.
HighlightLanguage GetLanguageForFilename(const wxString &filename)
bool ReadBool(const wxString &name, bool defaultVal=false)
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
DLLIMPORT bool NormalizePath(wxFileName &f, const wxString &base)
Definition: globals.cpp:942
void OnProjectSavedTimer(wxTimerEvent &event)
delayed running after saving project, while many projects&#39; saving
EVTIMPORT const wxEventType cbEVT_PROJECT_ACTIVATE
Definition: sdk_events.cpp:99
size_t Length() const
int ReplaceTarget(const wxString &text)
Replace the target text with the argument text.
a container class to hold all the Tokens getting from parsing stage
Definition: tokentree.h:37
TokenIdxSet m_Children
if it is a class kind token, then it contains all the member tokens
Definition: token.h:268
Event used to request from the main app to add a window to the docking system.
Definition: sdk_events.h:83
static void AddonToolBar(wxToolBar *toolBar, wxString resid)
Definition: manager.cpp:405
wxCStrData c_str() const
wxMenuItem * Append(int id, const wxString &item=wxEmptyString, const wxString &helpString=wxEmptyString, wxItemKind kind=wxITEM_NORMAL)
wxString GetLine(int line) const
Retrieve the contents of a line.
TokenIdxSet m_Ancestors
all the ancestors in the inheritance hierarchy
Definition: token.h:271
EVTIMPORT const wxEventType cbEVT_UPDATE_VIEW_LAYOUT
Definition: sdk_events.cpp:134
bool Matches(const wxString &text, int flags=0) const
DLLIMPORT int cbGetSingleChoiceIndex(const wxString &message, const wxString &caption, const wxArrayString &choices, wxWindow *parent=NULL, const wxSize &size=wxSize(300, 300), int initialSelection=0)
Definition: globals.cpp:1427
int NameSpacePosition() const
find the namespace whose scope covers the current line the m_CurrentLine is used
unsigned int m_Line
Line index where the token was met, which is 1 based.
Definition: token.h:210
FileType
Known file types.
Definition: globals.h:49
cbProject * GetProject() const
Definition: sdk_events.h:41
wxString GetNextToken()
size_t size()
total size of std::vector<Token*>
Definition: tokentree.cpp:98
int m_Index
current Token index in the tree, it is index of the std::vector<Token*>, so use the index...
Definition: token.h:262
void UpdateFunctions(unsigned int scopeItem)
the scope item has changed or becomes invalid, so the associated function wxChoice should be updated...
wxString & GetKeywords(HighlightLanguage lang, int idx)
cbProjectManagerUI & GetUI()
Identify a function body&#39;s position, the underline data structure of the second wxChoice of CC&#39;s tool...
unsigned int m_ImplLineEnd
if token is impl, closing brace line
Definition: token.h:225
void OnCurrentProjectReparse(wxCommandEvent &event)
event handler when user select context menu->reparse file/projects
bool IsAbsolute(wxPathFormat format=wxPATH_NATIVE) const
DLLIMPORT FileType FileTypeOf(const wxString &filename)
Definition: globals.cpp:285
#define wxICON_INFORMATION
int idParserStart
Definition: parser.cpp:93
EVTIMPORT const wxEventType cbEVT_PROJECT_SAVE
Definition: sdk_events.cpp:98
void CallTipShow(int pos, const wxString &definition)
Show a call tip containing a definition near position pos.
virtual wxTreeItemData * GetItemData(const wxTreeItemId &item) const
wxString GetNamespace() const
get a literal string presentation of the namespace.
Definition: token.cpp:253
ProjectFile * GetProjectFile() const
Definition: cbproject.h:61
wxString Name
function&#39;s long name (including arguments and return type)
std::vector< wxString > wxStringVec
Definition: globals.h:205
virtual ~CodeCompletion()
Destructor.
bool m_IsNoExcept
the member method is noexcept (yes/no)
Definition: token.h:251
void AddToken(const FunctionToken &token)
void RegisterImage(int type, const wxBitmap &bmp)
Register an image for use in autocompletion lists.
wxArrayString m_Aliases
used for namespace aliases
Definition: token.h:280
void NotifyMissingFile(const wxString &name)
Definition: globals.h:370
EditorBase * GetEditor() const
Definition: sdk_events.h:44
#define wxT(string)
bool m_IsTemp
local (automatic) variable
Definition: token.h:245
TokenScope m_Scope
public? private? protected?
Definition: token.h:231
int GetModificationType() const
Definition: wxscintilla.h:5457
#define wxNOT_FOUND
void SetPath(const wxString &path, wxPathFormat format=wxPATH_NATIVE)
wxString DisplayName() const
a short simple string to show the token information, this usually generate for show the tip message w...
Definition: token.cpp:80
EVTIMPORT const wxEventType cbEVT_PROJECT_FILE_CHANGED
Definition: sdk_events.cpp:106
virtual std::vector< CCCallTip > GetCallTips(int pos, int style, cbEditor *ed, int &argsPos)
Supply content for the calltip at the specified location.
Represents a file in a Code::Blocks project.
Definition: projectfile.h:39
int GetLexer() const
Retrieve the lexing language of the document.
void OnAppDoneStartup(CodeBlocksEvent &event)
SDK event when application has started up.
size_t GetMenuItemCount() const
bool empty() const
size_t find(const wxString &str, size_t nStart=0) const
A generic Code::Blocks event.
Definition: sdk_events.h:20
void OnRenameSymbols(wxCommandEvent &event)
CC&#39;s re-factoring function, rename a symbol.
EFileType FileType(const wxString &filename, bool force_refresh=false)
return a file type, which can be either header files or implementation files or other files ...
void DebugLog(const wxString &msg)
Definition: cclogger.cpp:107
#define wxSCI_C_WXSMITH
WXSMITH begin # Keep in sync with wxscinilla.h -> wxSCI_C_WXSMITH Keep in sync with SciLexer...
Definition: wxscintilla.h:663
int GetLineEndPosition(int line) const
Get the position after the last visible characters on a line.
Code completion plugin has those features: show tool-tip when the mouse hover over the variables/func...
int WordStartPosition(int pos, bool onlyWordCharacters)
Get position of start of word.
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
void OnProjectClosed(CodeBlocksEvent &event)
void RecalcInheritanceChain(Token *token)
convert the Token&#39;s ancestor string to it&#39;s IDs this contains recursive calls, for example in such co...
Definition: tokentree.cpp:643
bool empty()
check to see whether the TokenTree is empty
Definition: tokentree.h:63
wxUSE_UNICODE_dependent wxChar
xxxxx **begin result *wxChar GetNextNonWhitespaceChar(cbStyledTextCtrl *control, int position)
for OnGotoFunction(), search forward /* yyy
const wxArrayString & GetIncludeDirs() const
Definition: parser_base.h:160
void OnEditorSave(CodeBlocksEvent &event)
SDK editor related events.
const wxArrayString & GetDirs() const
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
bool EqualNameSpace(const NameSpace &ns1, const NameSpace &ns2)
wxString GetStrippedArgs() const
remove all default value of the function argument string, e.g.
Definition: token.cpp:206
PluginManager manages plugins.
Definition: pluginmanager.h:76
std::vector< NameSpace > NameSpaceVec
Definition: parserthread.h:34
bool MakeRelativeTo(const wxString &pathBase=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
virtual int GetImageCount() const
virtual const wxString & GetFilename() const
Get the editor&#39;s filename (if applicable).
Definition: editorbase.h:45
void wxPostEvent(wxEvtHandler *dest, const wxEvent &event)
EVTIMPORT const wxEventType cbEVT_EDITOR_CLOSE
Definition: sdk_events.cpp:80
bool AppendDir(const wxString &dir)
Event functor class.
Definition: cbfunctor.h:37
Represents a Code::Blocks project.
Definition: cbproject.h:96
#define TOOLBAR_REFRESH_DELAY
wxString GetIncludeFile() const
int GetEOLMode() const
Retrieve the current end of line mode - one of wxSCI_EOL_CRLF, wxSCI_EOL_CR, or wxSCI_EOL_LF.
virtual CCProviderStatus GetProviderStatusFor(cbEditor *ed)
Does this plugin handle code completion for the editor ed?
int GetCurrentLine()
Manually declared methods.
EditorBase * GetActiveEditor()
size_t find_first_of(const char *sz, size_t nStart=0) const
a symbol found in the parsed files, it can be many kinds, such as a variable, a class and so on...
Definition: token.h:82
#define TRACE(format, args...)
wxString & RemoveLast(size_t n=1)
wxArrayInt GetSelectedIndices() const
cbStyledTextCtrl * GetControl() const
Returns a pointer to the underlying cbStyledTextCtrl object (which itself is the wxWindows implementa...
Definition: cbeditor.cpp:842
long idSystemHeadersThreadFinish
event ids used to notify parent objects
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
virtual std::vector< CCToken > GetTokenAt(int pos, cbEditor *ed, bool &allowCallTip)
Supply the definition of the token at the specified location.
display symbols of current file
Definition: parser_base.h:43
ModuleType
The type of module offering a context menu.
Definition: globals.h:38
void OnViewClassBrowser(wxCommandEvent &event)
event handler when user click Menu->View->Symbols browser
void DoCodeCompleteIncludes(cbEditor *ed, int &tknStart, int tknEnd, std::vector< CCToken > &tokens)
fill the tokens with correct include file names
void ParseFunctionsAndFillToolbar()
normally the editor has changed, then CC need to parse the document again, and (re)construct the inte...
int GetTabWidth() const
Retrieve the visible size of a tab.
wxString & Last()
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
int DoAllMethodsImpl()
ContextMenu->Insert-> All class methods.
wxChar GetLastNonWhitespaceChar(cbStyledTextCtrl *control, int position)
for OnGotoFunction(), search backward
ExitCode Wait(wxThreadWait flags=wxTHREAD_WAIT_BLOCK)
DLLIMPORT bool IsSuffixOfPath(wxFileName const &suffix, wxFileName const &path)
Definition: globals.cpp:962
bool LessNameSpace(const NameSpace &ns1, const NameSpace &ns2)
cbEditor * GetBuiltinActiveEditor()
Definition: editormanager.h:95
#define HL_NONE
Definition: globals.h:167
EditorColourSet * GetColourSet() const
Get the colour set in use.
Definition: cbeditor.h:170
void RemoveAllEventSinksFor(void *owner)
Definition: manager.cpp:570
bool IsCharacter(int style)
Is style classified as character for current language?
wxString ShortName
function&#39;s base name (without scope prefix)
wxString Scope
class or namespace
bool GetMatch(size_t *start, size_t *len, size_t index=0) const
virtual cbTreeCtrl * GetTree()=0
Retrieve a pointer to the project manager&#39;s tree (GUI).
wxMenuItem * AppendSeparator()
Base class that all "editors" should inherit from.
Definition: editorbase.h:30
LogManager * GetLogManager() const
Definition: manager.cpp:439
long idSystemHeadersThreadMessage
DLLIMPORT bool IsWindowReallyShown(wxWindow *win)
Finds out if a window is really shown.
Definition: globals.cpp:931
int GetCurrentPos() const
Returns the position of the caret.
virtual void OnRelease(bool appShutDown)
void OnGotoPrevFunction(wxCommandEvent &event)
navigate to the previous function body
void OnProjectSaved(CodeBlocksEvent &event)
wxString & Item(size_t nIndex)
cbProject * GetActiveProject()
Retrieve the active project.
Structure representing a generic token, passed between CC plugins and CCManager.
Definition: cbplugin.h:746
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
bool IsString(int style)
Is style classified as string for current language?
static wxString AutocompGetName(const wxString &selected)
when user select one item in the suggestion list, the selected contains the full display name...
int GetLength() const
Returns the number of bytes in the document.
bool IsEmpty() const
bool m_IsConst
the member method is const (yes/no)
Definition: token.h:248
void OnGotoDeclaration(wxCommandEvent &event)
handle both goto declaration and implementation event
wxString displayName
Verbose string representing the token.
Definition: cbplugin.h:777
void clear()
wxEventType wxEVT_TIMER
#define CC_LOCKER_TRACK_TT_MTX_UNLOCK(M)
Definition: cclogger.h:165
const wxStringCharType * wx_str() const
virtual int ShowModal()
#define wxTIMER_ONE_SHOT
wxString GetTextRange(int startPos, int endPos)
Retrieve a range of text.
virtual bool IsBuiltinEditor() const
Is this a built-in editor?
Definition: editorbase.cpp:209
wxMenu * GetMenu(size_t menuIndex) const
void OnProjectFileChanged(CodeBlocksEvent &event)
void OnUnimplementedClassMethods(wxCommandEvent &event)
handle CC&#39;s context menu->insert "All class methods without implementation..."
#define wxSCI_LEX_CPP
Definition: wxscintilla.h:480
wxString wxEmptyString
void OnFindReferences(wxCommandEvent &event)
CC&#39;s re-factoring function, find all the reference place.
bool IsAlive() const
wxString GetCurLine(int *linePos=NULL)
Retrieve the text of the line containing the caret.
bool s_DebugSmartSense
if this option is enabled, there will be many log messages when doing semantic match ...
void OnUpdateUI(wxUpdateUIEvent &event)
event handler for updating UI e.g.
MacrosManager * GetMacrosManager() const
Definition: manager.cpp:454
The goto function dialog allow user to type a function name, and filter out the functions.
int GetFilesCount()
Definition: cbproject.h:142
cbEditor * Open(const wxString &filename, int pos=0, ProjectFile *data=nullptr)
const wxString & _(const wxString &string)
wxString & Trim(bool fromRight=true)
void OnProjectFileAdded(CodeBlocksEvent &event)
int FindMenu(const wxString &title) const
void ReplaceMacros(wxString &buffer, ProjectBuildTarget *target=nullptr, bool subrequest=false)
Base class for plugin configuration panels.
cbEditor * GetBuiltinEditor(EditorBase *eb)
wxString m_Args
If it is a function Token, then this value is function arguments, e.g.
Definition: token.h:194
void OnSelectedFileReparse(wxCommandEvent &event)
void GotoFunctionPrevNext(bool next=false)
navigate between function bodies
#define wxSCI_MOD_INSERTTEXT
Notifications Type of modification and the action which caused the modification.
Definition: wxscintilla.h:413
Plugin registration object.
Definition: cbplugin.h:1099
Functor class for use as a editor modification operations hook.
Definition: editor_hooks.h:52
void OnWorkspaceChanged(CodeBlocksEvent &event)
SDK workspace related events.
void OnRealtimeParsingTimer(wxTimerEvent &event)
event fired from the edit event hook function to indicate parsing while editing
void EnableToolbarTools(bool enable=true)
enable the two wxChoices
#define wxSCI_KEYWORDSET_MAX
Maximum value of keywordSet parameter of SetKeyWords.
Definition: wxscintilla.h:404
unsigned int m_ImplFileIdx
function implementation file index
Definition: token.h:216
#define CC_LOCKER_TRACK_TT_MTX_LOCK(M)
Definition: cclogger.h:159
wxArray< int > wxArrayInt
EVTIMPORT const wxEventType cbEVT_APP_STARTUP_DONE
Definition: sdk_events.cpp:68
int DoClassMethodDeclImpl()
ContextMenu->Insert-> declaration/implementation.
int PositionFromLine(int line) const
Retrieve the position at the start of a line.
static bool IsBusy()
For use with plugins.
bool TestIncludeLine(wxString const &line)
for CodeCompleteIncludes() a line has some pattern like below
virtual void BuildMenu(wxMenuBar *menuBar)
build menus in the main frame
void Colourise(int start, int end)
Colourise a segment of the document using the current lexing language.
Abstract base hook functor interface.
Definition: editor_hooks.h:26
bool HasMoreTokens() const
#define REALTIME_PARSING_DELAY
void UpdateEditorSyntax(cbEditor *ed=NULL)
highlight member variables
void OnProjectActivated(CodeBlocksEvent &event)
SDK project related events.
void SetKeyWords(int keyWordSet, const wxString &keyWords)
Set up the key words used by the lexer.
enum
Definition: token.h:40
EditorColourSet * GetColourSet()
wxString & Append(const char *psz)
A file editor.
Definition: cbeditor.h:43
virtual int FindItem(const wxString &itemString) const
EVTIMPORT const wxEventType cbEVT_EDITOR_ACTIVATED
Definition: sdk_events.cpp:83
bool IsEmpty() const
int GetCharAt(int pos) const
Returns the character byte at the position.
DLLIMPORT void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode=pdlBest, bool enforce=false)
Definition: globals.cpp:1177
used for iterations
void Clear()
int idMenuGotoDeclaration
void OnToolbarTimer(wxTimerEvent &event)
delayed for toolbar update
cbProject * GetProject() const
Definition: cbproject.h:59
wxString GetPath(int flags=wxPATH_GET_VOLUME, wxPathFormat format=wxPATH_NATIVE) const
size_t GetFileMatches(const wxString &filename, std::set< size_t > &result, bool caseSensitive, bool is_prefix)
Definition: tokentree.cpp:843
void OnEditorClosed(CodeBlocksEvent &event)
static const size_t npos
size_t Len() const
any kind of functions
Definition: token.h:73
long g_idCCDebugLogger
Definition: cclogger.cpp:26
DLLIMPORT wxString GetEOLStr(int eolMode=-1)
Reads settings if eolMode is -1 Expected input (defined in sdk/wxscintilla/include/wx/wxscintilla.h) is: wxSCI_EOL_CRLF=0, wxSCI_EOL_CR=1, or wxSCI_EOL_LF=2.
Definition: globals.cpp:812
bool IsRelative(wxPathFormat format=wxPATH_NATIVE) const
EVTIMPORT const wxEventType cbEVT_SHOW_DOCK_WINDOW
Definition: sdk_events.cpp:131
void Log(const wxString &msg, int i=app_log, Logger::level lv=Logger::info)
Definition: logmanager.h:140
void GotoPos(int caret)
Set caret to a position and ensure it is visible.
wxString GetLineIndentString(int line=-1) const
Returns the specified line&#39;s (0-based) indentation (whitespace) string.
Definition: cbeditor.cpp:2778
FileTreeDataKind GetKind() const
Definition: cbproject.h:58
#define wxSCI_INVALID_POSITION
Definition: wxscintilla.h:70
int GetFindMenuItemFirst() const
Returns the position of the first menu item in the find group.
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
wxString & insert(size_t nPos, const wxString &str)
void DebugLog(const wxString &msg, Logger::level lv=Logger::info)
Definition: logmanager.h:146
bool ProcessEvent(CodeBlocksEvent &event)
Definition: manager.cpp:246
bool EndsWith(const wxString &suffix, wxString *rest=NULL) const
int idMenuGotoImplementation
wxString GetCommonTopLevelPath() const
Definition: cbproject.cpp:423
bool GetModified() const override
Definition: cbproject.cpp:162
void RegisterFindMenuItems(bool before, int count)
Can be called by plugins&#39; BuildModuleMenu when building the EditorManager&#39;s context menu...
int idGotoImplementation
void OnProjectFileRemoved(CodeBlocksEvent &event)
EVTIMPORT const wxEventType cbEVT_WORKSPACE_CHANGED
Definition: sdk_events.cpp:111
void RegisterEventSink(wxEventType eventType, IEventFunctorBase< CodeBlocksEvent > *functor)
Definition: manager.cpp:550
general function, not constructor nor destructor
Definition: token.h:54
DLLIMPORT HookFunctorBase * UnregisterHook(int id, bool deleteHook=true)
Unregister a previously registered project loading/saving hook.
int GetStyleAt(int pos) const
Returns the style byte at the position.
wxMenuItem * FindChildItem(int id, size_t *pos=NULL) const
void Init(wxEvtHandler *parent, int logId, int debugLogId, int addTokenId=-1)
Definition: cclogger.cpp:69
void OnCCDebugLogger(CodeBlocksThreadEvent &event)
CC&#39;s own debug logger, to handle log event sent from other worker threads or itself(the main GUI thre...
size_t Add(const wxString &str, size_t copies=1)
void OnGotoFunction(wxCommandEvent &event)
event handler when user click Menu->Search->Goto function
void FindFunctionAndUpdate(int currentLine)
the caret has changed, so the wxChoice need to be updated to indicates which scope and function in wh...
void SetTargetStart(int start)
Sets the position that starts the target which is used for updating the document without affecting th...
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
void AddListEntries(const wxArrayString &IncludeFile)
void OnGotoNextFunction(wxCommandEvent &event)
navigate to the next function body
int LineFromPosition(int pos) const
Retrieve the line containing a position.
void OnCCLogger(CodeBlocksThreadEvent &event)
CC&#39;s own logger, to handle log events sent from other worker threads or itself(the main GUI thread)...
void OnSelectedProjectReparse(wxCommandEvent &event)
wxThreadError Run()
#define wxSCI_MOD_DELETETEXT
Definition: wxscintilla.h:414
EVTIMPORT const wxEventType cbEVT_PROJECT_CLOSE
Definition: sdk_events.cpp:96
wxString GetText() const
Retrieve all the text in the document.
size_t GetCount() const
int idParserEnd
Definition: parser.cpp:94
int Find(wxUniChar ch, bool fromEnd=false) const
EVTIMPORT const wxEventType cbEVT_EDITOR_OPEN
Definition: sdk_events.cpp:81
wxUniChar GetChar(size_t n) const
void SetTargetEnd(int end)
Sets the position that ends the target which is used for updating the document without affecting the ...
wxUniChar Last() const
void OnParserStart(wxCommandEvent &event)
batch parsing start event this event usually be fired when an Parser object try to start parsing task...
ProjectsArray * GetProjects()
Retrieve an array of all the opened projects.
void DoParseOpenedProjectAndActiveEditor()
if C::B starts up with some projects opened, this function will be called to parse the already opened...
void OnParserEnd(wxCommandEvent &event)
batch parsing end event this event usually be fired when the task pool becomes empty ...
virtual void BuildModuleMenu(const ModuleType type, wxMenu *menu, const FileTreeData *data=0)
build context popup menu
the Parser object is newly created, and we are parsing the predefined macro buffer, the source files, and finally mark the project&#39;s tokens as local
Definition: parser.h:93
virtual wxString GetDocumentation(const CCToken &token)
Supply html formatted documentation for the passed token.
static wxString g_GlobalScope(_T("<global>"))
Scopes choice name for global functions in CC&#39;s toolbar.
void OnScope(wxCommandEvent &event)
Toolbar select event.
EVTIMPORT const wxEventType cbEVT_PROJECT_FILE_REMOVED
Definition: sdk_events.cpp:105
void RereadOptions()
read CC&#39;s options, mostly happens the user change some setting and press APPLY
void UpdateToolBar()
update CC&#39;s ToolBar, the user may disable the first wxChoice, so we need to recreate the wxChoice and...
bool EditorHasNameUnderCursor(wxString &NameUnderCursor, bool &IsInclude)
return identifier like token string under the current cursor pointer
macro definition, such as: #define AAA(x,y) f(x,y), where AAA is a token of tkMacroDef ...
Definition: token.h:63
wxString GetImplFilename() const
get a full path of the file which contains the function implementation.
Definition: token.cpp:192
virtual std::vector< CCToken > GetAutocompList(bool isAuto, cbEditor *ed, int &tknStart, int &tknEnd)
Supply content for the autocompletion list.
void RemoveAt(size_t nIndex, size_t count=1)
wxString SubString(size_t from, size_t to) const
HighlightLanguage GetLanguage() const
Definition: cbeditor.h:292
void MatchCodeStyle(wxString &str, int eolStyle=wxSCI_EOL_LF, const wxString &indent=wxEmptyString, bool useTabs=false, int tabSize=4)
modify the string content to follow the current editor&#39;s code style The code style includes the EOL...
void OnEditorOpen(CodeBlocksEvent &event)
int Printf(const wxString &pszFormat,...)
const FunctionToken * GetToken(int index) const
EVTIMPORT const wxEventType cbEVT_EDITOR_SAVE
Definition: sdk_events.cpp:86
wxString m_FullType
this is the full return value (if any): e.g.
Definition: token.h:182
wxMenuItemList & GetMenuItems()
#define CodeBlocksThreadEventHandler(func)
Definition: sdk_events.h:236
virtual void SetSelection(int n)
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
void OnClassMethod(wxCommandEvent &event)
handle CC&#39;s context menu->insert "Class method declaration/implementation..."
void FunctionPosition(int &scopeItem, int &functionItem) const
helper method in finding the function position in the vector for the function containing the current ...
long g_idCCLogger
Definition: cclogger.cpp:25
#define NULL
Definition: prefix.cpp:59
void ClearRegisteredImages()
Clear all the registered images.
void DoCodeCompletePreprocessor(int tknStart, int tknEnd, cbEditor *ed, std::vector< CCToken > &tokens)
fill the tokens with correct preprocessor directives, such as #i will prompt "if", "include"
bool wxGetKeyState(wxKeyCode key)
static wxString Format(const wxString &format,...)
wxString Mid(size_t first, size_t nCount=wxString::npos) const
int id
CCManager will pass this back unmodified. Use it as an internal identifier for the token...
Definition: cbplugin.h:774
wxMenuItem * Insert(size_t pos, wxMenuItem *menuItem)
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395
HighlightLanguage GetHighlightLanguage(int lexer)
wxString Name
Definition: parserthread.h:29
bool IsPreprocessor(int style)
Is style classified as preprocessor for current language?
virtual wxTreeItemId GetTreeSelection()=0
Get the selection of the project manager&#39;s tree (GUI).
int CompareStringLen(const wxString &first, const wxString &second)
Sorting in GetLocalIncludeDirs()
wxArrayString buildTargets
An array of strings, containing the names of all the build targets this file belongs to...
Definition: projectfile.h:190
size_t GetDirCount() const
std::set< wxString > StringSet
Definition: parser_base.h:19
Event used to request from the main app to manage the view layouts.
Definition: sdk_events.h:158
used to record the position of a token when user click find declaration or implementation ...
DLLIMPORT int RegisterHook(HookFunctorBase *functor)
Register a project loading/saving hook.