20 name:
"Basic Code Formatter",
21 shortcut:
"Ctrl+Shift+K",
22 wbModules: {
"ScriptEditor" },
23 awesomeFontCode: 0xF036)]
24class SCR_BasicCodeFormatterPlugin : WorkbenchPlugin
30 [
Attribute(defvalue:
"1",
desc:
"Fix e.g 'for( int' → 'for (int', ';;' → ';', ') ;' → ');', 'NULL' → 'null', ',' → ', ', etc.",
category:
"Formatting")]
31 protected bool m_bGeneralFormatting;
33 [
Attribute(defvalue:
"1",
desc:
"Remove empty spaces at the end of code lines",
category:
"Formatting")]
34 protected bool m_bTrimLineEnds;
36 [
Attribute(defvalue:
"1",
desc:
"Replace four-spaces tabs with the tab character and remove spaces mixed with tabs",
category:
"Formatting")]
37 protected bool m_bFixTabs;
40 protected bool m_bFixMethodSeparators;
45 [
Attribute(defvalue:
"1",
desc:
"Add one final line return if the file is missing one",
category:
"Formatting")]
46 protected bool m_bAddFinalLineReturn;
48 [
Attribute(
desc:
"Accepted class/enum prefixes (e.g 'SCR_', 'TAG_', etc) - an underscore is automatically added if missing. 'SCR_' is automatically whitelisted.\nCase-sensitive",
category:
"Formatting")]
49 protected ref array<string> m_aAcceptedScriptPrefixes;
55 [
Attribute(defvalue:
"0",
desc:
"Process all script files in the addon defined below (only process the currently opened file if unchecked)",
category:
"Batch Process")]
56 protected bool m_bBatchProcessAddon;
59 protected int m_iAddon;
61 [
Attribute(defvalue:
"1",
desc:
"Only log reports where processing did something to the file",
category:
"Batch Process")]
62 protected bool m_bOnlyLogChanges;
64 [
Attribute(defvalue:
"10", uiwidget:
UIWidgets.Slider,
desc:
"Max number of formatting reports to display - use -1 to display all reports",
params:
"-1 100 1",
category:
"Batch Process")]
65 protected int m_iMaxLoggedReports;
71 [
Attribute(defvalue:
"0",
desc:
"Demo mode only logs (possible) fixes and does not modify the file at all",
category:
"Options")]
72 protected bool m_bDemoMode;
74 [
Attribute(defvalue:
"1",
desc:
"Display a dialog on execution if unchecked - dialog is always displayed when batch-processing is enabled",
category:
"Options")]
75 protected bool m_bSilentExecution;
77 [
Attribute(defvalue:
"1",
desc:
"Only format DiffCommand-detected modified lines instead of all of them",
category:
"Options")]
78 protected bool m_bOnlyFormatModifiedLines;
81 protected bool m_bLogFixes;
84 protected bool m_bReportFindings;
86 [
Attribute(defvalue:
"scripts/xxx/generated/",
desc:
"Directories in which to avoid formatting (case-insensitive, no wildcards)",
category:
"Options")]
87 protected ref array<string> m_aExcludedDirectories;
89 [
Attribute(
desc:
"Spell check config - set it to null to reset its default values",
category:
"Options")]
90 protected ref SCR_BasicCodeFormatterSpellCheckConfig m_SpellCheckConfig;
92 [
Attribute(defvalue:
"1",
desc:
"Whether or not display flagged words details in the report",
category:
"Options")]
93 protected bool m_bShowSpellCheckFindingsDetails;
99 [
Attribute(defvalue: DEFAULT_DIFF_CMD,
desc:
"The command line used to generate the diff file\n%1 = absolute target filepath\n%2 = absolute destination filepath",
category:
"Advanced")]
100 protected string m_sDiffCommand;
104 protected ref array<ref array<string>> m_aGeneralFormatting_Start;
105 protected ref array<ref array<string>> m_aGeneralFormatting_Middle;
106 protected ref array<ref array<string>> m_aGeneralFormatting_End;
108 protected ref array<string> m_aForbiddenDivisions;
109 protected ref array<string> m_aPrefixLineChecks;
110 protected ref array<string> m_aPrefixChecks;
112 protected ref array<string> m_aForbiddenDirectories;
114 protected ref array<string> m_aForForEachWhileArray;
115 protected ref array<string> m_aIfForForEachWhileArray;
116 protected ref array<string> m_aEndBracketSemicolonArray;
117 protected ref array<string> m_aNewArrayNewRefArray;
118 protected ref array<string> m_aScriptInvokerArray;
129 protected static const int LINE_NUMBER_LIMIT = 12;
130 protected static const string LINE_NUMBER_RANGE =
"%1-%2";
132 protected static const string LOG_SEPARATOR =
"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -";
133 protected static const string BRACKET_OPEN =
"{";
134 protected static const string BRACKET_CLOSE =
"}";
135 protected static const string MEMBER_PREFIX =
"m_";
136 protected static const string STATIC_PREFIX =
"s_";
139 protected static const ref array<string> NATIVE_TYPES = {
140 "bool",
"float",
"int",
"string",
"typename",
"vector",
141 "FactionKey",
"LocalizedString",
"ResourceName",
147 protected static const string METHOD_SEPARATOR =
SCR_StringHelper.DOUBLE_SLASH +
"------------------------------------------------------------------------------------------------";
148 protected static const string DIFF_FILENAME =
"tempDiffFile.txt";
151 protected static const string DEFAULT_DIFF_CMD =
"cmd /c svn diff \"%1\" > \"%2\"";
153 protected static const ref array<string> FORCED_PREFIXES = {
"SCR_" };
154 protected static const ref array<string> EXCLUDED_DIRECTORIES = {
155 "scripts/Core/generated/",
156 "scripts/GameLib/generated/",
157 "scripts/Game/generated/",
158 "scripts/WorkbenchGameCommon/generated/",
160 protected static const string GENERATED_SCRIPT_WARNING =
"Do not modify, this script is generated";
161 protected static const ResourceName SPELLCHECK_CONFIG =
"{53D7DE332A43449F}Configs/Workbench/ScriptEditor/BasicCodeFormatterPlugin/BasicCodeFormatterSpellCheckConfig.conf";
165 protected override void Run()
167 if (m_bBatchProcessAddon || !m_bSilentExecution)
169 if (!Workbench.ScriptDialog(
"Configure 'Basic Code formatter' plugin",
"Configure formatting options",
this))
175 if (m_bBatchProcessAddon)
176 RunAddonFilesBatchProcess();
185 bool batchProcessAddon = m_bBatchProcessAddon;
186 bool demoMode = m_bDemoMode;
187 bool onlyFormatModifiedLines = m_bOnlyFormatModifiedLines;
189 m_bBatchProcessAddon =
false;
190 m_bOnlyFormatModifiedLines =
false;
195 m_bBatchProcessAddon = batchProcessAddon;
196 m_bDemoMode = demoMode;
197 m_bOnlyFormatModifiedLines = onlyFormatModifiedLines;
202 protected void Initialise()
204 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
212 m_aPrefixChecks.Clear();
214 m_aPrefixChecks = {};
216 for (
int i = m_aAcceptedScriptPrefixes.Count() - 1; i >= 0; i--)
218 string prefix = m_aAcceptedScriptPrefixes[i].Trim();
221 m_aAcceptedScriptPrefixes.RemoveOrdered(i);
225 if (!prefix.EndsWith(
"_"))
226 m_aAcceptedScriptPrefixes[i] = prefix +
"_";
229 array<string> toRemove = {};
230 foreach (
string forcedPrefix : FORCED_PREFIXES)
232 if (!m_aAcceptedScriptPrefixes.Contains(forcedPrefix))
234 m_aAcceptedScriptPrefixes.Insert(forcedPrefix);
235 toRemove.Insert(forcedPrefix);
239 foreach (
string prefix : m_aAcceptedScriptPrefixes)
241 foreach (
string prefixLineCheck : m_aPrefixLineChecks)
243 m_aPrefixChecks.Insert(prefixLineCheck + prefix);
247 foreach (
string forcedPrefix : toRemove)
249 m_aAcceptedScriptPrefixes.RemoveItem(forcedPrefix);
253 m_aForbiddenDirectories = {};
254 m_aForbiddenDirectories.Copy(EXCLUDED_DIRECTORIES);
255 foreach (
int i,
string excludedDirectory : m_aExcludedDirectories)
257 if (!excludedDirectory)
263 m_aExcludedDirectories[i] = excludedDirectory;
265 excludedDirectory.ToLower();
266 m_aForbiddenDirectories.Insert(excludedDirectory);
269 if (m_mForbiddenWords)
270 m_mForbiddenWords.Clear();
274 if (!m_SpellCheckConfig)
275 m_SpellCheckConfig = SCR_ConfigHelperT<SCR_BasicCodeFormatterSpellCheckConfig>.GetConfigObject(SPELLCHECK_CONFIG);
277 if (m_SpellCheckConfig && m_SpellCheckConfig.m_aEntries)
279 foreach (SCR_BasicCodeFormatterSpellCheckConfig_ForbiddenWordEntry entry : m_SpellCheckConfig.m_aEntries)
281 if (!entry.m_bEnabled)
291 if (m_mForbiddenWords.Contains(mistake))
294 string correction = entry.m_sCorrection;
295 correction.TrimInPlace();
297 correction =
string.Format(
"use \"%1\" instead", correction);
299 string comment = entry.m_sComment;
300 comment.TrimInPlace();
305 correction =
string.Format(
"%1 (%2)", correction, comment);
307 correction = comment;
310 m_mForbiddenWords.Insert(mistake, correction);
317 protected void RunCurrentFile()
320 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
321 scriptEditor.GetCurrentFile(currentFile);
322 SCR_BasicCodeFormatterPluginFileReport report = ProcessFile(currentFile,
false);
324 PrintReport(report, m_bLogFixes, m_bReportFindings);
329 protected void RunAddonFilesBatchProcess()
331 string absoluteAddonDirectory;
332 if (!SCR_AddonTool.GetAddonAbsolutePath(m_iAddon,
string.Empty, absoluteAddonDirectory,
true))
334 Print(
"Wrong addon selected: " + SCR_AddonTool.GetAddonID(m_iAddon) +
" (read-only?)",
LogLevel.ERROR);
338 string addonName = SCR_AddonTool.GetAddonID(m_iAddon);
339 string addonFileSystem = SCR_AddonTool.ToFileSystem(addonName);
340 int addonFileSystemLength = addonFileSystem.Length();
341 int addonFileSystemLengthPlus3 = addonFileSystemLength + 3;
344 array<string> relativeFilePaths = {};
345 foreach (
string scriptFile : scriptFiles)
350 int scriptFileLength = scriptFile.Length();
351 if (scriptFileLength < addonFileSystemLengthPlus3)
354 relativeFilePaths.Insert(scriptFile.Substring(addonFileSystemLength, scriptFileLength - scriptFileLength));
357 int editableScriptsCount = relativeFilePaths.Count();
358 if (editableScriptsCount < 1)
360 Print(
"No script files found in " + addonName +
" - leaving",
LogLevel.WARNING);
364 if (!Workbench.ScriptDialog(
366 "You are about to format " + editableScriptsCount +
" \"" + addonName +
"\" addon script files.\n\n" +
"Continue?",
367 new WorkbenchDialog_OKCancel())
371 array<ref SCR_BasicCodeFormatterPluginFileReport> reports = ProcessFiles(relativeFilePaths,
true);
373 if (m_iMaxLoggedReports < 1)
376 int displayedReports;
377 foreach (SCR_BasicCodeFormatterPluginFileReport report : reports)
382 if (m_bOnlyLogChanges && report.IsClean())
385 PrintReport(report, m_bLogFixes, m_bReportFindings);
388 if (m_iMaxLoggedReports > 0 && displayedReports >= m_iMaxLoggedReports)
399 protected array<ref SCR_BasicCodeFormatterPluginFileReport> ProcessFiles(array<string> relativeFilePaths,
bool useFileIO)
402 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
403 scriptEditor.GetCurrentFile(currentFile);
405 SCR_BasicCodeFormatterPluginFileReport report;
406 array<ref SCR_BasicCodeFormatterPluginFileReport> result = {};
407 foreach (
string relativeFilePath : relativeFilePaths)
409 report = ProcessFile(relativeFilePath, useFileIO && relativeFilePath != currentFile);
410 result.Insert(report);
422 protected SCR_BasicCodeFormatterPluginFileReport ProcessFile(
string relativeFilePath,
bool useFileIO)
426 Print(
"Provided relative file path is empty",
LogLevel.WARNING);
430 foreach (
string forbiddenDir : m_aForbiddenDirectories)
432 if (relativeFilePath.StartsWith(forbiddenDir))
434 PrintFormat(
"File is in excluded directory, skipping (%1) - %2", forbiddenDir, relativeFilePath, level:
LogLevel.NORMAL);
439 bool isReadOnly =
false;
440 bool demoMode = m_bDemoMode;
443 string absoluteFilePath;
444 if (!Workbench.GetAbsolutePath(relativeFilePath, absoluteFilePath,
true))
446 Print(
"Cannot find the absolute file path, switching to readonly mode - is file read-only? " + relativeFilePath,
LogLevel.WARNING);
451 SCR_BasicCodeFormatterPluginFileReport report =
new SCR_BasicCodeFormatterPluginFileReport(relativeFilePath, relativeFilePath == __FILE__);
453 bool reportFindings = !report.m_bIsPluginFile && m_bReportFindings;
454 bool doGeneralFormatting = !report.m_bIsPluginFile && m_bGeneralFormatting;
456 bool isPreviousLineEmpty;
457 bool emptyLineGroupLogged;
461 if (m_bOnlyFormatModifiedLines && !isReadOnly)
463 report.m_iDiffTime =
System.GetTickCount();
464 report.m_aDiffLines = GetFileModifiedLineNumbers(absoluteFilePath, isInRepository);
465 report.m_iDiffTime =
System.GetTickCount(report.m_iDiffTime);
467 if (report.m_aDiffLines && report.m_aDiffLines.IsEmpty())
470 doGeneralFormatting =
false;
472 report.m_aDiffLines = null;
476 array<string> pieces;
477 array<string> friendlyWords = {};
481 const int startTick =
System.GetTickCount();
483 array<string> lines = ReadFileContent(relativeFilePath, useFileIO);
484 report.m_iReadTime =
System.GetTickCount(startTick);
486 if (lines.Contains(GENERATED_SCRIPT_WARNING))
488 Print(
"Skipping generated script " + relativeFilePath,
LogLevel.NORMAL);
492 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
494 int linesCount = lines.Count();
495 report.m_iLinesTotal = linesCount;
497 bool prevFormatThisLine;
500 foreach (
int lineNumber,
string fullLine : lines)
502 int lineNumberPlus1 = lineNumber + 1;
503 bool formatThisLine = !report.m_aDiffLines || report.m_aDiffLines.Contains(lineNumberPlus1);
504 if (!formatThisLine && !reportFindings)
506 prevFormatThisLine = formatThisLine;
507 prevFullLine = fullLine;
508 prevContent = fullLine.Trim();
513 GetIndentAndLineContentAsPieces(fullLine, indentation, pieces);
514 int piecesCount = pieces.Count();
520 int endSpacesRemoved;
523 endSpacesRemoved = indentation.Length();
524 indentation =
string.Empty;
528 string endPiece = pieces[piecesCount - 1];
530 endSpacesRemoved = pieces[piecesCount - 1].Length() - endPiece.Length();
531 if (endSpacesRemoved > 0)
532 pieces.Set(piecesCount - 1, endPiece);
535 if (endSpacesRemoved > 0)
537 report.m_iEndSpacesRemovedTotal += endSpacesRemoved;
538 report.m_aTrimmings.Insert(lineNumberPlus1);
545 int spaceInTabsReplaced = indentation.Replace(
SCR_StringHelper.SPACE,
string.Empty);
547 if (fourSpacesReplaced > 0 || spaceInTabsReplaced > 0)
549 report.m_iFourSpacesReplacedTotal += fourSpacesReplaced;
550 report.m_iSpaceInTabsReplacedTotal += spaceInTabsReplaced;
551 report.m_aFixedIndentations.Insert(lineNumberPlus1);
555 if (m_bFixMethodSeparators)
557 if (piecesCount == 1 && pieces[0].StartsWith(
SCR_StringHelper.DOUBLE_SLASH +
"---") && pieces[0].EndsWith(
"---") && !
SCR_StringHelper.
Filter(pieces[0],
"/-",
true) && pieces[0] != METHOD_SEPARATOR)
559 pieces.Set(0, METHOD_SEPARATOR);
560 report.m_iMethodSeparatorFixedTotal++;
564 if (doGeneralFormatting)
565 report.m_iGeneralFormattingTotal += GeneralFormatting(indentation, pieces);
572 report.m_aBadSeparatorFound.Insert(lineNumberPlus1);
575 fullLineLC.ToLower();
577 foreach (
string friendlyWord : friendlyWords)
579 foreach (
string forbiddenWord,
string correction : m_mForbiddenWords)
583 if (report.m_mForbiddenWordFound.Contains(forbiddenWord))
584 report.m_mForbiddenWordFound.Get(forbiddenWord).Insert(lineNumberPlus1);
586 report.m_mForbiddenWordFound.Insert(forbiddenWord, { lineNumberPlus1 });
593 string findingsString = currContent.Trim();
594 bool isCurrentLineEmpty = !findingsString;
595 if (isPreviousLineEmpty)
597 if (isCurrentLineEmpty)
599 if (!emptyLineGroupLogged)
601 report.m_aDoubleEmptyLineFound.Insert(lineNumber);
602 emptyLineGroupLogged =
true;
607 emptyLineGroupLogged =
false;
612 if (isCurrentLineEmpty)
614 if (prevContent.StartsWith(
"{"))
615 report.m_aSuperfluousEmptyLineFound.Insert(lineNumberPlus1);
619 if (prevFullLine.StartsWith(
"\t\t") && prevContent.StartsWith(
"}") && !currContent.StartsWith(
"}") && !currContent.StartsWith(
"else"))
620 report.m_aMissingEmptyLineFound.Insert(lineNumberPlus1);
624 findingsString =
string.Empty;
625 array<string> splits = {};
626 foreach (
string piece : pieces)
635 findingsString += piece;
640 if (findingsString.Contains(
" = new ") && !findingsString.Contains(
"("))
641 report.m_aNewWithoutParentheseFound.Insert(lineNumberPlus1);
644 report.m_aNewArrayFound.Insert(lineNumberPlus1);
646 if (indentation.StartsWith(
"\t\t") && findingsString.StartsWith(
"ref "))
647 report.m_aUselessRefFound.Insert(lineNumberPlus1);
649 if (findingsString.Contains(
"auto "))
650 report.m_aAutoKeywordFound.Insert(lineNumberPlus1);
652 if (findingsString.Contains(
"autoptr "))
653 report.m_aAutoptrKeywordFound.Insert(lineNumberPlus1);
655 if (findingsString.StartsWith(
"for ("))
657 findingsString.Split(
";", splits,
true);
659 report.m_aForCountCall.Insert(lineNumberPlus1);
662 foreach (
string forbiddenDivision : m_aForbiddenDivisions)
664 if (findingsString.Contains(forbiddenDivision))
666 report.m_aDivideByXFound.Insert(lineNumberPlus1);
672 lineNumber < linesCount - 1
677 string nextLine = lines[lineNumberPlus1];
678 if (!nextLine.Trim().StartsWith(BRACKET_OPEN))
679 report.m_aUnscopedLoopFound.Insert(lineNumberPlus1);
683 report.m_aOneLinerFound.Insert(lineNumberPlus1);
685 if ((!isInRepository || formatThisLine) && HasBadVariableNaming(indentation, findingsString))
686 report.m_aBadVariableNamingFound.Insert(lineNumberPlus1);
689 report.m_aBadScriptInvokerFound.Insert(lineNumberPlus1);
691 if (findingsString.StartsWith(
"Print") && findingsString.EndsWith(
";"))
693 if (findingsString.StartsWith(
"Print("))
695 if (!findingsString.Contains(
"LogLevel.") && !findingsString.Contains(
"logLevel)"))
696 report.m_aWildPrintFound.Insert(lineNumberPlus1);
698 if (findingsString.Contains(
"Print(string.Format("))
699 report.m_aPrintToPrintFormatFound.Insert(lineNumberPlus1);
702 if (findingsString.StartsWith(
"PrintFormat("))
704 if (!findingsString.Contains(
"level:"))
705 report.m_aWildPrintFound.Insert(lineNumberPlus1);
709 if (findingsString.Contains(
"enums: ParamEnumArray.FromEnum("))
710 report.m_aEnumsToEnumTypeFound.Insert(lineNumberPlus1);
713 report.m_aNonPrefixedClassOrEnumFound.Insert(lineNumberPlus1);
716 isPreviousLineEmpty = isCurrentLineEmpty;
719 prevFormatThisLine = formatThisLine;
721 string finalLine = indentation + currContent;
722 prevFullLine = finalLine;
723 prevContent = currContent;
725 if (finalLine == fullLine)
728 report.m_iLinesEdited++;
735 lines[lineNumber] = finalLine;
739 if (scriptEditor.SetOpenedResource(relativeFilePath))
740 scriptEditor.SetLineText(finalLine, lineNumber);
747 if (!demoMode && m_bAddFinalLineReturn && linesCount > 0 && lines[linesCount - 1] !=
string.Empty)
750 lines.Insert(
string.Empty);
752 AddFinalLineReturnToCurrentFile();
754 report.m_bHasAddedFinalLineReturn =
true;
767 if (!demoMode && useFileIO)
770 report.m_iFormatTime =
System.GetTickCount(startTick) - report.m_iReadTime;
780 protected array<string> ReadFileContent(
string relativeFilePath,
bool useFileIO)
786 array<string> result = {};
787 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
788 scriptEditor.SetOpenedResource(relativeFilePath);
790 for (
int lineNumber, linesCount = scriptEditor.GetLinesCount(); lineNumber < linesCount; lineNumber++)
795 scriptEditor.GetLineText(line, lineNumber);
808 protected void PrintReport(notnull SCR_BasicCodeFormatterPluginFileReport report,
bool printFixes,
bool printFindings)
812 array<string> reportArray = {};
814 if (report.m_iLinesEdited > 0)
815 reportArray.Insert(
string.Format(
"%1 lines changed", report.m_iLinesEdited));
817 if (!report.m_aTrimmings.IsEmpty())
818 reportArray.Insert(report.m_aTrimmings.Count().ToString() +
" line trimmings");
820 if (!report.m_aFixedIndentations.IsEmpty())
821 reportArray.Insert(report.m_aFixedIndentations.Count().ToString() +
"× indent fixes at lines " + JoinLineNumbers(report.m_aFixedIndentations));
823 if (report.m_iGeneralFormattingTotal > 0)
824 reportArray.Insert(
string.Format(
"%1 formattings", report.m_iGeneralFormattingTotal));
826 if (report.m_iEndSpacesRemovedTotal > 0)
827 reportArray.Insert(
string.Format(
"%1 end spaces trimming", report.m_iEndSpacesRemovedTotal));
829 if (report.m_iFourSpacesReplacedTotal > 0)
830 reportArray.Insert(
string.Format(
"%1 4-spaces indent -> tabs replaced", report.m_iFourSpacesReplacedTotal));
832 if (report.m_iSpaceInTabsReplacedTotal > 0)
833 reportArray.Insert(
string.Format(
"%1 space(s) in indentation removed", report.m_iSpaceInTabsReplacedTotal));
835 if (report.m_iMethodSeparatorFixedTotal > 0)
836 reportArray.Insert(
string.Format(
"%1 method separators fixed", report.m_iMethodSeparatorFixedTotal));
838 if (report.m_bHasAddedFinalLineReturn)
839 reportArray.Insert(
"added final newline");
841 string reportLine =
"";
842 if (m_bDemoMode && !reportArray.IsEmpty())
843 reportLine =
"<span style='color: turquoise'>[DEMO]</span> ";
845 if (report.m_bIsPluginFile)
846 reportLine +=
"<span style='color: orange'>[PLUGIN FILE]</span> ";
848 reportLine +=
"<strong>" +
FilePath.StripPath(report.m_sRelativeFilePath) +
"</strong> - ";
850 if (reportArray.IsEmpty())
851 reportLine +=
"no fixes to report";
855 reportLine +=
" (read: " + report.m_iReadTime +
" ms, format: " + report.m_iFormatTime +
" ms";
857 if (report.m_iDiffTime > 0)
858 reportLine +=
", diff: " + report.m_iDiffTime +
" ms";
860 report.m_iDiffTime = 0;
862 reportLine +=
" - total: " + (report.m_iReadTime + report.m_iFormatTime + report.m_iDiffTime) +
" ms)";
867 if (report.m_aDiffLines && !report.m_aDiffLines.IsEmpty())
869 int diffLinesCount = report.m_aDiffLines.Count();
870 float percentage = diffLinesCount / report.m_iLinesTotal * 100;
871 PrintFormat(
"Checked (%1/%2) edited lines %3 (%4%%)", diffLinesCount, report.m_iLinesTotal, JoinLineNumbers(report.m_aDiffLines), percentage.ToString(lenDec: 2), level:
LogLevel.NORMAL);
875 Print(
"Checked all " + report.m_iLinesTotal +
" lines (100% of the file)",
LogLevel.NORMAL);
879 if (printFindings && !report.m_bIsPluginFile)
881 if (!report.m_aNewWithoutParentheseFound.IsEmpty())
882 PrintFinding(
"new instance(s) without ()", report.m_aNewWithoutParentheseFound,
"always use parentheses when instanciating a class");
884 if (!report.m_aUselessRefFound.IsEmpty())
885 PrintFinding(
"ref something", report.m_aUselessRefFound,
"ref is not needed in script scope, only on class instance declaration");
887 if (!report.m_aNewArrayFound.IsEmpty())
888 PrintFinding(
"'new array<>'", report.m_aNewArrayFound,
"replace by {} whenever possible");
890 if (!report.m_aBadSeparatorFound.IsEmpty())
891 PrintFinding(
"bad separator(s) detected", report.m_aBadSeparatorFound,
"use separators only for methods, not for classes or anything else - keep the minimum amount of classes per file");
893 if (!report.m_aDoubleEmptyLineFound.IsEmpty())
894 PrintFinding(
"multiple consecutive empty lines", report.m_aDoubleEmptyLineFound,
"leave only one");
896 if (!report.m_aSuperfluousEmptyLineFound.IsEmpty())
897 PrintFinding(
"superfluous empty line(s)", report.m_aSuperfluousEmptyLineFound,
"an empty line is not welcome after the beginning of a scope");
899 if (!report.m_aMissingEmptyLineFound.IsEmpty())
900 PrintFinding(
"missing empty line(s)", report.m_aMissingEmptyLineFound,
"have an empty line between the end of a scope (or an unscoped if/if-else) and code after that");
902 if (!report.m_aAutoKeywordFound.IsEmpty())
903 PrintFinding(
"'auto' keyword", report.m_aAutoKeywordFound,
"use the direct type instead");
905 if (!report.m_aAutoptrKeywordFound.IsEmpty())
906 PrintFinding(
"'autoptr' keyword", report.m_aAutoptrKeywordFound,
"remove if used on a standard variable, or replace with 'ref' if used for a member variable array");
908 if (!report.m_aForCountCall.IsEmpty())
909 PrintFinding(
"for-loop method call", report.m_aForCountCall,
"a method is called every iteration; is it wanted? (usually arr.Count())");
911 if (!report.m_aDivideByXFound.IsEmpty())
912 PrintFinding(
"potentially avoidable division", report.m_aDivideByXFound,
"use ' * 0.5' instead of ' / 2', ' * 0.1' instead of ' / 10' etc whenever possible");
914 if (!report.m_aUnscopedLoopFound.IsEmpty())
915 PrintFinding(
"loop without brackets", report.m_aUnscopedLoopFound,
"always use brackets {} with for/foreach/while loops");
917 if (!report.m_aOneLinerFound.IsEmpty())
918 PrintFinding(
"one-liner", report.m_aOneLinerFound,
"use a line return after an if/for/foreach/while condition");
920 if (!report.m_aBadVariableNamingFound.IsEmpty())
921 PrintFinding(
"badly-named variables", report.m_aBadVariableNamingFound,
"use proper prefixes: m_s for ResourceName/string, m_v for vectors, NO m_p, CASED_CONSTS, etc");
923 if (!report.m_aBadScriptInvokerFound.IsEmpty())
924 PrintFinding(
"raw ScriptInvoker", report.m_aBadScriptInvokerFound,
"use typed ScriptInvokerBase<> - see SCR_ScriptInvokerHelper.c for examples");
926 if (!report.m_aWildPrintFound.IsEmpty())
927 PrintFinding(
"wild Print()", report.m_aWildPrintFound,
"use Print with LogLevel.XXX (or PrintFormat with level: LogLevel.XXX) to show this is not a temporary debug print");
929 if (!report.m_aPrintToPrintFormatFound.IsEmpty())
930 PrintFinding(
"string.Format Print", report.m_aPrintToPrintFormatFound,
"Print(string.Format()) can be converted to PrintFormat()");
932 if (!report.m_aEnumsToEnumTypeFound.IsEmpty())
933 PrintFinding(
"enums using ParamEnumArray.FromEnum", report.m_aEnumsToEnumTypeFound,
"\"enums:\" can be converted to \"enumType: EnumType\"");
935 if (!report.m_aNonPrefixedClassOrEnumFound.IsEmpty())
937 array<string> prefixes;
938 if (m_aAcceptedScriptPrefixes.IsEmpty())
939 prefixes = FORCED_PREFIXES;
941 prefixes = m_aAcceptedScriptPrefixes;
943 PrintFinding(
"non-prefixed class/enum", report.m_aNonPrefixedClassOrEnumFound,
"classes and enums should be prefixed; see the settings to setup accepted prefixes (currently \"" +
SCR_StringHelper.
Join(
"\", \"", prefixes) +
"\")");
946 if (!report.m_mForbiddenWordFound.IsEmpty())
948 const string description =
"flagged words";
949 if (m_bShowSpellCheckFindingsDetails)
952 array<string> mapKeys = {};
953 foreach (
string key, array<int> lineNumbers : report.m_mForbiddenWordFound)
956 count += lineNumbers.Count();
960 "<span style='color: #DAD; font-weight: bold'>%1×</span> %2 found; see Options > Spell Check Config:",
966 array<int> lineNumbers;
967 foreach (
string mapKey : mapKeys)
969 string tip =
string.Format(
"\"%1\" is not an accepted word", mapKey);
971 if (m_mForbiddenWords.Find(mapKey, correction))
973 correction.TrimInPlace();
975 tip +=
"; " + correction;
982 lineNumbers = report.m_mForbiddenWordFound.Get(mapKey);
983 int lineNumbersCount = lineNumbers.Count();
984 for (
int i = lineNumbersCount - 1; i >= 0; i--)
986 if (lineNumbers.Find(lineNumbers[i]) != i)
987 lineNumbers.RemoveOrdered(i);
991 "- <span style='color: #DAD; font-weight: bold'>%1×</span> %2 found at line(s) <span style='color: #FDA'>%3</span>%4",
993 string.Format(
"\"%1\"", mapKey),
994 JoinLineNumbers(lineNumbers),
1001 array<string> mapKeys = {};
1002 array<int> finalLineNumbers = {};
1003 foreach (
string mapKey, array<int> lineNumbers : report.m_mForbiddenWordFound)
1005 mapKeys.Insert(mapKey);
1006 finalLineNumbers.InsertAll(lineNumbers);
1010 SCR_ArrayHelperT<int>.RemoveDuplicates(finalLineNumbers);
1012 PrintFinding(
string.Format(
"%1 lines (%2 variations)", description, mapKeys.Count()), finalLineNumbers,
string.Format(
"see Options > Spell Check Config (%1)",
SCR_StringHelper.
Join(
", ", mapKeys)));
1023 protected int GeneralFormatting(
string indentation, inout notnull array<string> pieces)
1025 int piecesCount = pieces.Count();
1026 if (piecesCount < 1)
1030 if (!indentation && pieces[0].StartsWith(BRACKET_CLOSE +
";"))
1040 array<ref array<string>> format;
1046 int startPieceIndex = -1;
1048 foreach (
int pieceIndex,
string piece : pieces)
1053 startPieceIndex = pieceIndex;
1060 format = m_aGeneralFormatting_Start;
1061 for (
int i, cnt = format.Count(); i < cnt; i++)
1063 toReplace = format[i][0];
1064 replaceWith = format[i][1];
1067 if (replaceWith.Contains(toReplace))
1069 PrintFormat(
"%1:%2 - safety exit! %3/%4",
FilePath.StripPath(__FILE__), __LINE__, toReplace, replaceWith, level:
LogLevel.WARNING);
1073 while (startPiece.StartsWith(toReplace))
1081 pieces.Set(startPieceIndex, startPiece);
1088 (startPiece.StartsWith(
"class ") || startPiece.StartsWith(
"enum ") || startPiece.StartsWith(
"foreach (")) &&
1089 startPiece.IndexOf(
":") > -1
1093 int colonIndex = startPiece.IndexOf(
":");
1100 colonIndex = startPiece.IndexOf(
":");
1101 if (colonIndex < startPiece.Length() -1 && startPiece[colonIndex + 1] !=
SCR_StringHelper.SPACE)
1109 pieces.Set(startPieceIndex, startPiece);
1116 for (
int pieceIndex; pieceIndex < piecesCount; pieceIndex++)
1118 string piece = pieces[pieceIndex];
1123 format = m_aGeneralFormatting_Middle;
1124 for (
int i, cnt = format.Count(); i < cnt; i++)
1126 toReplace = format[i][0];
1127 replaceWith = format[i][1];
1130 if (replaceWith.Contains(toReplace))
1132 PrintFormat(
"%1:%2 - safety exit! %3/%4",
FilePath.StripPath(__FILE__), __LINE__, toReplace, replaceWith, level:
LogLevel.WARNING);
1136 while (piece.Contains(toReplace))
1138 piece.Replace(toReplace, replaceWith);
1144 pieces.Set(pieceIndex, piece);
1151 int endPieceIndex = -1;
1153 for (
int pieceIndex = piecesCount - 1; pieceIndex >= 0; pieceIndex--)
1157 endPiece = pieces[pieceIndex];
1158 endPieceIndex = pieceIndex;
1165 format = m_aGeneralFormatting_End;
1166 for (
int i, cnt = format.Count(); i < cnt; i++)
1168 toReplace = format[i][0];
1169 replaceWith = format[i][1];
1172 if (replaceWith.Contains(toReplace))
1174 PrintFormat(
"%1:%2 - safety exit! %3/%4",
FilePath.StripPath(__FILE__), __LINE__, toReplace, replaceWith, level:
LogLevel.WARNING);
1178 while (endPiece.EndsWith(toReplace))
1180 endPiece = endPiece.Substring(0, endPiece.Length() - toReplace.Length()) + replaceWith;
1187 if (startPiece.StartsWith(
"["))
1189 if (endPiece.Trim().EndsWith(
")];"))
1200 pieces.Set(endPieceIndex, endPiece);
1208 for (
int pieceIndex; pieceIndex < piecesCount; pieceIndex++)
1210 string piece = pieces[pieceIndex];
1214 for (
int i, length = piece.Length(); i < length; i++)
1217 if (i == length - 1)
1222 prevChar = piece[i - 1];
1224 string character = piece[i];
1228 nextChar = piece[i + 1];
1267 pieces.Set(pieceIndex, piece);
1270 return replacements;
1327 protected bool AddFinalLineReturnToCurrentFile()
1329 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
1330 int lastLineNumber = scriptEditor.GetLinesCount() - 1;
1332 scriptEditor.GetLineText(fullLine, lastLineNumber);
1340 scriptEditor.InsertLine(
string.Empty, lastLineNumber);
1341 scriptEditor.SetLineText(fullLine, lastLineNumber);
1342 scriptEditor.SetLineText(
string.Empty, lastLineNumber + 1);
1351 static void GetIndentAndLineContent(
string fullLine, out
string indentation, out
string content)
1353 int lineLength = fullLine.Length();
1356 indentation =
string.Empty;
1361 int firstCharIndex = -1;
1362 for (
int i; i < lineLength; i++)
1364 string character = fullLine[i];
1372 if (firstCharIndex < 0)
1374 indentation = fullLine;
1379 if (firstCharIndex == 0)
1381 indentation =
string.Empty;
1386 indentation = fullLine.Substring(0, firstCharIndex);
1387 content = fullLine.Substring(firstCharIndex, lineLength - firstCharIndex);
1395 protected static void GetIndentAndLineContentAsPieces(
string fullLine, out
string indentation, out array<string> pieces)
1400 GetIndentAndLineContent(fullLine, indentation,
content);
1405 bool isInCommentBlock;
1407 string currentContent;
1408 for (
int i, contentLength =
content.Length(); i < contentLength; i++)
1410 string previousChar;
1412 previousChar =
content[i - 1];
1414 string currentChar =
content[i];
1416 if (i < contentLength - 1)
1428 pieces.Insert(currentContent + currentChar);
1429 currentContent =
string.Empty;
1436 pieces.Insert(currentContent);
1437 currentContent = currentChar;
1448 if (isInCommentBlock)
1450 if (previousChar ==
"*")
1452 pieces.Insert(currentContent + currentChar);
1453 currentContent =
string.Empty;
1454 isInCommentBlock =
false;
1460 if (nextChar ==
"*")
1462 pieces.Insert(currentContent);
1463 currentContent = currentChar;
1464 isInCommentBlock =
true;
1471 pieces.Insert(currentContent);
1473 pieces.Insert(
content.Substring(i, contentLength - i));
1479 currentContent += currentChar;
1481 if (i == contentLength - 1 && currentContent)
1482 pieces.Insert(currentContent);
1490 protected bool HasBadVariableNaming(
string indentation,
string findingsString)
1496 if (findingsString.StartsWith(
"[")
1497 || findingsString.StartsWith(
"#")
1498 || findingsString.EndsWith(
")")
1504 array<string> pieces = {};
1506 int piecesCount = pieces.Count();
1507 if (piecesCount < 2)
1510 if (pieces[1] ==
"=")
1513 if (pieces.Contains(
"override")
1514 || pieces.Contains(
"void")
1515 || pieces.Contains(
"event")
1516 || pieces.Contains(
"proto")
1517 || pieces.Contains(
"external")
1519 || pieces.Contains(
"return"))
1522 bool isProtected = pieces.RemoveItemOrdered(
"protected");
1526 bool isPrivate = pieces.RemoveItemOrdered(
"private");
1530 bool isStatic = pieces.RemoveItemOrdered(
"static");
1534 bool isConst = pieces.RemoveItemOrdered(
"const");
1538 bool isRef = pieces.RemoveItemOrdered(
"ref");
1543 for (
int i; i < piecesCount; i++)
1546 pieces.RemoveOrdered(0);
1559 varName = rest.Trim();
1563 varName = rest.Substring(0,
index).Trim();
1564 rest = rest.Substring(
index, rest.Length() -
index).Trim();
1569 index = varName.IndexOf(
"[");
1570 if (
index > 0 && varName.IndexOfFrom(
index,
"]") > 1)
1573 varName = varName.Substring(0,
index);
1584 if (varName.Length() < 3)
1587 string expectedPrefix;
1589 expectedPrefix = STATIC_PREFIX;
1591 expectedPrefix = MEMBER_PREFIX;
1593 if (!varName.StartsWith(expectedPrefix))
1599 if (m_mVariableTypePrefixes.Contains(
type))
1601 expectedPrefix += m_mVariableTypePrefixes.Get(
type);
1602 return !varName.StartsWith(expectedPrefix);
1605 foreach (
string key,
string value : m_mVariableTypePrefixesStart)
1607 if (
type.StartsWith(key))
1609 expectedPrefix += value;
1610 return !varName.StartsWith(expectedPrefix);
1614 foreach (
string key,
string value : m_mVariableTypePrefixesEnd)
1616 if (
type.EndsWith(key))
1618 expectedPrefix += value;
1619 return !varName.StartsWith(expectedPrefix);
1623 string hungarianChar = varName[2];
1626 if (hungarianChar ==
"e")
1628 typename typeTypename =
type.ToType();
1632 for (
int i; i < 8; ++i)
1634 if (
typename.EnumToString(typeTypename, i) !=
"unknown")
1663 protected static string JoinLineNumbers(notnull array<int> lineNumbers,
int maxNumbers = LINE_NUMBER_LIMIT)
1665 if (lineNumbers.IsEmpty())
1666 return string.Empty;
1668 int count = lineNumbers.Count();
1670 return lineNumbers[0].ToString();
1673 bool wasSequel, isSequel;
1674 array<string> groups = {};
1676 foreach (
int i,
int currValue : lineNumbers)
1678 wasSequel = isSequel;
1679 isSequel = i > 0 && currValue == lineNumbers[i - 1] + 1;
1683 groups[countG - 1] =
string.Format(LINE_NUMBER_RANGE, groups[countG - 1], currValue);
1690 groups[countG - 1] =
string.Format(LINE_NUMBER_RANGE, groups[countG - 1], lineNumbers[i - 1]);
1692 groups.Insert(currValue.ToString());
1695 if (maxNumbers > 0 && countG >= maxNumbers)
1697 hitLimit = i < count - 1;
1703 string result = groups[0];
1704 for (
int i = 1; i < countG - 1; i++)
1706 result +=
", " + groups[i];
1710 return result +
", " + groups[countG - 1] +
", ...";
1713 result +=
" & " + groups[countG - 1];
1728 protected void PrintFinding(
string description, notnull array<int> lineNumbers,
string tip =
string.Empty)
1730 description.TrimInPlace();
1731 if (lineNumbers.IsEmpty())
1742 "<span style='color: #DAD; font-weight: bold'>%1×</span> %2 found at line(s) <span style='color: #FDA'>%3</span>%4",
1743 lineNumbers.Count(),
1745 JoinLineNumbers(lineNumbers),
1757 protected array<int> GetFileModifiedLineNumbers(
string absoluteFilePath, out
bool isInRepository)
1759 isInRepository =
false;
1761 if (!
FileIO.FileExists(absoluteFilePath))
1763 Print(
"Absolute file does not exist, skipping diff for \"" + absoluteFilePath +
"\"",
LogLevel.ERROR);
1767 string absoluteFileDirectory =
FilePath.StripFileName(absoluteFilePath);
1771 string absoluteCmdOutputFilePath = absoluteFileDirectory + DIFF_FILENAME;
1772 string commandLine =
string.Format(m_sDiffCommand, absoluteFilePath, absoluteCmdOutputFilePath);
1774 int errorCode = Workbench.RunCmd(commandLine,
true);
1777 Print(
"Failed to obtain diff - the file may not be VCS-added yet or the command is wrong (error code " + errorCode +
")",
LogLevel.ERROR);
1780 if (
FileIO.FileExists(absoluteCmdOutputFilePath))
1782 if (!
FileIO.DeleteFile(absoluteCmdOutputFilePath))
1783 Print(
"Temp diff file could NOT be deleted",
LogLevel.WARNING);
1789 if (!
FileIO.FileExists(absoluteCmdOutputFilePath))
1795 isInRepository =
true;
1805 while (!fileHandle.IsEOF())
1808 fileHandle.ReadLine(line);
1809 if (line.StartsWith(
"@@ -"))
1812 int plusIndex = line.IndexOf(
"+") + 1;
1813 int commaIndex = line.IndexOfFrom(plusIndex,
",");
1814 string diffLineNumber = line.Substring(plusIndex, commaIndex - plusIndex);
1815 lineNumber = diffLineNumber.ToInt();
1822 if (line.StartsWith(
"-"))
1825 if (line.StartsWith(
"+"))
1826 result.Insert(lineNumber);
1838 if (!
FileIO.DeleteFile(absoluteCmdOutputFilePath))
1839 Print(
"Cannot delete the temp diff file - " + absoluteCmdOutputFilePath,
LogLevel.WARNING);
1847 if (!m_SpellCheckConfig)
1848 m_SpellCheckConfig = SCR_ConfigHelperT<SCR_BasicCodeFormatterSpellCheckConfig>.GetConfigObject(SPELLCHECK_CONFIG);
1850 Workbench.ScriptDialog(
"Configure 'Basic Code Formatter' plugin",
"Formats code, basically.",
this);
1869 protected void SCR_BasicCodeFormatterPlugin()
1872 m_aGeneralFormatting_Start = {};
1873 m_aGeneralFormatting_Start.Insert({
"if(",
"if (" });
1874 m_aGeneralFormatting_Start.Insert({
"else if(",
"else if (" });
1875 m_aGeneralFormatting_Start.Insert({
"for(",
"for (" });
1876 m_aGeneralFormatting_Start.Insert({
"foreach(",
"foreach (" });
1877 m_aGeneralFormatting_Start.Insert({
"while(",
"while (" });
1878 m_aGeneralFormatting_Start.Insert({
"switch(",
"switch (" });
1881 m_aGeneralFormatting_Middle = {};
1883 m_aGeneralFormatting_Middle.Insert({
";;",
";" });
1886 m_aGeneralFormatting_Middle.Insert({
" ,",
"," });
1887 m_aGeneralFormatting_Middle.Insert({
" ;",
";" });
1888 m_aGeneralFormatting_Middle.Insert({
" NULL;",
" null;" });
1889 m_aGeneralFormatting_Middle.Insert({
" NULL,",
" null," });
1890 m_aGeneralFormatting_Middle.Insert({
" NULL)",
" null)" });
1891 m_aGeneralFormatting_Middle.Insert({
"{ }",
"{}" });
1892 m_aGeneralFormatting_Middle.Insert({
"array <",
"array<" });
1893 foreach (
string nativeType : NATIVE_TYPES)
1895 m_aGeneralFormatting_Middle.Insert({
"<ref " + nativeType +
">",
"<" + nativeType +
">" });
1896 m_aGeneralFormatting_Middle.Insert({
"<ref " + nativeType +
",",
"<" + nativeType +
"," });
1897 m_aGeneralFormatting_Middle.Insert({
", ref " + nativeType +
">",
", " + nativeType +
">" });
1898 m_aGeneralFormatting_Middle.Insert({
", ref " + nativeType +
",",
", " + nativeType +
"," });
1901 m_aGeneralFormatting_Middle.Insert({
"( ",
"(" });
1902 m_aGeneralFormatting_Middle.Insert({
" )",
")" });
1905 m_aGeneralFormatting_End = {};
1907 m_aGeneralFormatting_End.Insert({
", )]",
")]" });
1908 m_aGeneralFormatting_End.Insert({
",)]",
")]" });
1912 m_aForbiddenDivisions = {};
1913 array<int> forbiddenDivisors = { 2, 4, 5, 8, 10, 20, 50, 100, 1000, 10000, 100000, 1000000 };
1914 foreach (
int forbiddenDivisor : forbiddenDivisors)
1916 m_aForbiddenDivisions.Insert(
" / " + forbiddenDivisor +
";");
1917 m_aForbiddenDivisions.Insert(
" / " + forbiddenDivisor +
")");
1918 m_aForbiddenDivisions.Insert(
" / " + forbiddenDivisor +
SCR_StringHelper.SPACE);
1921 m_aPrefixLineChecks = {
"class ",
"enum " };
1923 m_aForForEachWhileArray = {
"for ",
"foreach ",
"while " };
1924 m_aIfForForEachWhileArray = {
"if ",
"for ",
"foreach ",
"while " };
1925 m_aNewArrayNewRefArray = {
"new array<",
"new ref array<" };
1926 m_aScriptInvokerArray = {
"ScriptInvoker()",
"ScriptInvoker<",
"ScriptInvoker\t",
"ScriptInvoker " };
1927 m_aEndBracketSemicolonArray = { BRACKET_CLOSE,
";" };
1930 m_mVariableTypePrefixes.Insert(
"bool",
"b");
1931 m_mVariableTypePrefixes.Insert(
"float",
"f");
1932 m_mVariableTypePrefixes.Insert(
"int",
"i");
1933 m_mVariableTypePrefixes.Insert(
"string",
"s");
1934 m_mVariableTypePrefixes.Insert(
"ResourceName",
"s");
1935 m_mVariableTypePrefixes.Insert(
"LocalizedString",
"s");
1936 m_mVariableTypePrefixes.Insert(
"vector",
"v");
1939 m_mVariableTypePrefixesStart.Insert(
"array<",
"a");
1940 m_mVariableTypePrefixesStart.Insert(
"map<",
"m");
1945 m_mVariableTypePrefixesStart.Insert(
"E" +
SCR_StringHelper.UPPERCASE[i],
"e");
1946 m_mVariableTypePrefixesStart.Insert(
"SCR_E" +
SCR_StringHelper.UPPERCASE[i],
"e");
1950 m_mVariableTypePrefixesEnd.Insert(
"Widget",
"w");
1955class SCR_BasicCodeFormatterPluginFileReport
1957 string m_sRelativeFilePath;
1958 bool m_bIsPluginFile;
1960 int m_iReadTime = -1;
1961 int m_iFormatTime = -1;
1962 int m_iDiffTime = -1;
1964 int m_iEndSpacesRemovedTotal;
1965 int m_iSpaceInTabsReplacedTotal;
1966 int m_iFourSpacesReplacedTotal;
1967 int m_iMethodSeparatorFixedTotal;
1968 int m_iGeneralFormattingTotal;
1974 ref array<int> m_aDiffLines;
1975 ref array<int> m_aTrimmings = {};
1976 ref array<int> m_aFixedIndentations = {};
1977 bool m_bHasAddedFinalLineReturn;
1980 ref array<int> m_aBadSeparatorFound = {};
1981 ref array<int> m_aDoubleEmptyLineFound = {};
1982 ref array<int> m_aSuperfluousEmptyLineFound = {};
1983 ref array<int> m_aMissingEmptyLineFound = {};
1984 ref array<int> m_aNewWithoutParentheseFound = {};
1985 ref array<int> m_aUselessRefFound = {};
1986 ref array<int> m_aNewArrayFound = {};
1987 ref array<int> m_aAutoKeywordFound = {};
1988 ref array<int> m_aAutoptrKeywordFound = {};
1989 ref array<int> m_aForCountCall = {};
1990 ref array<int> m_aDivideByXFound = {};
1991 ref array<int> m_aUnscopedLoopFound = {};
1992 ref array<int> m_aOneLinerFound = {};
1993 ref array<int> m_aBadVariableNamingFound = {};
1994 ref array<int> m_aBadScriptInvokerFound = {};
1995 ref array<int> m_aWildPrintFound = {};
1996 ref array<int> m_aPrintToPrintFormatFound = {};
1997 ref array<int> m_aEnumsToEnumTypeFound = {};
1998 ref array<int> m_aNonPrefixedClassOrEnumFound = {};
1999 ref map<string, ref array<int>> m_mForbiddenWordFound =
new map<string, ref array<int>>();
2006 if (m_iLinesEdited != 0)
2009 bool areAllElementsEmpty =
2010 m_aBadSeparatorFound.IsEmpty() &&
2011 m_aDoubleEmptyLineFound.IsEmpty() &&
2012 m_aSuperfluousEmptyLineFound.IsEmpty() &&
2013 m_aMissingEmptyLineFound.IsEmpty() &&
2014 m_aNewWithoutParentheseFound.IsEmpty() &&
2015 m_aUselessRefFound.IsEmpty() &&
2016 m_aNewArrayFound.IsEmpty() &&
2017 m_aAutoKeywordFound.IsEmpty() &&
2018 m_aAutoptrKeywordFound.IsEmpty() &&
2019 m_aForCountCall.IsEmpty() &&
2020 m_aDivideByXFound.IsEmpty() &&
2021 m_aUnscopedLoopFound.IsEmpty() &&
2022 m_aOneLinerFound.IsEmpty() &&
2023 m_aBadVariableNamingFound.IsEmpty() &&
2024 m_aBadScriptInvokerFound.IsEmpty() &&
2025 m_aWildPrintFound.IsEmpty();
2027 if (!areAllElementsEmpty)
2030 areAllElementsEmpty =
2031 m_aPrintToPrintFormatFound.IsEmpty() &&
2032 m_aEnumsToEnumTypeFound.IsEmpty() &&
2033 m_aNonPrefixedClassOrEnumFound.IsEmpty() &&
2034 m_mForbiddenWordFound.IsEmpty();
2036 return areAllElementsEmpty;
2041 void SCR_BasicCodeFormatterPluginFileReport(
string relativeFilePath,
bool isPluginFile)
2043 m_sRelativeFilePath = relativeFilePath;
2044 m_bIsPluginFile = isPluginFile;
2053 name:
"Basic Code Formatter - forced",
2054 description:
"Forces Code Formatting checking ALL lines only for the current file",
2055 shortcut:
"Ctrl+Alt+Shift+K",
2056 wbModules: {
"ScriptEditor" },
2057 awesomeFontCode: 0xF036)]
2058class SCR_BasicCodeFormatterForcedPlugin : WorkbenchPlugin
2061 protected override void Run()
2063 ScriptEditor scriptEditor = Workbench.GetModule(ScriptEditor);
2067 SCR_BasicCodeFormatterPlugin formatterPlugin = SCR_BasicCodeFormatterPlugin.Cast(scriptEditor.GetPlugin(SCR_BasicCodeFormatterPlugin));
2068 if (!formatterPlugin)
2070 Print(
"Failed to obtain Basic Code Formatter Plugin",
LogLevel.ERROR);
2074 formatterPlugin.RunForced();
class RestAPIHelper< JsonApiStruct T > content
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
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 ParamEnumArray FromAddons(int titleFormat=2, int hideCoreModules=0)
static string FormatValueNameToUserFriendly(string valueName)
static string Filter(string input, string characters, bool useCharactersAsBlacklist=false)
static bool ContainsLowercase(string input)
static bool EndsWithAny(string input, notnull array< string > lineEnds)
static bool ContainsUppercase(string input)
static int CountOccurrences(string haystack, string needle, bool caseInsensitive=false)
static bool CheckCharacters(string input, bool allowLC, bool allowUC, bool allowDigits, bool allowUnderscore=false)
static int IndexOf(string input, notnull array< string > samples)
static bool StartsWithAny(string input, notnull array< string > lineStarts)
static bool ContainsAny(string input, notnull array< string > needles)
static string ReplaceTimes(string input, string sample, string replacement, int howMany=1, int skip=0)
static bool SimpleStarSearchMatches(string haystack, string needle, bool caseSensitive, bool strictMatch)
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)
static array< string > SearchWorkbenchFiles(array< string > fileExtensions=null, array< string > searchStrArray=null, string rootPath="", bool recursive=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.
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
FileMode
Mode for opening file. See FileSystem::Open.
proto bool Contains(T value)