Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AutocompletePlugin.c
Go to the documentation of this file.
1#ifdef WORKBENCH
27[WorkbenchPluginAttribute(name: "Autocomplete", description: "Helps autocompleting keywords, adding [Attribute()] decorators, cast nullchecks etc.", shortcut: "Ctrl+Return" /* "Ctrl+Space" */, wbModules: { "ScriptEditor" }, awesomeFontCode: 0xE2CA)]
28class SCR_AutocompletePlugin : WorkbenchPlugin
29{
30 /*
31 Category: General
32 */
33
34 [Attribute(defvalue: "1", desc: "Add class constructor on \"" + CONSTRUCTOR_KEYWORD + "\" keyword", category: "General")]
35 protected bool m_bAddConstructor;
36
37 [Attribute(defvalue: "1", desc: "Add class destructor on \"" + DESTRUCTOR_KEYWORD + "\" keyword", category: "General")]
38 protected bool m_bAddDestructor;
39
40 [Attribute(defvalue: "1", desc: "Autocomplete \" = new\" statements, e.g:"
41 + "\n- array<int> myArray = new → array<int> myArray = {};"
42 + "\n- array<ref SCR_MyClass> myArray = new → array<ref SCR_MyClass> myArray = {};"
43 + "\n- map<int, ref SCR_MySuperClass> myMap = new → map<int, ref SCR_MySuperClass> myMap = new map<int, ref SCR_MySuperClass>();"
44 + "\n- bool m_bMyVar = new → bool m_bMyVar;", category: "General")]
45 protected bool m_bAddInstantiation;
46
47 [Attribute(defvalue: "0", uiwidget: UIWidgets.ComboBox, desc: "On which line ending does instantion completion triggers", enums: SCR_ParamEnumArray.FromString("Both \"= new\" and \"=\";\"= new\";\"=\" only"), category: "General")]
48 protected int m_iInstantiationTrigger;
49
50 [Attribute(defvalue: "1", desc:"Fix \"new\" statements, e.g:"
51 + "\n- SCR_MyClass instance = new SCR_MyClass; → SCR_MyClass instance = new SCR_MyClass();"
52 + "\n- array<string> instance = new array<string>(); → array<string> instance = {};", category: "General")]
53 protected bool m_bFixInstantiation;
54
55 [Attribute(defvalue: "1", desc: "Add a nullcheck below a \"Class a = Class.Cast(b)\" statement if not present", category: "General")]
56 protected bool m_bAddCastNullcheck;
57
58 [Attribute(defvalue: "1", desc: "Add (or fix) a validity check below a \"Resource.Load\" statement if not present", category: "General")]
59 protected bool m_bAddOrFixResourceLoadValidityCheck;
60
61 [Attribute(defvalue: LogLevel.NORMAL.ToString(), desc: "Add a LogLevel to a Print or PrintFormat if not present", enums: {
62 new ParamEnum("Disabled", "-1", "Do not add log level to Print/PrintFormat missing it"),
63 new ParamEnum("LogLevel.NORMAL", LogLevel.NORMAL.ToString()),
64 new ParamEnum("LogLevel.WARNING", LogLevel.WARNING.ToString()),
65 new ParamEnum("LogLevel.ERROR", LogLevel.ERROR.ToString()),
66 new ParamEnum("LogLevel.FATAL", LogLevel.FATAL.ToString()),
67 }, uiwidget: UIWidgets.ComboBox, category: "General")]
68 protected LogLevel m_eAddPrintLogLevel;
69
70// [Attribute(defvalue: "1", desc: "Keep comment indentation on commented keyword's usage (e.g \" ctor // TODO\")")]
71 protected bool m_bKeepCommentIndentation = true;
72
73 /*
74 Category: Keywords
75 */
76
77 [Attribute(defvalue: "1", desc: "Use the tool's keyword list below", category: "Keywords")]
78 protected bool m_bUseToolKeywords;
79
80 [Attribute(desc: "Tool-defined keyword-replacement pairs - editable and resettable", category: "Keywords")]
81 protected ref array<ref SCR_AutocompletePlugin_KeywordData> m_aToolKeywords;
82
83 [Attribute(defvalue: "1", desc: "Use the user-defined keyword list below - this list will never be touched or reset in any way by the tool", category: "Keywords")]
84 protected bool m_bUseUserKeywords;
85
86 [Attribute(desc: "User-defined keyword-replacement pairs", category: "Keywords")]
87 protected ref array<ref SCR_AutocompletePlugin_KeywordData> m_aUserKeywords;
88
89 /*
90 Category: Attributes
91 */
92
93 [Attribute(defvalue: "1", desc: "Use Tool Attributes", category: "Attribute Decorators")]
94 protected bool m_bUseToolAttributeDecorators;
95
96 [Attribute(desc: "Tool-defined [Attribute()] decorators - editable and resettable", category: "Attribute Decorators")]
97 protected ref array<ref SCR_AutocompletePlugin_AttributeData> m_aToolAttributeDecorators;
98
99 [Attribute(defvalue: "1", desc: "Use the user-defined [Attribute()] decorator list below - this list will never be touched or reset in any way by the tool", category: "Attribute Decorators")]
100 protected bool m_bUseUserAttributeDecorators;
101
102 [Attribute(desc: "User-defined [Attribute()] decorators", category: "Attribute Decorators")]
103 protected ref array<ref SCR_AutocompletePlugin_AttributeData> m_aUserAttributeDecorators;
104
107
108 protected static const string SEP_NL = SCR_StringHelper.DOUBLE_SLASH + "------------------------------------------------------------------------------------------------\n";
109 protected static const string CONSTRUCTOR_KEYWORD = "ctor";
110 protected static const string DESTRUCTOR_KEYWORD = "dtor";
111 protected static const string ENTITY_SUFFIX = "Entity"; // used to detect IEntity's ctor(IEntitySource src, IEntity parent)
112
113 protected static const ref array<string> NATIVE_TYPES = {
114 "bool", "float", "int", "string", "typename", "vector",
115 "FactionKey", "LocalizedString", "ResourceName",
116 };
117
118 //------------------------------------------------------------------------------------------------
119 override void Run()
120 {
121 AutoCompleteCurrentLine();
122 }
123
124 //------------------------------------------------------------------------------------------------
125 protected void AutoCompleteCurrentLine()
126 {
127 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
128 if (!scriptEditor)
129 {
130 PrintFormat("[SCR_AutocompletePlugin.AutoCompleteCurrentLine] Script Editor is unavailable?! (%1 L%2)", __FILE__, __LINE__, level: LogLevel.ERROR);
131 return;
132 }
133
134 string currentLine; // used as currentFile first
135 if (!scriptEditor.GetCurrentFile(currentLine))
136 return;
137
138// if (currentLine == __FILE__)
139// {
140// Print("cannot process plugin file");
141// return;
142// }
143
144 if (!scriptEditor.GetLineText(currentLine))
145 {
146 PrintFormat("[SCR_AutocompletePlugin.AutoCompleteCurrentLine] Script Editor cannot read the current line (%1 L%2)", __FILE__, __LINE__, level: LogLevel.ERROR);
147 return;
148 }
149
150 string indentation;
151 SCR_BasicCodeFormatterPlugin.GetIndentAndLineContent(currentLine, indentation, currentLine);
152
153 int commentIndex = currentLine.IndexOf(SCR_StringHelper.DOUBLE_SLASH);
154 if (commentIndex == 0) // the whole line is a comment
155 return;
156
157 string indentedComment;
158 if (commentIndex > 0)
159 {
160 if (m_bKeepCommentIndentation)
161 {
162 string codeAndCommentLine = currentLine;
163 currentLine = currentLine.Substring(0, commentIndex);
164 currentLine.TrimInPlace();
165 indentedComment = codeAndCommentLine.Substring(currentLine.Length(), codeAndCommentLine.Length() - currentLine.Length());
166 indentedComment = SCR_StringHelper.TrimRight(indentedComment);
167 }
168 else
169 {
170 indentedComment = currentLine.Substring(commentIndex, currentLine.Length() - commentIndex);
171 indentedComment.TrimInPlace();
172 indentedComment = SCR_StringHelper.SPACE + indentedComment;
173 currentLine = currentLine.Substring(0, commentIndex); // trimmed below
174 }
175 }
176
177 currentLine.TrimInPlace();
178 if (!currentLine)
179 return;
180
181 if (m_bAddInstantiation)
182 {
183 if (((m_iInstantiationTrigger == 0 || m_iInstantiationTrigger == 2) && currentLine.EndsWith(" ="))
184 || ((m_iInstantiationTrigger == 0 || m_iInstantiationTrigger == 1) && currentLine.EndsWith(" = new")))
185 {
186 if (AddNewType(scriptEditor, indentation, currentLine, indentedComment))
187 return;
188 }
189 }
190
191 if (m_bFixInstantiation)
192 {
193 if (FixInstantiation(scriptEditor, indentation, currentLine, indentedComment))
194 return;
195 }
196
197 if (m_bAddCastNullcheck && currentLine.Contains(".Cast(")) // )
198 {
199 if (AddCastCheck(scriptEditor, indentation, currentLine))
200 return;
201 }
202
203 if (m_bAddOrFixResourceLoadValidityCheck && currentLine.Contains("Resource.Load(")) // )
204 {
205 if (AddResourceLoadValidityCheck(scriptEditor, indentation, currentLine))
206 return;
207 }
208
209 if (m_eAddPrintLogLevel > -1
210 && (currentLine.StartsWith("Print(") || currentLine.StartsWith("PrintFormat(")) // ))
211 && currentLine.EndsWith(");"))
212 {
213 if (AddPrintLogLevel(scriptEditor, indentation, currentLine, indentedComment))
214 return;
215 }
216
217 string lineLC = currentLine;
218 lineLC.ToLower();
219
220 if (m_bAddConstructor && lineLC == CONSTRUCTOR_KEYWORD)
221 {
222 if (AddConstructorDestructor(scriptEditor, true, indentation, indentedComment))
223 return;
224 }
225
226 if (m_bAddDestructor && lineLC == DESTRUCTOR_KEYWORD)
227 {
228 if (AddConstructorDestructor(scriptEditor, false, indentation, indentedComment))
229 return;
230 }
231
232 // [Attribute()] ?
233 if (indentation == SCR_StringHelper.TAB
234 && currentLine.Contains(SCR_StringHelper.SPACE)
235 && currentLine.EndsWith(";")
236 && !currentLine.Contains("="))
237 {
238 CheckToolAttributeDecorators();
239 FillAttributeDecoratorMap();
240 if (AddAttributeDecorator(scriptEditor, indentation, currentLine))
241 return;
242 }
243
244 // only keywords can save us here
245
246 CheckToolKeywords();
247 FillKeywordsMap();
248
249 SCR_AutocompletePlugin_KeywordData data = m_mKeywords.Get(currentLine); // case-sensitive!
250 if (data)
251 scriptEditor.SetLineText(AddIndentation(string.Format(data.m_sValue, indentedComment), indentation));
252 }
253
254 //------------------------------------------------------------------------------------------------
261 protected bool AddNewType(notnull ScriptEditor scriptEditor, string indentation, string currentLine, string comment)
262 {
263 if (!currentLine.Contains(SCR_StringHelper.EQUALS))
264 return false;
265
266 array<string> tokens = {};
267 currentLine.Split(SCR_StringHelper.EQUALS, tokens, true);
268
269 int tokensCount = tokens.Count();
270 if (m_iInstantiationTrigger == 1) // "= new" only
271 {
272 if (tokensCount < 2)
273 return false;
274 }
275 else
276 {
277 if (tokensCount < 1)
278 return false;
279 }
280
281 tokens[0].Split(SCR_StringHelper.SPACE, tokens, true);
282 if (tokens.Count() < 2)
283 return false;
284
285 tokens.RemoveItemOrdered("auto");
286 tokens.RemoveItemOrdered("autoptr");
287 tokens.RemoveItemOrdered("protected");
288 tokens.RemoveItemOrdered("private");
289 tokens.RemoveItemOrdered("static");
290 if (tokens.IsEmpty())
291 return false;
292
293 if (tokens[0] == "ref")
294 {
295 tokens.RemoveOrdered(0);
296
297 if (indentation != SCR_StringHelper.TAB && currentLine.StartsWith("ref ") && currentLine != "ref ")
298 {
299 currentLine = currentLine.Substring(4, currentLine.Length() - 4);
300 currentLine.TrimInPlace();
301 }
302 }
303
304 tokensCount = tokens.Count();
305 if (tokensCount < 2)
306 return false;
307
308 string newVarType;
309 if (tokensCount == 2)
310 {
311 newVarType = tokens[0];
312 }
313 else
314 {
315 tokens.Remove(tokensCount - 1);
316 newVarType = SCR_StringHelper.Join(SCR_StringHelper.SPACE, tokens, false);
317 }
318
319 currentLine.Replace(" = new", " =");
320
321 if (NATIVE_TYPES.Contains(newVarType))
322 {
323 currentLine.Replace(" =", string.Empty);
324 currentLine.TrimInPlace();
325 currentLine += ";";
326
327 scriptEditor.SetLineText(string.Format("%1%2%3", indentation, currentLine, comment));
328 return true;
329 }
330
331 if (newVarType.StartsWith("array<"))
332 currentLine += " {};";
333 else
334 currentLine += " new " + newVarType + "();";
335
336 scriptEditor.SetLineText(string.Format("%1%2%3", indentation, currentLine, comment));
337 return true;
338 }
339
340 //------------------------------------------------------------------------------------------------
346 protected bool FixInstantiation(notnull ScriptEditor scriptEditor, string indentation, string currentLine, string comment)
347 {
348 if (!currentLine.Contains(" = new "))
349 return false;
350
351 array<string> tokens = {};
352 currentLine.Split(SCR_StringHelper.EQUALS, tokens, true);
353
354 int tokensCount = tokens.Count();
355 if (m_iInstantiationTrigger == 1) // "= new" only
356 {
357 if (tokensCount < 2)
358 return false;
359 }
360 else
361 {
362 if (tokensCount < 1)
363 return false;
364 }
365
366 tokens[0].Split(SCR_StringHelper.SPACE, tokens, true);
367 if (tokens.Count() < 2)
368 return false;
369
370 array<string> keywords;
371 if (indentation == SCR_StringHelper.TAB) // member/static properties
372 keywords = {};
373
374 tokens.RemoveItemOrdered("auto");
375 tokens.RemoveItemOrdered("autoptr");
376 if (keywords)
377 {
378 if (tokens.RemoveItemOrdered("protected"))
379 keywords.Insert("protected");
380 else
381 if (tokens.RemoveItemOrdered("private"))
382 keywords.Insert("private");
383 }
384
385 if (!tokens.IsEmpty() && tokens[0] == "ref")
386 {
387 tokens.RemoveOrdered(0);
388 if (keywords) // member/static property = keep ref
389 keywords.Insert("ref");
390 }
391
392 tokensCount = tokens.Count();
393 if (tokensCount < 2)
394 return false;
395
396 string varType, varName;
397 if (tokensCount == 2)
398 {
399 varType = tokens[0];
400 varName = tokens[1];
401 }
402 else
403 {
404 varName = tokens[tokensCount - 1];
405 tokens.Remove(tokensCount - 1);
406 varType = SCR_StringHelper.Join(SCR_StringHelper.SPACE, tokens, false);
407 }
408
409 string newLine;
410 if (NATIVE_TYPES.Contains(varType))
411 {
412 newLine = string.Format("%1 %2;", varType, varName);
413 if (keywords)
414 keywords.RemoveItemOrdered("ref");
415 }
416 else
417 {
418 if (varType.StartsWith("array<"))
419 newLine = string.Format("%1 %2 = {};", varType, varName);
420 else
421 newLine = string.Format("%1 %2 = new %1();", varType, varName);
422 }
423
424 if (keywords && !keywords.IsEmpty())
425 newLine = SCR_StringHelper.Join(SCR_StringHelper.SPACE, keywords) + SCR_StringHelper.SPACE + newLine;
426
427 if (currentLine == newLine)
428 return false;
429
430 scriptEditor.SetLineText(string.Format("%1%2%3", indentation, newLine, comment));
431 return true;
432 }
433
434 //------------------------------------------------------------------------------------------------
439 protected bool AddCastCheck(notnull ScriptEditor scriptEditor, string indentation, string currentLine)
440 {
441 array<string> tokens = {};
442 currentLine.Split(SCR_StringHelper.SPACE, tokens, true);
443
444 int tokensCount = tokens.Count();
445 if (tokensCount < 3)
446 return false;
447
448 int varIndex;
449 if (tokensCount == 3)
450 varIndex = 0;
451 else // greater than that
452 varIndex = 1;
453
454 if (tokens[varIndex + 1] != "=")
455 return false;
456
457 string varName = tokens[varIndex];
458
459 string belowLine;
460 int currentLineNumber = scriptEditor.GetCurrentLine();
461 if (!scriptEditor.GetLineText(belowLine, currentLineNumber + 1))
462 return false;
463
464 belowLine.TrimInPlace();
465 if (belowLine.StartsWith("if (!" + varName + ")"))
466 return false;
467
468 string insert = "if (!" + varName + ")\n\treturn;";
469 if (belowLine) // !.IsEmpty()
470 insert += "\n";
471
472 scriptEditor.InsertLine(AddIndentation(insert, indentation), scriptEditor.GetCurrentLine() + 1);
473 return true;
474 }
475
476 //------------------------------------------------------------------------------------------------
481 protected bool AddResourceLoadValidityCheck(notnull ScriptEditor scriptEditor, string indentation, string currentLine)
482 {
483 array<string> tokens = {};
484 currentLine.Split(SCR_StringHelper.SPACE, tokens, true);
485
486 if (tokens[0] == "Resource")
487 tokens.RemoveOrdered(0);
488
489 if (tokens.Count() < 3)
490 return false;
491
492 if (tokens[1] != "=")
493 return false;
494
495 string belowLine;
496 int nextLineNumber = scriptEditor.GetCurrentLine() + 1;
497 if (!scriptEditor.GetLineText(belowLine, nextLineNumber))
498 return false;
499
500 string varName = tokens[0];
501 belowLine.TrimInPlace();
502 if (belowLine.StartsWith("if (!" + varName + ".IsValid())"))
503 return false;
504
505 string nullCheck = "if (!" + varName + ")";
506 if (belowLine.StartsWith(nullCheck)) // fix
507 {
508 if (belowLine == nullCheck)
509 {
510 scriptEditor.SetLineText(indentation + "if (!" + varName + ".IsValid())", nextLineNumber)
511 }
512 else // move comment along
513 {
514 string restOfTheLine = belowLine.Substring(nullCheck.Length(), belowLine.Length() - nullCheck.Length());
515 scriptEditor.SetLineText(indentation + "if (!" + varName + ".IsValid())" + restOfTheLine, nextLineNumber);
516 }
517
518 return true;
519 }
520
521 string insert = "if (!" + varName + ".IsValid())\n\treturn;";
522 if (belowLine) // !.IsEmpty()
523 insert += "\n";
524
525 scriptEditor.InsertLine(AddIndentation(insert, indentation), nextLineNumber);
526 return true;
527 }
528
529 //------------------------------------------------------------------------------------------------
536 protected bool AddPrintLogLevel(notnull ScriptEditor scriptEditor, string indentation, string currentLine, string comment)
537 {
538 if (currentLine.StartsWith("Print(")) // )
539 {
540 if (currentLine.Contains("LogLevel.") || currentLine.EndsWith(", level);") || currentLine.EndsWith(", logLevel);"))
541 return false;
542
543 scriptEditor.SetLineText(
544 string.Format("%1%2, LogLevel.%3);%4",
545 indentation,
546 currentLine.Substring(0, currentLine.Length() - 2),
547 typename.EnumToString(LogLevel, m_eAddPrintLogLevel),
548 comment));
549
550 return true;
551 }
552
553 if (currentLine.StartsWith("PrintFormat(")) // )
554 {
555 if (currentLine.Contains("level: "))
556 return false;
557
558 if (currentLine.Contains("LogLevel."))
559 scriptEditor.SetLineText(indentation + SCR_StringHelper.InsertAt(currentLine, "level: ", currentLine.LastIndexOf("LogLevel.")) + comment);
560 else
561 scriptEditor.SetLineText(
562 string.Format("%1%2, level: LogLevel.%3);%4",
563 indentation,
564 currentLine.Substring(0, currentLine.Length() - 2),
565 typename.EnumToString(LogLevel, m_eAddPrintLogLevel),
566 comment));
567
568 return true;
569 }
570
571 return false;
572 }
573
574 //------------------------------------------------------------------------------------------------
579 protected bool AddAttributeDecorator(notnull ScriptEditor scriptEditor, string indentation, string currentLine)
580 {
581 int currentLineNumber = scriptEditor.GetCurrentLine();
582 if (currentLineNumber > 0)
583 {
584 string aboveLine;
585 if (!scriptEditor.GetLineText(aboveLine, currentLineNumber - 1) || aboveLine.StartsWith("\t[Attribute(")) // )
586 return false;
587 }
588
589 array<string> tokens = {};
590 currentLine.Split(SCR_StringHelper.SPACE, tokens, true);
591
592 tokens.RemoveItemOrdered("protected");
593 tokens.RemoveItemOrdered("private");
594 tokens.RemoveItemOrdered("ref");
595
596 int count = tokens.Count();
597 if (count < 2)
598 return false;
599
600 if (count > 2)
601 {
602 if (tokens[0] == "array<ref")
603 {
604 tokens[0] = tokens[0] + SCR_StringHelper.SPACE + tokens[1];
605 tokens.RemoveOrdered(1);
606 --count;
607 }
608 }
609
610 if (count > 2 && tokens[2] != "=")
611 return false;
612
613 string name = tokens[1];
614 if (!name.StartsWith("m_"))
615 return false;
616
617 int nameLength = name.Length();
618 if (nameLength < 3) // m_W is valid
619 return false;
620
621 string hungarianPrefix = name[2];
622 if (!SCR_StringHelper.LOWERCASE.Contains(hungarianPrefix))
623 hungarianPrefix = string.Empty;
624
625 string typeStr = tokens[0];
626 string friendlyName = SCR_StringHelper.FormatValueNameToUserFriendly(name);
627
628 SCR_AutocompletePlugin_AttributeData data = m_mAttributeDecorators.Get(typeStr);
629 if (data && hungarianPrefix == data.m_sPrefix)
630 {
631 scriptEditor.InsertLine(indentation + string.Format(data.m_sValue, friendlyName, typeStr));
632 return true;
633 }
634
635 // no exact type match found, dig deeper
636
637 typename type = typeStr.ToType();
638
639 // no map/set support
640 if (type && (type.IsInherited(map) || type.IsInherited(set)))
641 return false;
642
643 // array
644 if (typeStr.StartsWith("array<") || (type && type.IsInherited(array)))
645 {
646 if (hungarianPrefix == "a")
647 {
648 data = m_mAttributeDecorators.Get("array");
649 if (data)
650 scriptEditor.InsertLine(indentation + string.Format(data.m_sValue, friendlyName, typeStr));
651 else
652 scriptEditor.InsertLine(indentation + string.Format("[Attribute(desc: \"%1\")]", friendlyName, typeStr));
653 }
654
655 return true;
656 }
657
658 // enum
659 if (hungarianPrefix == "e")
660 {
661 int length = typeStr.Length();
662 bool isEnum = length > 2 && typeStr[0] == "E" && SCR_StringHelper.UPPERCASE.Contains(typeStr[1]); // e.g EFuelType
663 if (!isEnum) // tag-prefixed?
664 {
665 int index = typeStr.IndexOf("_E");
666 if (index > 1 && index < 9 && index + 2 < typeStr.Length() && SCR_StringHelper.UPPERCASE.Contains(typeStr[index + 2])) // if has _E + uppercase within the first 11 chars (tag = 2 to 8 chars)
667 isEnum = true;
668 }
669
670 if (isEnum)
671 {
672 data = m_mAttributeDecorators.Get("enum");
673 if (data)
674 scriptEditor.InsertLine(indentation + string.Format(data.m_sValue, friendlyName, typeStr));
675 else
676 scriptEditor.InsertLine(indentation + string.Format("[Attribute(desc: \"%1\", uiwidget: UIWidgets.CheckBox, enumType: %2)]", friendlyName, typeStr));
677
678 return true;
679 }
680 }
681
682 // objects - also covers arrays, hence having them first
683 if (type && type.IsInherited(Managed))
684 {
685 scriptEditor.InsertLine(indentation + string.Format("[Attribute(desc: \"%1\")]", friendlyName, typeStr));
686 return true;
687 }
688
689 return false;
690 }
691
692 //------------------------------------------------------------------------------------------------
697 protected string AddIndentation(string input, string indentation)
698 {
699 array<string> lines = {};
700 input.Split(SCR_StringHelper.LINE_RETURN, lines, false);
701
702 if (lines.IsEmpty())
703 return string.Empty;
704
705 foreach (int i, string line : lines)
706 {
707 if (line)
708 lines[i] = indentation + line;
709 }
710
711 return SCR_StringHelper.Join(SCR_StringHelper.LINE_RETURN, lines, true);
712 }
713
714 //------------------------------------------------------------------------------------------------
720 protected bool AddConstructorDestructor(notnull ScriptEditor scriptEditor, bool isConstructor, string indentation, string comment)
721 {
722 string className;
723 string methodName;
724 if (!SCR_CopyClassAndMethodPlugin.GetCursorClassAndMethodNames(scriptEditor, className, methodName))
725 return false;
726
727 if (!className)
728 {
729 Print("Cannot define current class", LogLevel.WARNING);
730 className = "DefaultClassName";
731 }
732
733 string text;
734 if (isConstructor)
735 {
736 if (className.EndsWith(ENTITY_SUFFIX))
737 text = string.Format(SEP_NL + SCR_StringHelper.DOUBLE_SLASH + " constructor\nvoid %1(IEntitySource src, IEntity parent)%2\n{\n\t\n}", className, comment);
738 else
739 text = string.Format(SEP_NL + SCR_StringHelper.DOUBLE_SLASH + " constructor\nvoid %1()%2\n{\n\t\n}", className, comment);
740 }
741 else
742 {
743 text = string.Format(SEP_NL + SCR_StringHelper.DOUBLE_SLASH + " destructor\nvoid ~%1()%2\n{\n\t\n}", className, comment);
744 }
745
746 scriptEditor.SetLineText(AddIndentation(text, indentation));
747 return true;
748 }
749
750 //------------------------------------------------------------------------------------------------
751 protected void CheckToolKeywords()
752 {
753 set<string> keywords = new set<string>();
754 SCR_AutocompletePlugin_KeywordData tmpData;
755 for (int i = m_aToolKeywords.Count() - 1; i >= 0; i--)
756 {
757 tmpData = m_aToolKeywords[i];
758 if (SCR_StringHelper.IsEmptyOrWhiteSpace(tmpData.m_sKeyword))
759 m_aToolKeywords.RemoveOrdered(i);
760 else
761 keywords.Insert(tmpData.m_sKeyword);
762 }
763
764 // structure
765 if (!keywords.Contains("if")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("if", "if (condition)%1\n{\n\t\n}"));
766 if (!keywords.Contains("ife")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("ife", "if (condition)%1\n{\n\t\n}\nelse\n{\n\t\n}"));
767 if (!keywords.Contains("for")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("for", "for (int i, count = arr.Count(); i < count; i++)%1\n{\n\t\n}"));
768 if (!keywords.Contains("forr")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("forr", "for (int i = arr.Count() - 1; i >= 0; i--)%1\n{\n\t\n}")); // for, reversed
769 if (!keywords.Contains("foreach")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("foreach", "foreach (string item : items)%1\n{\n\t\n}"));
770 if (!keywords.Contains("foreachi")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("foreachi", "foreach (int i, SCR_Class item : items)%1\n{\n\t\n}")); // foreach with index
771 if (!keywords.Contains("switch")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("switch", "switch (value)%1\n{\n\tcase 0:\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n}"));
772 if (!keywords.Contains("while")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("while", "while (condition)%1\n{\n\t\n}"));
773
774 // big structure
775 if (!keywords.Contains("class")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("class", "class SCR_MyClass%1\n{\n\tprotected string m_sValue = \"Generated class\";\n\n\t" + SEP_NL + "\t/" + "/! constructor\n\tvoid SCR_MyClass()\n\t{\n\t\t\n\t}\n}"));
776 if (!keywords.Contains("func")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("func", SEP_NL + SCR_StringHelper.DOUBLE_SLASH + "! \\param[in] parameter\n" + "protected void Method(int parameter)%1\n{\n\t\n}")); // meh alias
777 if (!keywords.Contains("method")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("method", SEP_NL + SCR_StringHelper.DOUBLE_SLASH + "! \\param[in] parameter\n" + "protected void Method(int parameter)%1\n{\n\t\n}"));
778
779 // syntactic sugar
780// if (!keywords.Contains("const")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("const", "protected static const int CONST_VALUE = 42;"));
781// if (!keywords.Contains("array")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("array", "protected ref array<string> m_aArray = {};"));
782// if (!keywords.Contains("map")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("map", "protected ref map<int, string> m_mMap = new map<int, string>();"));
783// if (!keywords.Contains("set")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("set", "protected ref set<string> m_mMap = new set<string>();"));
784 if (!keywords.Contains("findcomp")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("findcomp", "SCR_ComponentClass component = SCR_ComponentClass.Cast(entity.FindComponent(SCR_ComponentClass));%1\nif (!comp)\n\treturn;"));
785 if (!keywords.Contains("print")) m_aToolKeywords.Insert(SCR_AutocompletePlugin_KeywordData.Create("print", "Print(\"fill\", LogLevel.NORMAL);"));
786 }
787
788 //------------------------------------------------------------------------------------------------
789 protected void FillKeywordsMap()
790 {
791 m_mKeywords.Clear();
792
793 if (m_bUseToolKeywords)
794 {
795 foreach (SCR_AutocompletePlugin_KeywordData data : m_aToolKeywords)
796 {
797 // data.m_sKeyword.TrimInPlace();
798 if (data.m_bEnabled && !m_mKeywords.Contains(data.m_sKeyword))
799 m_mKeywords.Insert(data.m_sKeyword, data);
800 }
801 }
802
803 if (m_bUseUserKeywords)
804 {
805 foreach (SCR_AutocompletePlugin_KeywordData data : m_aUserKeywords)
806 {
807 // data.m_sKeyword.TrimInPlace();
808 if (data.m_bEnabled && !m_mKeywords.Contains(data.m_sKeyword))
809 m_mKeywords.Insert(data.m_sKeyword, data);
810 }
811 }
812 }
813
814 //------------------------------------------------------------------------------------------------
815 protected void CheckToolAttributeDecorators()
816 {
817 set<string> attributeDecorators = new set<string>();
818 SCR_AutocompletePlugin_AttributeData tmpData;
819 for (int i = m_aToolAttributeDecorators.Count() - 1; i >= 0; i--)
820 {
821 tmpData = m_aToolAttributeDecorators[i];
822 if (SCR_StringHelper.IsEmptyOrWhiteSpace(tmpData.m_sType))
823 m_aToolAttributeDecorators.RemoveOrdered(i);
824 else
825 attributeDecorators.Insert(tmpData.m_sType);
826 }
827
828 if (!attributeDecorators.Contains("array")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("array", "a", "[Attribute(defvalue: \"" + "\", desc: \"%1\")]"));
829 if (!attributeDecorators.Contains("bool")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("bool", "b", "[Attribute(defvalue: \"1\", desc: \"%1\")]"));
830 if (!attributeDecorators.Contains("Color")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("Color", "", "[Attribute(defvalue: \"1 1 1 1\", desc: \"%1\")]"));
831 if (!attributeDecorators.Contains("enum")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("enum", "e", "[Attribute(defvalue: \"0\", desc: \"%1\", uiwidget: UIWidgets.ComboBox, enumType: %2)]"));
832 if (!attributeDecorators.Contains("float")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("float", "f", "[Attribute(defvalue: \"0\", desc: \"%1\", params: \"0 inf 0.01\")]"));
833 if (!attributeDecorators.Contains("int")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("int", "i", "[Attribute(defvalue: \"0\", desc: \"%1\", params: \"0 inf\")]"));
834 if (!attributeDecorators.Contains("LocalizedString")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("string", "s", "[Attribute(defvalue: \"#AR-Something\", desc: \"%1\")]"));
835 if (!attributeDecorators.Contains("ResourceName")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("ResourceName", "s", "[Attribute(defvalue: \"" + "\", desc: \"%1\", uiwidget: UIWidgets.ResourcePickerThumbnail, params: \"edds et wav\")]"));
836 if (!attributeDecorators.Contains("string")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("string", "s", "[Attribute(defvalue: \"Default value\", desc: \"%1\")]"));
837 if (!attributeDecorators.Contains("vector")) m_aToolAttributeDecorators.Insert(SCR_AutocompletePlugin_AttributeData.Create("vector", "v", "[Attribute(defvalue: \"0 0 0\", desc: \"%1\")]"));
838 }
839
840 //------------------------------------------------------------------------------------------------
841 protected void FillAttributeDecoratorMap()
842 {
843 m_mAttributeDecorators.Clear();
844
845 if (m_bUseToolAttributeDecorators)
846 {
847 foreach (SCR_AutocompletePlugin_AttributeData data : m_aToolAttributeDecorators)
848 {
849 if (data.m_bEnabled && !m_mAttributeDecorators.Contains(data.m_sType))
850 m_mAttributeDecorators.Insert(data.m_sType, data);
851 }
852 }
853
854 if (m_bUseUserAttributeDecorators)
855 {
856 foreach (SCR_AutocompletePlugin_AttributeData data : m_aUserAttributeDecorators)
857 {
858 if (data.m_bEnabled && !m_mAttributeDecorators.Contains(data.m_sType))
859 m_mAttributeDecorators.Insert(data.m_sType, data);
860 }
861 }
862 }
863
864 //------------------------------------------------------------------------------------------------
865 protected override void Configure()
866 {
867 CheckToolKeywords();
868 CheckToolAttributeDecorators();
869 Workbench.ScriptDialog("Autocomplete Plugin", "Autocompletion settings", this);
870 }
871
872 //------------------------------------------------------------------------------------------------
873 [ButtonAttribute("Close", true)]
874 protected int ButtonClose()
875 {
876 return 1;
877 }
878}
879
881class SCR_AutocompletePlugin_KeywordData
882{
883 [Attribute(defvalue: "1", desc: "Enable this keyword-text pair")]
884 bool m_bEnabled;
885
886 [Attribute(defvalue: "keyword", desc: "Keyword to be detected - case-sensitive")]
887 string m_sKeyword;
888
889 [Attribute(defvalue: "protected string m_sKeyword = \"keyword\";", desc: "Text replacing the detected keyword\n- \\n for line return\n- \\t for tabulation\n- %1 for the in-line comment that was after the keyword (if any)", uiwidget: UIWidgets.EditBoxMultiline)]
890 string m_sValue;
891
892 //------------------------------------------------------------------------------------------------
898 static SCR_AutocompletePlugin_KeywordData Create(string keyword, string value, bool enabled = true)
899 {
900 SCR_AutocompletePlugin_KeywordData result = new SCR_AutocompletePlugin_KeywordData();
901
902 result.m_bEnabled = enabled;
903 result.m_sKeyword = keyword;
904 result.m_sValue = value;
905
906 return result;
907 }
908}
909
911class SCR_AutocompletePlugin_AttributeData
912{
913 [Attribute(defvalue: "1", desc: "Enable this attribute decorator")]
914 bool m_bEnabled;
915
916 [Attribute(defvalue: "array<ref SCR_Bird>", desc: "Classname or native type")]
917 string m_sType;
918
919 [Attribute(defvalue: "a", desc: "The 'x' in the m_xName prefix (e.g i for int, b for bool etc)\nCan be empty", precision: 1)]
920 string m_sPrefix;
921
922 [Attribute(defvalue: "[Attribute(defvalue: \"0\", desc: \"%1\")]", desc: "Value\n%1 = friendly variable name (e.g 'm_bCheckThis' → 'Check This')\n%2 = value type (e.g 'array<ref SCR_MyClass>')")]
923 string m_sValue;
924
925 //------------------------------------------------------------------------------------------------
931 static SCR_AutocompletePlugin_AttributeData Create(string type, string prefix, string value, bool enabled = true)
932 {
933 SCR_AutocompletePlugin_AttributeData result = new SCR_AutocompletePlugin_AttributeData();
934
935 result.m_sType = type.Trim();
936
937 prefix.TrimInPlace();
938 if (prefix)
939 result.m_sPrefix = prefix[0];
940
941 value.TrimInPlace();
942 result.m_sValue = value;
943 result.m_bEnabled = enabled;
944
945 return result;
946 }
947}
948#endif
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
params precision
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
EDamageType type
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Get all prefabs that have the spawner data
SCR_Faction ScriptedFaction SCR_BaseContainerCustomTitleField("m_sCallsign")
override void Run()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
override void Configure()
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
static ParamEnumArray FromString(string input)
static string FormatValueNameToUserFriendly(string valueName)
static bool IsEmptyOrWhiteSpace(string input)
static string TrimRight(string input)
static string Join(string separator, notnull array< string > pieces, bool joinEmptyEntries=true)
static string InsertAt(string input, string insertion, int insertionIndex=0)
Definition Types.c:486
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
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute