Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_DoxygenFillerPlugin.c
Go to the documentation of this file.
1#ifdef WORKBENCH
3 name: "Doxygen Filler",
4 description: "Create/Format Doxygen documentation skeleton for configured methods (default public methods only)",
5 shortcut: "Ctrl+Alt+Shift+D",
6 wbModules: { "ScriptEditor" },
7 awesomeFontCode: 0xF518)]
8// TODO: multiline method declarations
9// TODO: addon-wide file process
10class SCR_DoxygenFillerPlugin : WorkbenchPlugin
11{
12 /*
13 Doxygen
14 */
15
16 [Attribute("1", category: "Doxygen", desc: "Add Doxygen skeleton to public methods (neither protected nor private)")]
17 protected bool m_bDoxygenPublicMethods;
18
19 [Attribute("0", category: "Doxygen", desc: "Add Doxygen skeleton to protected methods")]
20 protected bool m_bDoxygenProtectedMethods;
21
22 [Attribute("0", category: "Doxygen", desc: "Add Doxygen skeleton to private methods")]
23 protected bool m_bDoxygenPrivateMethods;
24
25 [Attribute("0", category: "Doxygen", desc: "Add Doxygen skeleton to overridden methods")]
26 protected bool m_bDoxygenOverriddenMethods;
27
28 [Attribute("1", category: "Doxygen", desc: "Add Doxygen skeleton to static methods")]
29 protected bool m_bDoxygenStaticMethods;
30
31 [Attribute("0", category: "Doxygen", desc: "Add Doxygen skeleton to Obsolete methods")]
32 protected bool m_bDoxygenObsoleteMethods;
33
34 [Attribute("MethodPrefix", category: "Doxygen", desc: "Only document params and return value (without description) for methods starting with these prefixes (e.g Set*, Get*, On*, Is* etc, case-sensitive)")]
35 protected ref array<string> m_aPartialDoxygenPrefixes;
36
37 /*
38 Other
39 */
40
41 [Attribute("1", category: "Other", desc: "Replace Doxygen blocks with multiple one line comments (" + DOXYGEN_LINE_START + ")")]
42 protected bool m_bConvertDoxygenFormatting;
43
44 [Attribute("1", category: "Other", desc: "Add missing separators to undocumented methods")]
45 protected bool m_bAddMissingSeparators;
46
47 [Attribute("1", category: "Other", desc: "Add \"" + CONSTRUCTOR_COMMENT + "\" comment to constructor")]
48 protected bool m_bAddConstructorNormalComment;
49
50 [Attribute("1", category: "Other", desc: "Add \"" + DESTRUCTOR_COMMENT + "\" comment to destructor")]
51 protected bool m_bAddDestructorNormalComment;
52
53 /*
54 Debug
55 */
56
57 [Attribute(defvalue: "0", category: "Debug", desc: "Output method parsing errors in the log console")]
58 protected bool m_bOutputMethodParsingErrors;
59
60 protected static const string METHOD_SEPARATOR = SCR_StringHelper.DOUBLE_SLASH + "------------------------------------------------------------------------------------------------";
61 protected static const string DOXYGEN_LINE_START = SCR_StringHelper.DOUBLE_SLASH + "!"; // the space is optional... unfortunately
62 protected static const string GENERATED_SCRIPT_WARNING = "Do not modify, this script is generated"; // must be the exact line, tabs included if any
63 protected static const string CONSTRUCTOR_COMMENT = SCR_StringHelper.DOUBLE_SLASH + " constructor";
64 protected static const string DESTRUCTOR_COMMENT = SCR_StringHelper.DOUBLE_SLASH + " destructor";
65 protected static const string COMMENT_BLOCK_START = "/" + "*";
66 protected static const string COMMENT_BLOCK_END = "*" + "/";
67 protected static const ref array<string> DOXYGEN_BLOCK_STARTS = { COMMENT_BLOCK_START + "*", COMMENT_BLOCK_START + "!" };
68 protected static const string BASE_PARAM = "\\param";
69 protected static const string FAULTY_PARAM = "\\param ";
70
71 //------------------------------------------------------------------------------------------------
72 protected override void Run()
73 {
74 ProcessCurrentFile();
75 }
76
77 //------------------------------------------------------------------------------------------------
78 protected bool ProcessAddon()
79 {
80 // TODO
81 }
82
83 //------------------------------------------------------------------------------------------------
84 protected void Init()
85 {
86 if (m_aPartialDoxygenPrefixes.IsEmpty())
87 m_aPartialDoxygenPrefixes = { "Get", "Set", "On", "Is" };
88
89 SCR_ArrayHelperT<string>.RemoveDuplicates(m_aPartialDoxygenPrefixes);
90 }
91
92 //------------------------------------------------------------------------------------------------
95 protected bool ProcessCurrentFile()
96 {
97 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
98 if (!scriptEditor)
99 return false;
100
101 string filePath;
102 if (!scriptEditor.GetCurrentFile(filePath))
103 {
104 Print("Could not get current file", LogLevel.ERROR);
105 return false;
106 }
107
108 if (filePath == __FILE__)
109 {
110 Print("Cannot add Doxygen documentation to the Doxygen Filler plugin itself - " + filePath, LogLevel.NORMAL);
111 return false;
112 }
113
114 string absoluteFilePath;
115 if (!Workbench.GetAbsolutePath(filePath, absoluteFilePath, true))
116 {
117 Print("Could not get absolute file path - " + filePath, LogLevel.WARNING);
118 return false;
119 }
120
121 Print("Processing " + absoluteFilePath, LogLevel.NORMAL);
122
123 bool result = ProcessFile(absoluteFilePath);
124 if (result)
125 Print("Successfully processed " + absoluteFilePath, LogLevel.NORMAL);
126
127 return result;
128 }
129
130 //------------------------------------------------------------------------------------------------
134 protected bool ProcessFile(string filePath)
135 {
136 array<string> lines = SCR_FileIOHelper.ReadFileContent(filePath);
137 if (lines.Contains(GENERATED_SCRIPT_WARNING))
138 {
139 Print("This file is generated - skipping - " + filePath, LogLevel.WARNING);
140 return false;
141 }
142
143 array<ref Tuple2<int, string>> commentsToAdd = {};
144 array<ref Tuple2<int, string>> commentsToReplace = {}; // Doxygen blocks to Doxygen lines
145
146 int resetValues = 0; // 0 = don't reset, 1 = don't reset line offset, 2 = don't reset separator, 3 = reset everything
147 bool hasSeparator;
148 string currentDoxygenComment;
149 bool isInDoxygenCommentBlock;
150 bool isInCommentBlock;
151 string trimmedLine;
152 int commentBlockIndex;
153 string currentClassName;
154 int lineOffset;
155 bool isObsolete;
156 foreach (int lineId, string line : lines)
157 {
158 if (resetValues > 0)
159 {
160 if (resetValues != 2)
161 hasSeparator = false;
162
163 currentDoxygenComment = string.Empty;
164 if (resetValues != 1)
165 lineOffset = 0;
166
167 resetValues = 0;
168 }
169
170 commentBlockIndex = 0;
171 while (true) // meh
172 {
173 if (!isInCommentBlock)
174 {
175 commentBlockIndex = line.IndexOfFrom(commentBlockIndex, COMMENT_BLOCK_START);
176 if (commentBlockIndex < 0)
177 break;
178
179 isInCommentBlock = true;
180 isInDoxygenCommentBlock = SCR_StringHelper.IndexOfFrom(line, commentBlockIndex, DOXYGEN_BLOCK_STARTS) == commentBlockIndex;
181 }
182
183 commentBlockIndex = line.IndexOfFrom(commentBlockIndex, COMMENT_BLOCK_END);
184 if (commentBlockIndex < 0)
185 break;
186
187 isInCommentBlock = false;
188 isInDoxygenCommentBlock = false;
189 }
190
191 trimmedLine = line.Trim(); // 8191 chars limit
192
193 if (isInCommentBlock)
194 {
195 if (isInDoxygenCommentBlock)
196 {
197 if (currentDoxygenComment) // already has comment
198 currentDoxygenComment += "\n" + trimmedLine;
199 else
200 currentDoxygenComment += trimmedLine;
201 }
202 else
203 {
204 resetValues = 1;
205 }
206
207 continue;
208 }
209 else // related to comment blocks
210 {
211 if (currentDoxygenComment && trimmedLine.Contains(COMMENT_BLOCK_END))
212 {
213 if (trimmedLine == COMMENT_BLOCK_END)
214 currentDoxygenComment += "\n" + trimmedLine;
215 else
216 if (trimmedLine.StartsWith(COMMENT_BLOCK_END))
217 currentDoxygenComment += "\n" + COMMENT_BLOCK_END;
218 else
219 currentDoxygenComment += "\n" + trimmedLine.Substring(0, trimmedLine.IndexOfFrom(1, COMMENT_BLOCK_END) - 1);
220
221 continue;
222 }
223 }
224
225 // not in comment block? go ahead
226
227 if (!trimmedLine)
228 {
229 resetValues = 3;
230 continue;
231 }
232
233 if (trimmedLine.StartsWith(SCR_StringHelper.DOUBLE_SLASH))
234 {
235 if (trimmedLine == METHOD_SEPARATOR)
236 {
237 hasSeparator = true;
238 resetValues = 2;
239 continue;
240 }
241 else if (trimmedLine == CONSTRUCTOR_COMMENT || trimmedLine == DESTRUCTOR_COMMENT || trimmedLine.StartsWith(DOXYGEN_LINE_START))
242 {
243 if (currentDoxygenComment)
244 currentDoxygenComment += "\n" + trimmedLine;
245 else
246 currentDoxygenComment = trimmedLine;
247
248 continue;
249 }
250 else
251 {
252 // allow normal comments between Doxygen doc and method line
253 lineOffset--;
254 continue;
255 }
256 }
257
258 if (!m_bDoxygenObsoleteMethods && trimmedLine.StartsWith("[Obsolete(")) // )
259 {
260 isObsolete = true;
261 continue;
262 }
263
264 if (trimmedLine.StartsWith("[")) // [Attribute()]
265 {
266 lineOffset--;
267 continue;
268 }
269
270 if (trimmedLine.StartsWith("class "))
271 {
272 string classname = GetClassname(trimmedLine);
273 if (classname)
274 {
275 currentClassName = classname;
276 resetValues = 3;
277 continue;
278 }
279 }
280 else
281 if (trimmedLine.StartsWith("enum "))
282 {
283 resetValues = 3;
284 continue;
285 }
286
287 if (!currentClassName) // not in class? keep seeking
288 continue;
289
290 SCR_DoxygenFillerPlugin_Method method = GetMethodObject(line, lineId);
291 if (!method)
292 {
293 resetValues = 3;
294 continue;
295 }
296
297 if (isObsolete)
298 {
299 isObsolete = false;
300 resetValues = 3;
301 continue;
302 }
303
304 if (m_bConvertDoxygenFormatting && SCR_StringHelper.StartsWithAny(currentDoxygenComment, DOXYGEN_BLOCK_STARTS))
305 {
306 currentDoxygenComment = ConvertDoxygenBlockToSingleLines(currentDoxygenComment, method);
307 if (currentDoxygenComment)
308 {
309 currentDoxygenComment = AddIndent(currentDoxygenComment);
310 array<string> doxyBlockLines = {};
311 currentDoxygenComment.Split("\n", doxyBlockLines, false);
312 int doxyBlockLinesCount = doxyBlockLines.Count();
313 if (doxyBlockLinesCount > 0)
314 {
315 if (!hasSeparator && doxyBlockLines[0].Trim() == DOXYGEN_LINE_START)
316 currentDoxygenComment = SCR_StringHelper.ReplaceTimes(currentDoxygenComment, DOXYGEN_LINE_START + "\n", METHOD_SEPARATOR + "\n", 1);
317
318 commentsToReplace.Insert(new Tuple2<int, string>(lineId - doxyBlockLines.Count(), currentDoxygenComment));
319 }
320 }
321 }
322
323 if (!currentDoxygenComment)
324 {
325 int addedLines;
326 string doxygenDocumentation = GetDoxygenDocumentation(method, !hasSeparator && m_bAddMissingSeparators, currentClassName);
327 if (doxygenDocumentation)
328 {
329 doxygenDocumentation = AddIndent(doxygenDocumentation);
330 addedLines = SCR_StringHelper.CountOccurrences(doxygenDocumentation, "\n") + 1;
331
332 Print("+Doxygen " + method.m_sName + "() method (previously on L" + (lineId + 1) + ")", LogLevel.NORMAL);
333 commentsToAdd.Insert(new Tuple2<int, string>(lineId + lineOffset, doxygenDocumentation));
334 }
335 }
336
337 resetValues = 3;
338 }
339
340 int addCount = commentsToAdd.Count();
341 int replaceCount = commentsToReplace.Count();
342 if (addCount < 1 && (!m_bConvertDoxygenFormatting || replaceCount < 1))
343 {
344 if (m_bConvertDoxygenFormatting)
345 Print("No documentable methods nor convertible comments were found", LogLevel.NORMAL);
346 else
347 Print("No documentable methods were found", LogLevel.NORMAL);
348
349 return false;
350 }
351
352 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
353 bool useScriptEditor = scriptEditor != null; // staying in script editor for now
354
355 // replace first, -then- change lines
356 // otherwise line number is skewed
357
358 if (useScriptEditor)
359 {
360 if (!scriptEditor.SetOpenedResource(filePath))
361 {
362 Print("Cannot open resource in Script Editor - " + filePath, LogLevel.WARNING);
363 return false;
364 }
365
366 if (replaceCount > 0)
367 {
368 Print("Converting " + replaceCount + " comments...", LogLevel.NORMAL);
369
370 array<string> commentLines = {};
371 foreach (Tuple2<int, string> commentToReplace : commentsToReplace)
372 {
373 commentToReplace.param2.Split("\n", commentLines, false);
374 foreach (int i, string line : commentLines)
375 {
376 if (scriptEditor.SetOpenedResource(filePath))
377 scriptEditor.SetLineText(commentLines[i], commentToReplace.param1 + i);
378 }
379 }
380 }
381
382 if (addCount > 0)
383 {
384 Print("Documenting " + addCount + " methods...", LogLevel.NORMAL);
385
386 Tuple2<int, string> commentInfo;
387 for (int i = commentsToAdd.Count() - 1; i > -1; --i)
388 {
389 commentInfo = commentsToAdd[i];
390 if (commentInfo.param1 > 0)
391 {
392 string trimmedPreviousLine = lines[commentInfo.param1 - 1].Trim();
393 if (trimmedPreviousLine && trimmedPreviousLine != "{" && !trimmedPreviousLine.StartsWith(SCR_StringHelper.DOUBLE_SLASH)) // }
394 commentInfo.param2 = "\n" + commentInfo.param2;
395 }
396
397 if (scriptEditor.SetOpenedResource(filePath)) // forces the edited file to be focused
398 scriptEditor.InsertLine(commentInfo.param2, commentInfo.param1);
399 }
400 }
401 }
402 else // using FileIO (SCR_FileIOHelper)
403 {
404 if (replaceCount > 0)
405 {
406 // TODO: replacement
407 }
408
409 if (addCount > 0)
410 {
411 Tuple2<int, string> commentInfo;
412 for (int i = commentsToAdd.Count() - 1; i > -1; --i)
413 {
414 commentInfo = commentsToAdd[i];
415 if (commentInfo.param1 > 0)
416 {
417 string previousLine = lines[commentInfo.param1 - 1].Trim();
418 if (previousLine != METHOD_SEPARATOR && !SCR_StringHelper.IsEmptyOrWhiteSpace(previousLine))
419 commentInfo.param2 = "\n" + commentInfo.param2;
420 }
421
422 lines.InsertAt(commentInfo.param2, commentInfo.param1);
423 }
424 }
425
426 if (lines[lines.Count() - 1] != string.Empty)
427 lines.Insert(string.Empty);
428
429 SCR_FileIOHelper.WriteFileContent(filePath, lines);
430 }
431
432 return true;
433 }
434
435 //------------------------------------------------------------------------------------------------
440 protected string GetClassname(string classLine)
441 {
442 if (!classLine)
443 return string.Empty;
444
445 classLine.Replace("\t", " ");
446 if (!classLine.StartsWith("class "))
447 return string.Empty;
448
449 array<string> parts = {};
450 classLine.Split(" ", parts, true);
451
452 if (parts[0] != "class")
453 return string.Empty;
454
455 string classname = parts[1];
456 if (classname.EndsWith(":"))
457 classname = classname.Substring(0, classname.Length() - 1).Trim();
458
459 return classname;
460 }
461
462 //------------------------------------------------------------------------------------------------
467 protected SCR_DoxygenFillerPlugin_Method GetMethodObject(string line, int lineNumber)
468 {
469 if (!line)
470 return null;
471
472 if (line.StartsWith("\treturn"))
473 return null;
474
475 if (line.Contains(" = new ")) // safety against ref ScriptInvoker m_Invoker = new ScriptInvoker();
476 return null;
477
478 line.Replace("\n", string.Empty); // in case multiple lines are provided - beware of comments for now
479
480 int index = line.IndexOf(SCR_StringHelper.DOUBLE_SLASH);
481 if (index == 0)
482 return null;
483
484 if (index > -1)
485 line = line.Substring(0, index);
486
487 bool isMethod = line.StartsWith("\t") && // by method indentation level
488 !line.StartsWith("\t\t") && // meh, but still
489 line.Contains("(") &&
490 line.Contains(")");
491
492 if (!isMethod)
493 return null;
494
495 string trimmedLine = line.Trim();
496 if (trimmedLine.StartsWith(SCR_StringHelper.DOUBLE_SLASH))
497 return null;
498
499 trimmedLine.Replace(SCR_StringHelper.TAB, SCR_StringHelper.SPACE);
500 trimmedLine.Replace(", ", ",");
501 trimmedLine = SCR_StringHelper.ReplaceRecursive(trimmedLine, " ", " ");
502
503 index = trimmedLine.IndexOf("("); // ) // has to be > -1
504 array<string> rawSignatureAndParameters = {
505 trimmedLine.Substring(0, index),
506 trimmedLine.Substring(index + 1, trimmedLine.Length() - index - 1),
507 };
508
509 array<string> protectionReturnValueAndName = {};
510 rawSignatureAndParameters[0].Split(" ", protectionReturnValueAndName, true);
511
512 string tempString;
513 for (int i = protectionReturnValueAndName.Count() - 2; i >= 0; --i) // e.g array<ref SomeClass>
514 {
515 tempString = protectionReturnValueAndName[i];
516 if (tempString.EndsWith("ref"))
517 {
518 protectionReturnValueAndName[i] = tempString + " " + protectionReturnValueAndName[i + 1];
519 protectionReturnValueAndName.RemoveOrdered(i + 1);
520 }
521 }
522
523 bool isProtected = protectionReturnValueAndName.RemoveItemOrdered("protected");
524 if (!m_bDoxygenProtectedMethods && isProtected)
525 return null;
526
527 bool isPrivate = !isProtected && protectionReturnValueAndName.RemoveItemOrdered("private");
528 if (!m_bDoxygenPrivateMethods && isPrivate)
529 return null;
530
531 bool isPublic = !isProtected && !isPrivate;
532 if (!m_bDoxygenPublicMethods && isPublic)
533 return null;
534
535 bool isOverride = protectionReturnValueAndName.RemoveItemOrdered("override");
536 if (!m_bDoxygenOverriddenMethods && isOverride)
537 return null;
538
539 bool isStatic = protectionReturnValueAndName.RemoveItemOrdered("static");
540 if (!m_bDoxygenStaticMethods && isStatic)
541 return null;
542
543 bool isSealed = protectionReturnValueAndName.RemoveItemOrdered("sealed");
544 bool isEvent = protectionReturnValueAndName.RemoveItemOrdered("event");
545
546 if (protectionReturnValueAndName.Count() != 2)
547 {
548 if (m_bOutputMethodParsingErrors)
549 Print("Too many remaining method keywords line " + (lineNumber + 1) + ": " + SCR_StringHelper.Join(" | ", protectionReturnValueAndName), LogLevel.WARNING);
550
551 return null;
552 }
553
554 SCR_DoxygenFillerPlugin_Method method = new SCR_DoxygenFillerPlugin_Method();
555 method.m_sReturnType = protectionReturnValueAndName[0];
556 method.m_sName = protectionReturnValueAndName[1];
557 method.m_bOverride = isOverride;
558 method.m_bIsStatic = isStatic;
559 method.m_bIsSealed = isSealed;
560 method.m_bIsEvent = isEvent;
561
562 if (isProtected)
563 method.m_iProtection = 1;
564 else
565 method.m_iProtection = 2;
566
567 // parameters
568
569 tempString = rawSignatureAndParameters[1]; // variable reuse
570 if (tempString.StartsWith(")")) // no parameters, return now
571 return method;
572
573 tempString = tempString.Substring(0, tempString.LastIndexOf(")"));
574
575 array<ref array<string>> paramStrings = GetParamsModifierTypeAndNameFromSig(tempString);
576
577 SCR_DoxygenFillerPlugin_MethodParameter parameter;
578 foreach (array<string> modifiersTypeAndParamName : paramStrings)
579 {
580 parameter = new SCR_DoxygenFillerPlugin_MethodParameter();
581
582 if (modifiersTypeAndParamName.RemoveItemOrdered("out"))
583 parameter.m_iInOut = 1;
584 else if (modifiersTypeAndParamName.RemoveItemOrdered("inout"))
585 parameter.m_iInOut = 2;
586
587 if (modifiersTypeAndParamName.RemoveItemOrdered("notnull"))
588 parameter.m_bNotNull = true;
589
590 int count = modifiersTypeAndParamName.Count();
591 if (count != 2 && count != 4)
592 {
593 if (m_bOutputMethodParsingErrors)
594 Print("Cannot process parameter: " + SCR_StringHelper.Join(" | ", modifiersTypeAndParamName), LogLevel.WARNING);
595
596 continue;
597 }
598
599 parameter.m_sType = modifiersTypeAndParamName[0];
600 parameter.m_sName = modifiersTypeAndParamName[1];
601
602 if (count != 2)
603 {
604 if (modifiersTypeAndParamName[2] == "=") // "=" "defValue"
605 parameter.m_sDefaultValue = modifiersTypeAndParamName[3];
606 else
607 if (m_bOutputMethodParsingErrors)
608 Print("Cannot process parameter: " + SCR_StringHelper.Join(" | ", modifiersTypeAndParamName), LogLevel.WARNING);
609 }
610
611 method.m_aParameters.Insert(parameter);
612 }
613
614 return method;
615 }
616
617 //------------------------------------------------------------------------------------------------
621 protected array<ref array<string>> GetParamsModifierTypeAndNameFromSig(string paramsString)
622 {
623 // remove comma-space
624 paramsString.Replace(", ", ",");
625
626 bool inBrackets;
627 int chevronLevel;
628 string currC;
629 string buffer;
630
631 array<ref array<string>> result = {};
632 array<string> subResult = {};
633 for (int i, count = paramsString.Length(); i < count; i++)
634 {
635 currC = paramsString[i];
636
637 if (inBrackets)
638 {
639 if (currC == "]")
640 inBrackets = false;
641
642 continue;
643 }
644
645 if (currC == "[")
646 {
647 inBrackets = true;
648 continue;
649 }
650
651 if (chevronLevel == 0)
652 {
653 if (currC == ",")
654 {
655 if (buffer)
656 {
657 subResult.Insert(buffer); // dropping currC
658 buffer = string.Empty;
659 }
660
661 result.Insert(subResult);
662 subResult = {};
663 continue;
664 }
665
666 if (currC == " ")
667 {
668 if (buffer)
669 {
670 subResult.Insert(buffer); // dropping currC
671 buffer = string.Empty;
672 }
673
674 continue;
675 }
676 }
677
678 if (currC == "<")
679 chevronLevel++;
680 else if (currC == ">")
681 chevronLevel--;
682
683 buffer += currC;
684 }
685
686 if (buffer)
687 subResult.Insert(buffer);
688
689 if (!subResult.IsEmpty())
690 result.Insert(subResult);
691
692 // re-add comma-space
693 foreach (array<string> subArray : result)
694 {
695 foreach (int i, string value : subArray)
696 {
697 value.Replace(",", ", ");
698 subArray[i] = value;
699 }
700 }
701
702 return result;
703 }
704
705 //------------------------------------------------------------------------------------------------
706 protected string GetDoxygenDocumentation(notnull SCR_DoxygenFillerPlugin_Method method, bool addSeparator = false, string classname = string.Empty)
707 {
708 string generatedDoxygenDocumentation;
709
710 bool isConstrOrDestr;
711 if (classname && method.m_sReturnType == "void")
712 {
713 if (m_bAddDestructorNormalComment && method.m_sName == "~" + classname)
714 {
715 generatedDoxygenDocumentation = DESTRUCTOR_COMMENT;
716 isConstrOrDestr = true;
717 }
718 else
719 if (m_bAddConstructorNormalComment && method.m_sName == classname)
720 {
721 generatedDoxygenDocumentation = CONSTRUCTOR_COMMENT;
722 isConstrOrDestr = true;
723 }
724 }
725
726 if (!isConstrOrDestr)
727 {
728 if (!SCR_StringHelper.StartsWithAny(method.m_sName, m_aPartialDoxygenPrefixes))
729 generatedDoxygenDocumentation += DOXYGEN_LINE_START;
730 }
731
732 foreach (SCR_DoxygenFillerPlugin_MethodParameter parameter : method.m_aParameters)
733 {
734 if (generatedDoxygenDocumentation)
735 generatedDoxygenDocumentation += "\n";
736
737 generatedDoxygenDocumentation += DOXYGEN_LINE_START + " \\param";
738 switch (parameter.m_iInOut)
739 {
740 case 0: generatedDoxygenDocumentation += "[in]"; break; // meh - but \param alone is for old/unclear params
741 case 1: generatedDoxygenDocumentation += "[out]"; break;
742 case 2: generatedDoxygenDocumentation += "[in,out]"; break;
743 }
744
745 generatedDoxygenDocumentation += " " + parameter.m_sName;
746 }
747
748 if (method.m_sReturnType != "void")
749 {
750 if (generatedDoxygenDocumentation)
751 generatedDoxygenDocumentation += "\n";
752
753 generatedDoxygenDocumentation += DOXYGEN_LINE_START + " \\return";
754 }
755
756 if (addSeparator)
757 {
758 if (generatedDoxygenDocumentation)
759 generatedDoxygenDocumentation = METHOD_SEPARATOR + "\n" + generatedDoxygenDocumentation;
760 else
761 generatedDoxygenDocumentation = METHOD_SEPARATOR;
762 }
763
764 return generatedDoxygenDocumentation;
765 }
766
767 //------------------------------------------------------------------------------------------------
773 protected string ConvertDoxygenBlockToSingleLines(string doxygenBlock, inout SCR_DoxygenFillerPlugin_Method method)
774 {
775 doxygenBlock.TrimInPlace();
776
777 if (!doxygenBlock)
778 return string.Empty;
779
780// doxygenBlock.Replace("\\param ", "\\param[in] ");
781
782 int length = doxygenBlock.Length();
783 if (length < 5)
784 return string.Empty;
785 else if (length == 5) // / * * * /
786 return DOXYGEN_LINE_START;
787
788 if (!SCR_StringHelper.StartsWithAny(doxygenBlock, DOXYGEN_BLOCK_STARTS))
789 return string.Empty;
790
791 array<string> lines = SCR_StringHelper.GetLines(doxygenBlock, false, true);
792
793 int count = lines.Count();
794 if (count == 0)
795 return string.Empty; // huh?
796 else
797 if (count == 1)
798 return lines[0].Substring(3, lines[0].Length() - 5);
799
800 string line = lines[0];
801 length = line.Length();
802 if (length == 3)
803 lines[0] = string.Empty; // keep the line count
804 else
805 lines[0] = line.Substring(3, length - 3);
806
807 line = lines[count - 1]; // last line
808 length = line.Length();
809 if (length == 2)
810 lines[count - 1] = string.Empty; // keep the line count
811 else
812 lines[count - 1] = line.Substring(0, length - 2).Trim();
813
814 foreach (int i, string line2 : lines)
815 {
816 if (line2)
817 {
818 if (method)
819 {
820 SCR_DoxygenFillerPlugin_MethodParameter param;
821 for (int j = method.m_aParameters.Count() - 1; j >= 0; --j)
822 {
823 param = method.m_aParameters[j];
824 if (line2.StartsWith(FAULTY_PARAM + param.m_sName))
825 {
826 string suffix;
827 switch (param.m_iInOut)
828 {
829 case 0: suffix = "[in]"; break;
830 case 1: suffix = "[out]"; break;
831 case 2: suffix = "[in,out]"; break;
832 }
833
834 line2.Replace(FAULTY_PARAM + param.m_sName, BASE_PARAM + suffix + " " + param.m_sName);
835 break;
836 }
837 }
838 }
839
840 lines[i] = DOXYGEN_LINE_START + " " + line2;
841 }
842 else
843 {
844 lines[i] = DOXYGEN_LINE_START;
845 }
846 }
847
848 return SCR_StringHelper.Join("\n", lines, true);
849 }
850
851 //------------------------------------------------------------------------------------------------
857 protected static string AddIndent(string input, int indentLevel = 1, string indent = "\t")
858 {
859 if (!input)
860 return string.Empty;
861
862 if (indentLevel < 1)
863 indentLevel = 1;
864
865 indent = SCR_StringHelper.PadLeft("", indentLevel, indent);
866 input.Replace("\n", "\n" + indent);
867 return indent + input;
868 }
869
870 //------------------------------------------------------------------------------------------------
871 protected override void Configure()
872 {
873 Init();
874 Workbench.ScriptDialog("Configure Doxygen plugin", "Add Doxygen skeleton where wanted and needed.", this);
875 }
876
877 //------------------------------------------------------------------------------------------------
878 [ButtonAttribute("OK", true)]
879 protected bool ButtonOK()
880 {
881 return true;
882 }
883}
884
885//class SCR_DoxygenFillerPlugin_Class
886//{
887// string m_sName;
888// string m_sParent;
889//
890// ref array<ref SCR_DoxygenFillerPlugin_Variable> m_aVariables = {};
891// ref array<ref SCR_DoxygenFillerPlugin_Method> m_aMethods = {};
892//}
893//
894//class SCR_DoxygenFillerPlugin_Variable
895//{
896// bool m_bIsStatic;
897// bool m_bIsConstant;
898// int m_iProtection; //!< private = 0, protected = 1, public = 2
899// string m_sRef;
900// string m_sType;
901// string m_sName;
902// string m_sStartValue;
903//}
904
905class SCR_DoxygenFillerPlugin_Method
906{
907 int m_iProtection;
908 bool m_bIsStatic;
909 bool m_bIsSealed; // unused atm
910 bool m_bIsEvent; // unused atm
911 bool m_bOverride;
912 string m_sReturnType;
913 string m_sName;
914 ref array<ref SCR_DoxygenFillerPlugin_MethodParameter> m_aParameters = {};
915}
916
917class SCR_DoxygenFillerPlugin_MethodParameter
918{
919 int m_iInOut;
920 bool m_bNotNull; // unused atm
921 string m_sType; // unused atm
922 string m_sName;
923 string m_sDefaultValue; // unused atm
924}
925#endif
override void Init()
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
LocalizedString m_sName
override void Run()
bool ButtonOK()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
override void Configure()
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
static bool WriteFileContent(string filePath, notnull array< string > lines)
static array< string > ReadFileContent(string filePath, bool printWarning=true)
static array< string > GetLines(string input, bool removeEmptyLines=false, bool trimLines=false)
static string PadLeft(string input, int length, string padding=SPACE)
static string ReplaceRecursive(string input, string sample, string replacement)
static int CountOccurrences(string haystack, string needle, bool caseInsensitive=false)
static int IndexOfFrom(string input, int start, notnull array< string > samples)
static bool StartsWithAny(string input, notnull array< string > lineStarts)
static string ReplaceTimes(string input, string sample, string replacement, int howMany=1, int skip=0)
static bool IsEmptyOrWhiteSpace(string input)
static string Join(string separator, notnull array< string > pieces, bool joinEmptyEntries=true)
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
SCR_FieldOfViewSettings Attribute