Code::Blocks  SVN r11506
doxygen_parser.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: 10145 $
6  * $Id: doxygen_parser.cpp 10145 2015-03-10 02:54:16Z ollydbg $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/doxygen_parser.cpp $
8  */
9 
10 #include <sdk.h>
11 
12 #ifndef CB_PRECOMP
13  #include <wx/string.h>
14 
15  #include <cbeditor.h>
16  #include <editormanager.h>
17  #include <sdk_events.h>
18 #endif
19 
20 #include <wx/tokenzr.h>
21 #include <wx/html/htmlwin.h>
22 
23 #include <cbstyledtextctrl.h>
24 
25 #include "doxygen_parser.h"
26 
27 #include "cbcolourmanager.h"
28 #include "codecompletion.h"
29 
30 // Doxygen documents parser
31 namespace Doxygen
32 {
33  /* source: http://www.stack.nl/~dimitri/doxygen/commands.html
34  Some commands have one or more arguments. Each argument has a
35  certain range:
36 
37  If <sharp> braces are used the argument is a single word.
38 
39  If (round) braces are used the argument extends until the end of
40  the line on which the command was found.
41 
42  If {curly} braces are used the argument extends until the next
43  paragraph. Paragraphs are delimited by a blank line or by
44  a section indicator.
45 
46  If in addition to the above argument specifiers [square] brackets
47  are used the argument is optional.
48  */
50  _T(""), // no keyword
51  _T("param"), // \param [(dir)] <parameter-name> { parameter description }
52  _T("return"), _T("result"), // \return { description of the return value }
53  _T("brief"), _T("short"), // \brief { brief description }
54  _T("sa"), _T("see"), // \sa { references }
55 
56  // structural commands:
57  _T("class"), _T("struct"), //
58  _T("union"), //
59  _T("enum"), //
60  _T("namespace"), //
61 
62  _T("fn"), //
63  _T("var"), //
64  _T("def"), //
65 
66  _T("code"), //
67  _T("endcode"), //
68 
69  _T("b"), //
70 
71  };
72 
73  const int DoxygenParser::KwCount = sizeof(DoxygenParser::Keywords)/sizeof(DoxygenParser::Keywords[0]);
74 
76 
78  m_FoundKw(-1),
79  m_Pos(-1)
80  {
81  assert(KwCount == KEYWORDS_COUNT);
82  }
83 
85  {
86  ++m_Pos;
87  if (m_Pos >= (int)doc.size())
88  return KEYWORDS_COUNT;
89 
90  if ( IsKeywordBegin(doc) )
91  {
92  ++m_Pos;
93  int fkw = CheckKeyword(doc);
94  if (fkw != NO_KEYWORD)
95  return fkw;
96  }
97 
98  return NO_KEYWORD;
99  }
100 
101  int DoxygenParser::GetArgument(const wxString& doc, int range, wxString& output)
102  {
103  SkipDecorations(doc);
104 
105  int nestedArgsCount = 0;
106  switch (range)
107  {
108  case RANGE_PARAGRAPH:
109  nestedArgsCount = GetParagraphArgument(doc, output);
110  break;
111  case RANGE_WORD:
112  GetWordArgument(doc, output);
113  break;
114  case RANGE_BLOCK:
115  GetBlockArgument(doc, output);
116  break;
117  case RANGE_LINE:
118  nestedArgsCount = GetLineArgument(doc,output);
119  break;
120  default:
121  break;
122  }
123  --m_Pos;
124  return nestedArgsCount;
125  }
126 
128  {
129  return m_Pos;
130  }
131 
132  void DoxygenParser::ReplaceInDoc(wxString& doc, size_t start, size_t count,
133  const wxString& str)
134  {
135  if (start < (size_t)m_Pos)
136  {
137  doc.replace(start, count, str);
138  m_Pos += str.size() - count;
139  }
140  else
141  doc.replace(start, count, str);
142  }
143 
145  {
146  const wxString& kw = DoxygenParser::Keywords[m_FoundKw];
147  int posBegin = m_Pos - kw.size();
148  ReplaceInDoc(doc, posBegin - 1, kw.size()+1, str);
149  }
150 
152  {
153  int kwLen = 0;
154  int machingKwCount = KwCount;
155  bool foundOne = false;
156  bool isKw[KEYWORDS_COUNT] = {};
157  for (int j = 0; j < KEYWORDS_COUNT; ++j)
158  isKw[j] = true;
159 
160  while (m_Pos < (int)doc.size() && !foundOne)
161  {
162  for (int k = 0; k < KwCount; ++k)
163  {
164  if ( isKw[k] && (kwLen >= (int)Keywords[k].size() ||
165  doc[m_Pos + kwLen] != Keywords[k][kwLen]) )
166  {
167  isKw[k] = false;
168  --machingKwCount;
169  if (machingKwCount == 1)
170  {
171  foundOne = true;
172  //end loop:
173  k = KwCount;
174  --kwLen;
175  }
176  }//if
177 
178  }// for (k)
179  ++kwLen;
180  }//while
181 
182  if (!foundOne)
183  return NO_KEYWORD;
184 
185  int foundKw = 0;
186  for (int l = 0; l < KwCount; ++l)
187  {
188  if (isKw[l])
189  {
190  foundKw = l;
191  break;
192  }
193  }// for (l)
194 
195  if (doc.size() < m_Pos + Keywords[foundKw].size())
196  return NO_KEYWORD;
197 
198  while (kwLen < (int)Keywords[foundKw].size())
199  {
200  if (isKw[foundKw])
201  isKw[foundKw] = doc[m_Pos + kwLen] == Keywords[foundKw][kwLen];
202  else
203  return NO_KEYWORD;
204 
205  ++kwLen;
206  }
207  //now kwLen = Keywords[foundKw].size()
208 
209  if (m_Pos + kwLen < (int)doc.size())
210  {
211  if ( !IsOneOf(doc[m_Pos + kwLen], _T(" \t\n")))
212  return NO_KEYWORD;
213  }
214 
215  //got valid keyword
216  m_FoundKw = foundKw;
217  m_Pos = m_Pos + kwLen;
218  return foundKw;
219  }
220 
222  {
223  int nestedArgsCount = 0;
224  while (m_Pos < (int)doc.size())
225  {
226  int tmpPos = m_Pos;
227  nestedArgsCount += GetLineArgument(doc, output);
228  HandleNewLine(doc,output,_T(' '));
229  if (doc[m_Pos] == _T('\n') || m_Pos == tmpPos)
230  {
231  //++i;
232  break;
233  }
234 
235  }
236  return nestedArgsCount;
237  }
238 
240  {
241  bool gotWord = false;
242  while (m_Pos < (int)doc.size())
243  {
244  wxChar c = doc[m_Pos];
245  switch (c)
246  {
247  case _T('\n'):
248  case _T(' '):
249  case _T('\t'):
250  if (gotWord)
251  return;
252 
253  ++m_Pos;
254  break;
255  default:
256  output += doc[m_Pos];
257  ++m_Pos;
258  gotWord = true;
259  }
260  }
261  }
262 
264  {
265  //TODO: add implementation
266  (void)doc;
267  (void)output;
268  }
269 
271  {
272  int nestedArgsCount = 0;
273  while (m_Pos < (int)doc.size())
274  {
275  wxChar c = doc[m_Pos];
276  switch (c)
277  {
278  case _T('\n'):
279  //SkipDecorations(doc);
280  return nestedArgsCount;
281  break;
282 
283  case _T('@'):
284  case _T('\\'):
285  if ( IsKeywordBegin(doc) )
286  {
287  int tmpI = m_Pos;
288  ++m_Pos;
289  int kw = CheckKeyword(doc);
290  m_Pos = tmpI;
291  if (kw < NESTED_KEYWORDS_BEGIN && kw != NO_KEYWORD)
292  return nestedArgsCount;
293  else
294  {
295  output += doc[m_Pos];
296  ++nestedArgsCount;
297  }
298  }
299  ++m_Pos;
300  break;
301 
302  default:
303  output += doc[m_Pos];
304  ++m_Pos;
305  }// switch
306 
307  }// while
308  return nestedArgsCount;
309  }
310 
311 
313  {
314  bool isSpecial = doc[m_Pos] == _T('@') || doc[m_Pos] == _T('\\');
315 
316  if (!isSpecial)
317  return false;
318 
319  if (m_Pos > 0)
320  {
321  bool isPrevWhitespace = doc[m_Pos - 1] == _T(' ') ||
322  doc[m_Pos - 1] == _T('\n') || doc[m_Pos - 1] == _T('\t');
323 
324  return isPrevWhitespace;
325  }
326 
327  if (m_Pos == 0)
328  return true;
329 
330  return false;
331  }
332 
333  bool DoxygenParser::IsOneOf(wxChar c, const wxChar* chars) const
334  {
335  while (*chars)
336  {
337  if (c == *chars)
338  return true;
339  ++chars;
340  }
341  return false;
342  }
343 
344  bool DoxygenParser::IsEnd(const wxString& doc) const
345  {
346  return m_Pos >= (int)doc.size();
347  }
348 
349  int DoxygenParser::GetEndLine(const wxString& doc) const
350  {
351  size_t endLine = doc.find(_T('\n'), m_Pos);
352  if (endLine == wxString::npos)
353  endLine = doc.size();
354  return endLine;
355  }
356 
358  {
359  //ignore everything from beginig of line to first word
360  if (doc[m_Pos] != _T('\n'))
361  return false;
362  ++m_Pos;
363 
364  while (!IsEnd(doc) && IsOneOf(doc[m_Pos], _T(" \t*/")))
365  ++m_Pos;
366 
367  return true;
368  }
369 
371  const wxString& replaceWith)
372  {
373  if ( SkipDecorations(doc) )
374  {
375  output += replaceWith;
376  return true;
377  }
378  return false;
379  }
380 
381 }// end of Doxygen namespace
382 
383 
384 /*Documentation Popup*/
385 
386 namespace HTMLTags
387 {
388  static const wxString br = _T("<br>");
389  static const wxString sep = _T(" ");
390  static const wxString b1 = _T("<b>");
391  static const wxString b0 = _T("</b>");
392 
393  static const wxString a1 = _T("<a>");
394  static const wxString a0 = _T("</a>");
395 
396  static const wxString i1 = _T("<i>");
397  static const wxString i0 = _T("</i>");
398 
399  static const wxString pre1 = _T("<pre>");
400  static const wxString pre0 = _T("</pre>");
401 
402  static const wxString nbsp(_T("&nbsp;"));
403  static const wxString tab = nbsp + nbsp + nbsp;
404 }
405 
406 /* DocumentationPopup static member functions implementation: */
407 
409 {
410  using namespace HTMLTags;
411 
412  wxString arguments[5];
413  wxString &plainText = arguments[0], &brief = arguments[1], &params = arguments[2],
414  &seeAlso = arguments[3], &returns = arguments[4];
415 
416  Doxygen::DoxygenParser parser;
417  int keyword = parser.FindNextKeyword(doc);
418  while (keyword < Doxygen::KEYWORDS_COUNT)
419  {
420  using namespace Doxygen;
421  switch (keyword)
422  {
423  case NO_KEYWORD:
424  parser.GetArgument(doc, RANGE_PARAGRAPH, plainText);
425  break;
426  case PARAM:
427  params += tab;
428  parser.GetArgument(doc, RANGE_PARAGRAPH, params);
429  params += br;
430  break;
431  case BRIEF:
432  case Doxygen::SHORT:
433  parser.GetArgument(doc, RANGE_PARAGRAPH, brief);
434  break;
435  case RETURN:
436  case RESULT:
437  parser.GetArgument(doc, RANGE_PARAGRAPH, returns);
438  break;
439  case SEE:
440  case SA:
441  parser.GetArgument(doc, RANGE_PARAGRAPH, seeAlso);
442  break;
443  case CODE:
444  plainText += pre1;
445  break;
446  case ENDCODE:
447  plainText += pre0;
448  break;
449  default:
450  break;
451  }
452  keyword = parser.FindNextKeyword(doc);
453  }
454  // process nested keywords:
455  for (size_t i = 0; i < (size_t)(sizeof(arguments)/sizeof(arguments[0])); ++i)
456  {
457  arguments[i].Trim(true).Trim(false);
458 
459  Doxygen::DoxygenParser dox_parser;
460  int dox_keyword = dox_parser.FindNextKeyword(arguments[i]);
461  while (dox_keyword < Doxygen::KEYWORDS_COUNT)
462  {
463  using namespace Doxygen;
464  switch (dox_keyword)
465  {
466  case B:
467  {
468  dox_parser.ReplaceCurrentKeyword(arguments[i], b1);
469  wxString arg0;
470  dox_parser.GetArgument(arguments[i], RANGE_WORD, arg0);
471  arguments[i].insert(dox_parser.GetPosition() + 1, b0);
472  }
473  break;
474  default:
475  break;
476  }
477  dox_keyword = dox_parser.FindNextKeyword(arguments[i]);
478  }
479  }// for (i)
480 
481  wxString html;
482  html.reserve(doc.size());
483 
484  if (brief.size() > 0)
485  html += b1 + brief + b0 + br;
486 
487  if (params.size() > 0)
488  html += b1 + _T("Parameters:") + b0 + br + params;
489 
490  if (returns.size() > 0)
491  html += b1 + _T("Returns:") + b0 + br + tab + returns + br;
492 
493  if (plainText.size()>0)
494  {
495  plainText.Trim(false);
496  plainText.Trim(true);
497  html += b1 + _T("Description:") + b0 + br + tab;
498  plainText.Replace(_T("\n"), br + tab);
499  html += plainText + br;
500  }
501 
502  if (seeAlso.size() > 0)
503  {
504  html += b1 + _T("See also: ") + b0;
505  wxStringTokenizer tokenizer(seeAlso, _T(" \n\t,;"));
506  while ( tokenizer.HasMoreTokens() )
507  {
508  const wxString& tok = tokenizer.GetNextToken();
509  if (tok.size() > 0)
510  html += CommandToAnchor(cmdSearchAll, tok, &tok) + _T(" ");
511  }
512  }
513 
514  return html;
515 }
516 
518 {
519  static Token ancestorChecker(_T(""), 0, 0, 0); // Because IsValidAncestor isn't static
520  const wxString& argType = ExtractTypeAndName(fullType);
521  if (!ancestorChecker.IsValidAncestor(argType))
522  return fullType;
523 
524  size_t found = fullType.find(argType);
525  fullType.replace(found, argType.size(), CommandToAnchor(cmdSearch, argType, &argType) );
526  return fullType;
527 }
528 
530 {
531  if (args.size() == 0)
532  return args;
533 
534  //removes '(' and ')'
535  wxStringTokenizer tokenizer(args.SubString(1,args.find_last_of(_T(')'))-1), _T(","));
536  args.clear();
537  while ( tokenizer.HasMoreTokens() )
538  {
539  wxString tok = tokenizer.GetNextToken();
540  args += ConvertTypeToAnchor(tok);
541  if (tokenizer.HasMoreTokens())
542  args += _T(", ");
543  }
544  return _T('(') + args +_T(')');
545 }
546 
549 {
550  // remove default argument
551  size_t eqPos = tok.Find(_T('='));
552  if (eqPos != wxString::npos)
553  tok.resize(eqPos);
554 
555  tok.Replace(_T("*"), _T(" "),true); //remove all '*'
556  tok.Replace(_T("&"), _T(" "),true); //remove all '&'
557  if (tok.GetChar(0) != _T(' '))
558  tok.insert(0u, _T(" ")); //it will be easer to find " const " and " volatile "
559 
560  //remove cv:
561  tok.Replace(_T(" const "), _T(" "),true);
562  tok.Replace(_T(" volatile "), _T(" "),true);
563  tok.Trim(true);
564  //tok.Trim(false);
565 
566  wxString _outName;
567  if (!outName)
568  outName = &_outName;
569 
570  static const wxString whitespace = _T(" \n\t");
571  size_t found = tok.find_last_of(whitespace);
572  if (found != wxString::npos)
573  {
574  // Argument have name _or_ type, if space was found
575  *outName = tok.SubString(found+1,tok.size());
576  tok.resize(found); //remove name
577  tok.Trim(true);
578  }
579 
580  found = tok.find_last_of(whitespace);
581  if (found != wxString::npos)
582  {
583  // Argument have name _and_ type
584  tok = tok.SubString(found+1,tok.size());
585  //tok.resize(found);
586  tok.Trim(true);
587  }
588  else
589  {
590  // Argument have only type
591  // so outName already have argument type.
592  tok.swap(*outName);
593  outName->clear();
594  }
595 
596  tok.Trim(false);
597  return tok;
598 }
599 
601  const wxString* args)
602 {
603  if (args)
604  {
605  return _T("<a href=\"") + commandTag + wxString::Format(_T("%i"), (int)cmd) +
606  separatorTag + *args + _T("\">") + name + _T("</a>");
607  }
608 
609  return _T("<a href=\"") + commandTag + wxString::Format(_T("%i"), (int)cmd) +
610  _T("\">") + name + _T("</a>");
611 }
612 
614 {
615  const wxString& tmp = wxString::Format(_T("%i"),arg0);
616  return CommandToAnchor(cmd, name, &tmp);
617 }
618 
620 {
621  if (!href.StartsWith(commandTag, &args))
622  return cmdNone;
623 
624  size_t separator = args.rfind(separatorTag);
625  if (separator == wxString::npos)
626  separator = args.size() + 1;
627 
628  long int command;
629  bool gotCommand = args.SubString(0,separator-1).ToLong(&command);
630  if (!gotCommand)
631  return cmdNone;
632 
633  if (separator + 1 < args.size())
634  args = args.SubString(separator+1, args.size());
635  else
636  args.clear();
637 
638  return (Command)(command);
639 }
640 
641 const wxChar DocumentationHelper::separatorTag = _T('+');
642 const wxString DocumentationHelper::commandTag = _T("cmd=");
643 
645  m_CC(cc),
646  m_CurrentTokenIdx(-1),
647  m_LastTokenIdx(-1),
648  m_Enabled(true)
649 {
651  colours->RegisterColour(_("Code completion"), _("Documentation popup background"), wxT("cc_docs_back"), *wxWHITE);
652  colours->RegisterColour(_("Code completion"), _("Documentation popup text"), wxT("cc_docs_fore"), *wxBLACK);
653  colours->RegisterColour(_("Code completion"), _("Documentation popup link"), wxT("cc_docs_link"), *wxBLUE);
654 }
655 
657 {
658 }
659 
661 {
662  // Dont attach if user dont want to use documentation helper and its already attached
663  if (!m_Enabled /*|| IsAttached()*/)
664  return;
665  // TODO: Is this function still needed?
666 }
667 
669 {
670  // TODO: Is this function still needed?
671 }
672 
674 {
675  //http://docs.wxwidgets.org/2.8/wx_wxhtml.html#htmltagssupported
676 
677  using namespace HTMLTags;
678 
679  if (tokenIdx == -1)
680  return wxEmptyString;
682 
683  wxString html = _T("<html><body bgcolor=\"");
684  html += colours->GetColour(wxT("cc_docs_back")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\" text=\"");
685  html += colours->GetColour(wxT("cc_docs_fore")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\" link=\"");
686  html += colours->GetColour(wxT("cc_docs_link")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\">");
687 
688  html += _T("<a name=\"top\"></a>");
689 
691 
692  Token* token = tree->at(tokenIdx);
693  if (!token || token->m_Name.IsEmpty())
694  {
696 
697  return wxEmptyString;
698  }
699 
700  wxString doxyDoc = tree->GetDocumentation(tokenIdx);
701 
702  m_CurrentTokenIdx = token->m_Index;
703 
704  // add parent:
705  wxString tokenNs = token->GetNamespace();
706  if (tokenNs.size() > 0)
707  html += b1 + CommandToAnchorInt(cmdDisplayToken, tokenNs.RemoveLast(2), token->m_ParentIndex) + b0 + br;
708 
709  html += br;
710 
711  //add scope and name:
712  switch (token->m_TokenKind)
713  {
714  case tkFunction:
715  if (token->m_Scope != tsUndefined)
716  html += i1 + token->GetTokenScopeString() + i0 + sep;
717  html += ConvertTypeToAnchor(token->m_FullType) + sep + b1 + token->m_Name + b0;
718  html += ConvertArgsToAnchors(token->GetFormattedArgs());
719  if (token->m_IsConst)
720  html += _T(" const");
721  if (token->m_IsNoExcept)
722  html += _T(" noexcept");
723  html += br;
724  break;
725 
726  case tkMacroDef:
727  html += b1 + token->m_Name + b0 + br + token->m_FullType + br;
728  break;
729 
730  case tkVariable:
731  if (token->m_Scope != tsUndefined)
732  html += i1 + token->GetTokenScopeString() + i0 + sep;
733  html += ConvertTypeToAnchor(token->m_FullType) + sep + b1 + token->m_Name + b0 + br;
734  break;
735 
736  case tkEnumerator:
737  if (token->m_Scope != tsUndefined)
738  html += i1 + token->GetTokenScopeString() + i0 + sep;
739  html += token->m_FullType + sep + b1 + token->m_Name + b0;
740  if (!token->m_Args.IsEmpty())
741  html += wxT(" = ") + token->GetFormattedArgs();
742  html += br;
743  break;
744 
745  case tkConstructor: // fall-through
746  case tkDestructor:
747  if (token->m_Scope != tsUndefined)
748  html += i1 + token->GetTokenScopeString() + i0 + sep;
749  html += token->m_FullType + sep + b1 + token->m_Name + b0 + ConvertArgsToAnchors(token->GetFormattedArgs()) + br;
750  break;
751 
752  case tkNamespace: // fall-through
753  case tkClass: // fall-through
754  case tkEnum: // fall-through
755  case tkTypedef: // fall-through
756  case tkMacroUse: // fall-through
757  case tkAnyContainer: // fall-through
758  case tkAnyFunction: // fall-through
759  case tkUndefined: // fall-through
760  default:
761  if (token->m_Scope != tsUndefined)
762  html += i1 + token->GetTokenScopeString() + i0 + sep;
763  html += token->m_FullType + sep + b1 + token->m_Name + b0 + br;
764  }
765 
766  //add kind:
767  if (token->m_TokenKind != tkUndefined)
768  html += i1 + _T("<font color=\"green\" size=3>") + _T("(") +
769  token->GetTokenKindString() +_T(")") + _T("</font>") + i0 + br;
770 
771  html += DoxygenToHTML(doxyDoc);
772 
773  //add go to declaration / implementation
774  {
775  const wxString& arg0 = wxString::Format(_T("%i"), token->m_Index);
776 
777  html += br + br + CommandToAnchor(cmdOpenDecl, _T("Open declaration"), &arg0);
778  if ((token->m_TokenKind & tkAnyFunction) && token->m_ImplLine > 0)
779  html += br + CommandToAnchor(cmdOpenImpl, _T("Open implementation"), &arg0);
780  }
781 
782  //add details:
783  switch (token->m_TokenKind)
784  {
785  case tkClass:
786  html += br + b1 + _T("Members:") + b0;
787  for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
788  {
789  const Token* t2 = tree->at(*it);
790  if (t2 && !t2->m_Name.IsEmpty())
791  {
792  html += br + sep + CommandToAnchorInt(cmdDisplayToken, t2->m_Name, *it) +
793  t2->GetStrippedArgs() + _T(": ") + t2->m_FullType;
794  }
795  }
796  break;
797 
798  case tkEnum:
799  html += br + b1 + _T("Values:") + b0;
800  for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
801  {
802  const Token* t2 = tree->at(*it);
803  if (t2 && !t2->m_Name.IsEmpty())
804  html += br + sep + CommandToAnchorInt(cmdDisplayToken, t2->m_Name, *it);
805  }
806  break;
807 
808  case tkNamespace: // fall-through
809  case tkTypedef: // fall-through
810  case tkConstructor: // fall-through
811  case tkDestructor: // fall-through
812  case tkFunction: // fall-through
813  case tkVariable: // fall-through
814  case tkEnumerator: // fall-through
815  case tkMacroDef: // fall-through
816  case tkMacroUse: // fall-through
817  case tkAnyContainer: // fall-through
818  case tkAnyFunction: // fall-through
819  case tkUndefined: // fall-through
820  default:
821  break;
822  }
823 
825 
826  html += br + br;
827 
828  // Append 'back' link:
829  if (m_LastTokenIdx >= 0)
831 
832  // Append 'close' link:
833  html += _T(" ") + CommandToAnchor(cmdClose, _T("Close"));
834  html += _T(" <a href=\"#top\">Top</a> ");
835 
836  html += _T("</body></html>");
837 
838  return html;
839 }
840 
842 {
843  using namespace HTMLTags;
844 
845  if (tokensIdx.empty())
846  return wxEmptyString;
847 
848  if (tokensIdx.size() == 1)
849  return GenerateHTML(*tokensIdx.begin(),tree);
851  wxString html = _T("<html><body bgcolor=\"");
852  html += colours->GetColour(wxT("cc_docs_back")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\" text=\"");
853  html += colours->GetColour(wxT("cc_docs_fore")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\" link=\"");
854  html += colours->GetColour(wxT("cc_docs_link")).GetAsString(wxC2S_HTML_SYNTAX) + _T("\">");
855 
856  html += _T("<a name=\"top\"></a>");
857 
858  html += _T("Multiple matches, please select one:<br>");
859  TokenIdxSet::const_iterator it = tokensIdx.begin();
860 
862 
863  while (it != tokensIdx.end())
864  {
865  const Token* token = tree->at(*it);
866 
867  html += token->GetNamespace() + CommandToAnchorInt(cmdDisplayToken, token->m_Name, token->m_Index);
868  html += nbsp + nbsp + token->GetTokenKindString();
869  html += _T("<br>");
870 
871  ++it;
872  }
873 
875 
876  html += _T("<br>");
877 
878  //Append 'back' link:
879  if (m_LastTokenIdx >= 0)
881 
882 
883  //Append 'close' link:
884  html += _T(" ") + CommandToAnchor(cmdClose, _T("Close"));
885  html += _T(" <a href=\"#top\">Top</a> ");
886 
887  html += _T("</body></html>");
888 
889  return html;
890 }
891 
893 {
894  if (!cfg)
895  cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
896 
897  m_Enabled = cfg->ReadBool(_T("/use_documentation_helper"), true);
898 
899  // Apply changes
900  if (m_Enabled)
901  OnAttach();
902  else
903  OnRelease();
904 }
905 
907 {
908  if (!cfg)
909  cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
910 
911  cfg->Write(_T("/use_documentation_helper"), m_Enabled);
912 }
913 
915 {
917 }
918 
919 //events:
920 wxString DocumentationHelper::OnDocumentationLink(wxHtmlLinkEvent& event, bool& dismissPopup)
921 {
923 
924  const wxString& href = event.GetLinkInfo().GetHref();
925  wxString args;
926  long int tokenIdx;
927 
928  Command command = HrefToCommand(href,args);
929  switch (command)
930  {
931  case cmdDisplayToken:
932  if(args.ToLong(&tokenIdx))
933  {
934  SaveTokenIdx();
935  return GenerateHTML(tokenIdx, tree);
936  }
937  break;
938 
939  case cmdSearch:
940  case cmdSearchAll:
941  {
942  size_t opb = args.find_last_of(_T('('));
943  size_t clb = args.find_last_of(_T(')'));
944  int kindToSearch = tkUndefined;
945  if (opb != wxString::npos && clb != wxString::npos)
946  {
947  args = args.Truncate(opb);
948  kindToSearch = tkAnyFunction|tkMacroDef;
949  }
950 
951  TokenIdxSet result;
952  size_t scpOp = args.rfind(_T("::"));
953  if (scpOp != wxString::npos)
954  {
955  //it may be function
956  tree->FindMatches(args.SubString(scpOp+2,args.size()), result,
957  true, false, TokenKind(kindToSearch));
958  }
959  else if (command == cmdSearchAll)
960  tree->FindMatches(args, result, true, false, TokenKind(kindToSearch));
961  else
962  tree->FindMatches(args, result, true, false, TokenKind(tkAnyContainer|tkEnum));
963 
964  if (result.size() > 0)
965  {
966  SaveTokenIdx();
967  return GenerateHTML(result, tree);
968  }
969  }
970  break;
971 
972  case cmdOpenDecl:
973  if (args.ToLong(&tokenIdx))
974  {
976  const Token* token = tree->at(tokenIdx);
977  cbEditor* targetEditor = edMan->Open(token->GetFilename());
978  if (targetEditor)
979  {
980  targetEditor->GotoTokenPosition(token->m_Line - 1, token->m_Name);
981  dismissPopup = true;
982  }
983  }
984  break;
985 
986  case cmdOpenImpl:
987  if (args.ToLong(&tokenIdx))
988  {
990  const Token* token = tree->at(tokenIdx);
991  cbEditor* targetEditor = edMan->Open(token->GetImplFilename());
992  if (targetEditor)
993  {
994  targetEditor->GotoTokenPosition(token->m_ImplLine - 1, token->m_Name);
995  dismissPopup = true;
996  }
997  }
998  break;
999 
1000  case cmdClose:
1001  dismissPopup = true;
1002  break;
1003 
1004  case cmdNone:
1005  default:
1006  if (href.size()>1 && href[0] == _T('#'))
1007  event.Skip(); // go to anchor
1008  else if (href.StartsWith(_T("www.")) || href.StartsWith(_T("http://")))
1009  wxLaunchDefaultBrowser(href);
1010  }
1011  // don't skip this event
1012  return wxEmptyString;
1013 }
1014 
1015 //end of Documentation popup functions
void ReplaceInDoc(wxString &doc, size_t start, size_t count, const wxString &str)
destructor class member function
Definition: token.h:51
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
variable
Definition: token.h:57
namespace
Definition: token.h:34
int m_ParentIndex
Parent Token index.
Definition: token.h:265
wxColour * wxBLACK
constructor class member function
Definition: token.h:48
class or struct
Definition: token.h:37
static Command HrefToCommand(const wxString &href, wxString &args)
wxString GenerateHTML(int tokenIdx, TokenTree *tree)
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
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
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
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
size_t rfind(const wxString &str, size_t nStart=npos) const
static wxString ExtractTypeAndName(wxString type, wxString *outName=0)
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
void resize(size_t nSize, wxUniChar ch='\0')
int GetEndLine(const wxString &doc) const
bool IsValidAncestor(const wxString &ancestor)
build in types are not valid ancestors for a type define token
Definition: token.cpp:133
typedef, note typedefs are stored as classes inheriting from the typedef&#39;d type, this takes advantage...
Definition: token.h:45
static wxString CommandToAnchor(Command cmd, const wxString &name, const wxString *args=0)
wxString & replace(size_t nStart, size_t nLen, const wxString &str)
void RegisterColour(const wxString &category, const wxString &name, const wxString &id, const wxColour &defaultColour)
container like tokens, those tokens can have children tokens
Definition: token.h:70
static const wxString br
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
bool ReadBool(const wxString &name, bool defaultVal=false)
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
int GetLineArgument(const wxString &doc, wxString &output)
#define _T(string)
unsigned int m_Line
Line index where the token was met, which is 1 based.
Definition: token.h:210
wxString GetNextToken()
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
bool IsKeywordBegin(const wxString &doc) const
wxString GetNamespace() const
get a literal string presentation of the namespace.
Definition: token.cpp:253
bool m_IsNoExcept
the member method is noexcept (yes/no)
Definition: token.h:251
static const wxString NewLineReplacment
static const wxString b0
#define wxT(string)
static const int KwCount
TokenScope m_Scope
public? private? protected?
Definition: token.h:231
static const wxString Keywords[]
void GetWordArgument(const wxString &doc, wxString &output)
size_t find(const wxString &str, size_t nStart=0) const
Code completion plugin has those features: show tool-tip when the mouse hover over the variables/func...
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
wxUSE_UNICODE_dependent wxChar
wxString GetStrippedArgs() const
remove all default value of the function argument string, e.g.
Definition: token.cpp:206
static const wxString pre0
CodeCompletion * m_CC
Pointer to CodeComplete object.
void Write(const wxString &name, const wxString &value, bool ignoreEmpty=false)
void RereadOptions(ConfigManager *cfg)
bool IsEnd(const wxString &doc) 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
wxString & RemoveLast(size_t n=1)
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
wxColour GetColour(const wxString &id) const
#define arg0
Definition: sqvm.cpp:456
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
DocumentationHelper(CodeCompletion *cc)
void swap(wxString &str)
static const wxString sep
wxString & Truncate(size_t len)
bool m_IsConst
the member method is const (yes/no)
Definition: token.h:248
void clear()
#define CC_LOCKER_TRACK_TT_MTX_UNLOCK(M)
Definition: cclogger.h:165
wxColour * wxWHITE
wxString wxEmptyString
size_t find_last_of(const wxString &str, size_t nStart=npos) const
cbEditor * Open(const wxString &filename, int pos=0, ProjectFile *data=nullptr)
const wxString & _(const wxString &string)
wxString & Trim(bool fromRight=true)
wxString m_Args
If it is a function Token, then this value is function arguments, e.g.
Definition: token.h:194
wxString GetTokenScopeString() const
the access kind string, e.g.
Definition: token.cpp:333
bool IsOneOf(wxChar c, const wxChar *chars) const
#define CC_LOCKER_TRACK_TT_MTX_LOCK(M)
Definition: cclogger.h:159
ParserBase & GetParser()
return a reference to the currently active Parser object
Definition: nativeparser.h:65
bool ToLong(long *val, int base=10) const
bool HasMoreTokens() const
undefined or just "all"
Definition: token.h:76
ColourManager * GetColourManager() const
Definition: manager.cpp:489
static const wxString tab
enum
Definition: token.h:40
A file editor.
Definition: cbeditor.h:43
bool IsEmpty() const
size_type size() const
int FindNextKeyword(const wxString &doc)
wxColour * wxBLUE
enumerator
Definition: token.h:60
static const size_t npos
any kind of functions
Definition: token.h:73
int m_CurrentTokenIdx
Documentation of which token was previously displayed.
wxString GetDocumentation(int tokenIdx)
get the document string associated with the token
Definition: tokentree.cpp:960
void GetBlockArgument(const wxString &doc, wxString &output)
void ReplaceCurrentKeyword(wxString &doc, const wxString &str)
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
wxString & insert(size_t nPos, const wxString &str)
static wxString DoxygenToHTML(const wxString &doc)
static wxString ConvertArgsToAnchors(wxString args)
general function, not constructor nor destructor
Definition: token.h:54
static const wxString pre1
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
bool HandleNewLine(const wxString &doc, wxString &output, const wxString &replaceWith=NewLineReplacment)
size_t FindMatches(const wxString &query, TokenIdxSet &result, bool caseSensitive, bool is_prefix, TokenKind kindMask=tkUndefined)
find a collection of matched tokens
Definition: tokentree.cpp:266
static wxString ConvertTypeToAnchor(wxString fullType)
int Find(wxUniChar ch, bool fromEnd=false) const
virtual TokenTree * GetTokenTree() const
wxUniChar GetChar(size_t n) const
void reserve(size_t sz)
bool wxLaunchDefaultBrowser(const wxString &url, int flags=0)
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
wxString SubString(size_t from, size_t to) const
virtual wxString GetAsString(long flags=wxC2S_NAME|wxC2S_CSS_SYNTAX) const
void WriteOptions(ConfigManager *cfg)
wxString m_FullType
this is the full return value (if any): e.g.
Definition: token.h:182
int CheckKeyword(const wxString &doc)
int GetArgument(const wxString &doc, int range, wxString &output)
wxString GetTokenKindString() const
the token kind string, e.g.
Definition: token.cpp:311
bool SkipDecorations(const wxString &doc)
int GetParagraphArgument(const wxString &doc, wxString &output)
static wxString CommandToAnchorInt(Command cmd, const wxString &name, int arg0)
static wxString Format(const wxString &format,...)
TokenKind
Definition: token.h:29
static const wxString nbsp(_T("&nbsp;"))
the usage of the macro, for example: AAA(1,2)
Definition: token.h:66
NativeParser m_NativeParser
this member will actually manage all the Parser instances