/* Function: AddCommentType * Adds a comment type to the file. */ public void AddCommentType(TextFileCommentType commentType) { if (commentTypes == null) { commentTypes = new List <TextFileCommentType>(); } commentTypes.Add(commentType); }
/* Function: MergeCommentTypeInto * Merges the settings of a <ConfigFiles.TextFileCommentType> into another one, overriding the settings of the first. This * does NOT cover keywords. The base object will be altered. */ protected void MergeCommentTypeInto(ref ConfigFiles.TextFileCommentType baseCommentType, ConfigFiles.TextFileCommentType overridingCommentType) { if (overridingCommentType.HasDisplayName) { baseCommentType.SetDisplayName(overridingCommentType.DisplayName, overridingCommentType.DisplayNamePropertyLocation); baseCommentType.SetDisplayNameFromLocale(null, default); } if (overridingCommentType.HasDisplayNameFromLocale) { baseCommentType.SetDisplayNameFromLocale(overridingCommentType.DisplayNameFromLocale, overridingCommentType.DisplayNameFromLocalePropertyLocation); baseCommentType.SetDisplayName(null, default); } if (overridingCommentType.HasPluralDisplayName) { baseCommentType.SetPluralDisplayName(overridingCommentType.PluralDisplayName, overridingCommentType.PluralDisplayNamePropertyLocation); baseCommentType.SetPluralDisplayNameFromLocale(null, default); } if (overridingCommentType.HasPluralDisplayNameFromLocale) { baseCommentType.SetPluralDisplayNameFromLocale(overridingCommentType.PluralDisplayNameFromLocale, overridingCommentType.PluralDisplayNameFromLocalePropertyLocation); baseCommentType.SetPluralDisplayName(null, default); } if (overridingCommentType.HasSimpleIdentifier) { baseCommentType.SetSimpleIdentifier(overridingCommentType.SimpleIdentifier, overridingCommentType.SimpleIdentifierPropertyLocation); } if (overridingCommentType.HasScope) { baseCommentType.SetScope(overridingCommentType.Scope, overridingCommentType.ScopePropertyLocation); } // Ignore keywods if (overridingCommentType.HasFlags) { baseCommentType.SetFlags(overridingCommentType.Flags, overridingCommentType.FlagsPropertyLocation); } }
/* Function: Duplicate * Creates an independent copy of the object and all its attributes. */ public TextFileCommentType Duplicate() { TextFileCommentType copy = new TextFileCommentType(name, namePropertyLocation, alterType); copy.name = name; copy.namePropertyLocation = namePropertyLocation; copy.alterType = alterType; copy.displayName = displayName; copy.displayNamePropertyLocation = displayNamePropertyLocation; copy.displayNameFromLocale = displayNameFromLocale; copy.displayNameFromLocalePropertyLocation = displayNameFromLocalePropertyLocation; copy.pluralDisplayName = pluralDisplayName; copy.pluralDisplayNamePropertyLocation = pluralDisplayNamePropertyLocation; copy.pluralDisplayNameFromLocale = pluralDisplayNameFromLocale; copy.pluralDisplayNameFromLocalePropertyLocation = pluralDisplayNameFromLocalePropertyLocation; copy.simpleIdentifier = simpleIdentifier; copy.simpleIdentifierPropertyLocation = simpleIdentifierPropertyLocation; copy.scope = scope; copy.scopePropertyLocation = scopePropertyLocation; if (keywordGroups != null) { copy.keywordGroups = new List <TextFileKeywordGroup>(keywordGroups.Count); foreach (var keywordGroup in keywordGroups) { copy.keywordGroups.Add(keywordGroup.Duplicate()); } } copy.flags = flags; copy.flagsPropertyLocation = flagsPropertyLocation; return(copy); }
/* Function: FinalizeCommentType * Converts a <ConfigFiles.TextFileCommentType> into a <CommentType>. This does NOT cover keywords. Also, * <CommentType.SimpleIdentifier> may still be null if one wasn't defined and it cannot be generated automatically. */ protected CommentType FinalizeCommentType(ConfigFiles.TextFileCommentType textCommentType) { CommentType final = new CommentType(textCommentType.Name); if (textCommentType.HasDisplayNameFromLocale) { final.DisplayName = Locale.Get("NaturalDocs.Engine", textCommentType.DisplayNameFromLocale); } else if (textCommentType.HasDisplayName) { final.DisplayName = textCommentType.DisplayName; } else { final.DisplayName = textCommentType.Name; } if (textCommentType.HasPluralDisplayNameFromLocale) { final.PluralDisplayName = Locale.Get("NaturalDocs.Engine", textCommentType.PluralDisplayNameFromLocale); } else if (textCommentType.HasPluralDisplayName) { final.PluralDisplayName = textCommentType.PluralDisplayName; } else { final.PluralDisplayName = final.DisplayName; } if (textCommentType.HasSimpleIdentifier) { final.SimpleIdentifier = textCommentType.SimpleIdentifier; } else { // This may end up as an empty string if there's no A-Z characters, such as if the name is in Japanese. In this case // we want it to be "CommentTypeID[number]" but the number isn't determind yet, so leave it as null for now. string simpleIdentifier = final.Name.OnlyAToZ(); if (!string.IsNullOrEmpty(simpleIdentifier)) { final.SimpleIdentifier = simpleIdentifier; } } if (textCommentType.HasScope) { final.Scope = (CommentType.ScopeValue)textCommentType.Scope; } else { final.Scope = CommentType.ScopeValue.Normal; } if (textCommentType.HasFlags) { final.Flags = AddImpliedFlags((CommentType.FlagValue)textCommentType.Flags); } else { final.Flags = CommentType.FlagValue.Code; } return(final); }
/* Function: ValidateCommentType * Validates all the settings in a <ConfigFiles.TextFileCommentType>. Returns whether it is valid, and adds any errors it finds * to errorList. */ protected bool ValidateCommentType(ConfigFiles.TextFileCommentType commentType, Errors.ErrorList errorList) { int startingErrorCount = errorList.Count; // Validate names if (commentType.DisplayNamePropertyLocation.IsDefined && commentType.DisplayNameFromLocalePropertyLocation.IsDefined) { // Put them in the proper order so the error appears on the second one string first, second; PropertyLocation secondPropertyLocation; if (commentType.DisplayNamePropertyLocation.LineNumber < commentType.DisplayNameFromLocalePropertyLocation.LineNumber) { first = "Display Name"; second = "Display Name From Locale"; secondPropertyLocation = commentType.DisplayNameFromLocalePropertyLocation; } else { first = "Display Name From Locale"; second = "Display Name"; secondPropertyLocation = commentType.DisplayNamePropertyLocation; } errorList.Add(Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", second, first), secondPropertyLocation); } if (commentType.PluralDisplayNamePropertyLocation.IsDefined && commentType.PluralDisplayNameFromLocalePropertyLocation.IsDefined) { string first, second; PropertyLocation secondPropertyLocation; if (commentType.PluralDisplayNamePropertyLocation.LineNumber < commentType.PluralDisplayNameFromLocalePropertyLocation.LineNumber) { first = "Plural Display Name"; second = "Plural Display Name From Locale"; secondPropertyLocation = commentType.PluralDisplayNameFromLocalePropertyLocation; } else { first = "Plural Display Name From Locale"; second = "Plural Display Name"; secondPropertyLocation = commentType.PluralDisplayNamePropertyLocation; } errorList.Add(Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", second, first), secondPropertyLocation); } // Validate flags if (commentType.Flags != null) { var flags = (CommentType.FlagValue)commentType.Flags; bool codeFlag = ((flags & CommentType.FlagValue.Code) != 0); bool fileFlag = ((flags & CommentType.FlagValue.File) != 0); bool documentationFlag = ((flags & CommentType.FlagValue.Documentation) != 0); bool variableTypeFlag = ((flags & CommentType.FlagValue.VariableType) != 0); bool classHierarchyFlag = ((flags & CommentType.FlagValue.ClassHierarchy) != 0); bool databaseHierarchyFlag = ((flags & CommentType.FlagValue.DatabaseHierarchy) != 0); bool enumFlag = ((flags & CommentType.FlagValue.Enum) != 0); // Check that only one of Code, File, and Documentation are defined if (codeFlag) { if (fileFlag && documentationFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b,c)", "Code", "File", "Documentation"), commentType.FlagsPropertyLocation); } else if (fileFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Code", "File"), commentType.FlagsPropertyLocation); } else if (documentationFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Code", "Documentation"), commentType.FlagsPropertyLocation); } } else if (fileFlag) { if (documentationFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "File", "Documentation"), commentType.FlagsPropertyLocation); } } // Check that File and Documentation aren't used with any of the other flags if (fileFlag) { if (variableTypeFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "File", "Variable Type"), commentType.FlagsPropertyLocation); } if (classHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "File", "Class Hierarchy"), commentType.FlagsPropertyLocation); } if (databaseHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "File", "Database Hierarchy"), commentType.FlagsPropertyLocation); } if (enumFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "File", "Enum"), commentType.FlagsPropertyLocation); } } if (documentationFlag) { if (variableTypeFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Documentation", "Variable Type"), commentType.FlagsPropertyLocation); } if (classHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Documentation", "Class Hierarchy"), commentType.FlagsPropertyLocation); } if (databaseHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Documentation", "Database Hierarchy"), commentType.FlagsPropertyLocation); } if (enumFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Documentation", "Enum"), commentType.FlagsPropertyLocation); } } // Check that Class Hierarchy and Database Hierarchy aren't both defined if (classHierarchyFlag && databaseHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.CantCombine(a,b)", "Class Hierarchy", "Database Hierarchy"), commentType.FlagsPropertyLocation); } // Check that Class Hierarchy and Database Hierarchy comment types also have Scope: Start if (commentType.Scope != CommentType.ScopeValue.Start) { // This is an error if Scope isn't defined because it's too big a behavior change to just make it implied. if (classHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.FlagRequiresScope(flag,scope)", "Class Hierarchy", "Start"), commentType.FlagsPropertyLocation); } if (databaseHierarchyFlag) { errorList.Add(Locale.Get("NaturalDocs.Engine", "CommentTypeFlags.FlagRequiresScope(flag,scope)", "Database Hierarchy", "Start"), commentType.FlagsPropertyLocation); } } // Variable Type and Enum are okay. We already know they aren't being used with File or Documentation, and they're safe // to use with Class Hierarchy and Database Hierarchy. } return(errorList.Count == startingErrorCount); }
// Group: Loading Functions // __________________________________________________________________________ /* Function: Load * * Loads the contents of a <Comments.txt> file into a <ConfigFiles.TextFile>, returning whether it was successful. If it * was unsuccessful config will be null and it will place errors on the errorList. * * Parameters: * * filename - The <Path> where the file is located. * propertySource - The <Engine.Config.PropertySource> associated with the file. * errorList - If it couldn't successfully parse the file it will add error messages to this list. * config - The contents of the file as a <ConfigFiles.TextFile>. */ public bool Load(Path filename, Engine.Config.PropertySource propertySource, Errors.ErrorList errorList, out ConfigFiles.TextFile config) { int previousErrorCount = errorList.Count; using (ConfigFile file = new ConfigFile()) { bool openResult = file.Open(filename, propertySource, ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace | ConfigFile.FileFormatFlags.CondenseValueWhitespace | ConfigFile.FileFormatFlags.SupportsNullValueLines | ConfigFile.FileFormatFlags.SupportsRawValueLines | ConfigFile.FileFormatFlags.MakeIdentifiersLowercase, errorList); if (openResult == false) { config = null; return(false); } config = new ConfigFiles.TextFile(); TextFileCommentType currentCommentType = null; TextFileKeywordGroup currentKeywordGroup = null; bool inKeywords = false; bool inTags = false; while (file.Get(out string identifier, out string value)) { // // Identifierless lines // if (identifier == null) { // Keywords if (inKeywords) { // Separate keywords string keyword, pluralKeyword; int commaIndex = value.IndexOf(','); if (commaIndex == -1) { keyword = value; pluralKeyword = null; } else { keyword = value.Substring(0, commaIndex).TrimEnd(); pluralKeyword = value.Substring(commaIndex + 1).TrimStart(); if (pluralKeyword.IndexOf(',') != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.NoMoreThanTwoKeywordsOnALine") ); } } // Check for banned characters int bannedCharIndex = keyword.IndexOfAny(BannedKeywordChars); char bannedChar = '\0'; if (bannedCharIndex != -1) { bannedChar = keyword[bannedCharIndex]; } else if (pluralKeyword != null) { bannedCharIndex = pluralKeyword.IndexOfAny(BannedKeywordChars); if (bannedCharIndex != -1) { bannedChar = pluralKeyword[bannedCharIndex]; } } if (bannedChar != '\0') { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", bannedChar) ); // Continue parsing } // Add to config currentKeywordGroup.Add(keyword, pluralKeyword); } // Tags, only a single value allowed else if (inTags) { if (value.IndexOf(',') != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.NoMoreThanOneTagOnALine") ); } int bannedChar = value.IndexOfAny(BannedKeywordChars); if (bannedChar != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.TagsCannotContain(char)", value[bannedChar]) ); // Continue parsing } config.AddTag(value, file.PropertyLocation); } // Raw line else { file.AddError( Locale.Get("NaturalDocs.Engine", "ConfigFile.LineNotInIdentifierValueFormat") ); } // Continue so we don't need to put all the identifier handling code in an else. continue; } // If we're here the line has an identifier currentKeywordGroup = null; inKeywords = false; inTags = false; // // Ignore Keywords // if (ignoreKeywordsRegex.IsMatch(identifier)) { currentCommentType = null; currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation); config.AddIgnoredKeywordGroup(currentKeywordGroup); inKeywords = true; if (!string.IsNullOrEmpty(value)) { string[] ignoredKeywordsArray = commaSeparatorRegex.Split(value); foreach (string ignoredKeyword in ignoredKeywordsArray) { int bannedChar = ignoredKeyword.IndexOfAny(BannedKeywordChars); if (bannedChar != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", ignoredKeyword[bannedChar]) ); // Continue parsing } currentKeywordGroup.Add(ignoredKeyword); } } } // // Tags // else if (tagsRegex.IsMatch(identifier)) { currentCommentType = null; inTags = true; if (!string.IsNullOrEmpty(value)) { string[] tagsArray = commaSeparatorRegex.Split(value); foreach (string tag in tagsArray) { int bannedChar = tag.IndexOfAny(BannedKeywordChars); if (bannedChar != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.TagsCannotContain(char)", tag[bannedChar]) ); // Continue parsing } config.AddTag(tag, file.PropertyLocation); } } } // // Comment Type // else if (commentTypeRegex.IsMatch(identifier)) { var existingCommentType = config.FindCommentType(value); if (existingCommentType != null) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.CommentTypeAlreadyExists(name)", value) ); // Continue parsing. We'll throw this into the existing type even though it shouldn't be overwriting // its values because we want to find any other errors there are in the file. currentCommentType = existingCommentType; } else { // There is no 1.6, but this covers all the 2.0 prereleases. if (file.Version < "1.6" && String.Compare(value, "generic", true) == 0) { value = "Information"; } currentCommentType = new TextFileCommentType(value, file.PropertyLocation); config.AddCommentType(currentCommentType); } } // // Alter Comment Type // else if (alterCommentTypeRegex.IsMatch(identifier)) { // We don't check if the name exists because it may exist in a different file. We also don't check if it exists // in the current file because using Alter is valid (if unnecessary) in that case and we don't want to combine // their definitions. Why? Consider this: // // Comment Type: Comment Type A // Keyword: Keyword A // // Comment Type: Comment Type B // Keyword: Keyword B // // Alter Comment Type: Comment Type A // Keyword: Keyword B // // Keyword B should be part of Comment Type A. However, if we merged the definitions it would appear // first and be overridden by Comment Type B. So we just create two comment type entries for A instead. currentCommentType = new TextFileCommentType(value, file.PropertyLocation, alterType: true); config.AddCommentType(currentCommentType); } // // (Plural) Display Name (From Locale) // else if (displayNameRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else if (currentCommentType.HasDisplayNameFromLocale) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Display Name", "Display Name from Locale") ); } else { currentCommentType.SetDisplayName(value, file.PropertyLocation); } } else if (pluralDisplayNameRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else if (currentCommentType.HasPluralDisplayNameFromLocale) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Plural Display Name", "Plural Display Name from Locale") ); } else { currentCommentType.SetPluralDisplayName(value, file.PropertyLocation); } } else if (displayNameFromLocaleRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else if (currentCommentType.HasDisplayName) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Display Name from Locale", "Display Name") ); } else { currentCommentType.SetDisplayNameFromLocale(value, file.PropertyLocation); } } else if (pluralDisplayNameFromLocaleRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else if (currentCommentType.HasPluralDisplayName) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Plural Display Name from Locale", "Plural Display Name") ); } else { currentCommentType.SetPluralDisplayNameFromLocale(value, file.PropertyLocation); } } // // Simple Identifier // else if (identifier == "simple identifier") { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else if (nonASCIILettersRegex.IsMatch(value)) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.SimpleIdentifierMustOnlyBeASCIILetters(name)", value) ); } else { currentCommentType.SetSimpleIdentifier(value, file.PropertyLocation); } } // // Scope // else if (identifier == "scope") { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else { value = value.ToLower(); if (value == "normal") { currentCommentType.SetScope(CommentType.ScopeValue.Normal, file.PropertyLocation); } else if (startRegex.IsMatch(value)) { currentCommentType.SetScope(CommentType.ScopeValue.Start, file.PropertyLocation); } else if (endRegex.IsMatch(value)) { currentCommentType.SetScope(CommentType.ScopeValue.End, file.PropertyLocation); } else if (alwaysGlobalRegex.IsMatch(value)) { currentCommentType.SetScope(CommentType.ScopeValue.AlwaysGlobal, file.PropertyLocation); } else { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Scope", value) ); } } } // // Flags // else if (flagsRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else { value = value.ToLower(); if (!string.IsNullOrEmpty(value)) { string[] flagStrings = commaSeparatorRegex.Split(value); // Merge them with the existing flags instead of overwriting them since they may also be set by the // Class Hierarchy property. CommentType.FlagValue flagsValue = currentCommentType.Flags ?? default; foreach (string flagString in flagStrings) { if (flagString == "code") { flagsValue |= CommentType.FlagValue.Code; } else if (flagString == "file") { flagsValue |= CommentType.FlagValue.File; } else if (documentationRegex.IsMatch(flagString)) { flagsValue |= CommentType.FlagValue.Documentation; } else if (variableTypeRegex.IsMatch(flagString)) { flagsValue |= CommentType.FlagValue.VariableType; } else if (classHierarchyRegex.IsMatch(flagString)) { flagsValue |= CommentType.FlagValue.ClassHierarchy; } else if (databaseHierarchyRegex.IsMatch(flagString)) { flagsValue |= CommentType.FlagValue.DatabaseHierarchy; } else if (enumRegex.IsMatch(flagString)) { flagsValue |= CommentType.FlagValue.Enum; } else if (string.IsNullOrEmpty(flagString) == false) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Flags", flagString) ); } } currentCommentType.SetFlags(flagsValue, file.PropertyLocation); } } } // // Class Hierarchy (deprecated, convert to flag) // else if (classHierarchyRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else { value = value.ToLower(); // Merge it with the existing flags since they may already be set. CommentType.FlagValue flagsValue = currentCommentType.Flags ?? default; if (yesRegex.IsMatch(value)) { flagsValue |= CommentType.FlagValue.ClassHierarchy; } else if (noRegex.IsMatch(value)) { flagsValue &= ~CommentType.FlagValue.ClassHierarchy; } else { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Class Hierarchy", value) ); } currentCommentType.SetFlags(flagsValue, file.PropertyLocation); } } // // Keywords // else if (keywordsRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else { currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation); currentCommentType.AddKeywordGroup(currentKeywordGroup); inKeywords = true; if (!string.IsNullOrEmpty(value)) { string[] keywordsArray = commaSeparatorRegex.Split(value); foreach (string keyword in keywordsArray) { int bannedChar = keyword.IndexOfAny(BannedKeywordChars); if (bannedChar != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", keyword[bannedChar]) ); // Continue parsing } currentKeywordGroup.Add(keyword); } } } } // // Language-Specific Keywords // // This must be tested after ignored and language-general keywords so that their modifiers ("add" or "ignore") don't // get mistaken for language names. else if (languageSpecificKeywordsRegex.IsMatch(identifier)) { if (currentCommentType == null) { AddNeedsCommentTypeError(file, identifier); } else { var match = languageSpecificKeywordsRegex.Match(identifier); var languageName = match.Groups[1].ToString(); currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation, languageName); currentCommentType.AddKeywordGroup(currentKeywordGroup); inKeywords = true; if (!string.IsNullOrEmpty(value)) { string[] keywordsArray = commaSeparatorRegex.Split(value); foreach (string keyword in keywordsArray) { int bannedChar = keyword.IndexOfAny(BannedKeywordChars); if (bannedChar != -1) { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", keyword[bannedChar]) ); // Continue parsing } currentKeywordGroup.Add(keyword); } } } } // // Deprecated keywords: Can Group With, Page Title if First // else if (identifier == "index" || identifier == "index with" || breakListsRegex.IsMatch(identifier) || identifier == "can group with" || identifier == "page title if first") { // Ignore and continue } // // Unrecognized keywords // else { file.AddError( Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedKeyword(keyword)", identifier) ); } } // while (file.Get) file.Close(); } if (errorList.Count == previousErrorCount) { return(true); } else { config = null; return(false); } }