// Group: Functions // __________________________________________________________________________ public ProjectConfig(Config.PropertySource source) { this.source = source; projectConfigFolder = new Path(); workingDataFolder = new Path(); projectInfo = new ProjectInfo(); tabWidth = 0; documentedOnly = false; autoGroup = true; shrinkFiles = true; projectConfigFolderPropertyLocation = PropertySource.NotDefined; workingDataFolderPropertyLocation = PropertySource.NotDefined; tabWidthPropertyLocation = PropertySource.NotDefined; documentedOnlyPropertyLocation = PropertySource.NotDefined; autoGroupPropertyLocation = PropertySource.NotDefined; shrinkFilesPropertyLocation = PropertySource.NotDefined; inputTargets = new List <Targets.Input>(); filterTargets = new List <Targets.Filter>(); outputTargets = new List <Targets.Output>(); }
/* Function: Open * * Attempts to open the passed configuration file and returns whether it was successful. Any errors * encountered in trying to open the file will be added to the errors array. * * Parameters: * * fileName - The <Path> of the configuration file. * propertySource - The <Config.PropertySource> this file represents. * fileFormatFlags - The <FileFormatFlags> to use when parsing the file. * errorList - A list where the parser will put any errors. */ public bool Open(Path fileName, Config.PropertySource propertySource, FileFormatFlags fileFormatFlags, ErrorList errorList) { if (IsOpen) { throw new Engine.Exceptions.FileAlreadyOpen(fileName, this.fileName); } if (!File.Exists(fileName)) { errorList.Add( Locale.Get("NaturalDocs.Engine", "ConfigFile.DoesNotExist(name)", fileName) ); return(false); } try { file = new StreamReader(fileName, System.Text.Encoding.UTF8, true); } catch (Exception e) { errorList.Add( Locale.Get("NaturalDocs.Engine", "ConfigFile.CouldNotOpen(name, exception)", fileName, e.Message) ); return(false); } this.fileName = fileName; this.propertySource = propertySource; this.fileFormatFlags = fileFormatFlags; this.errorList = errorList; this.lineNumber = 0; string identifier, valueString; if (!Get(out identifier, out valueString) || identifier.ToLower() != "format") { AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.DidntStartWithFormat(name)", fileName)); } else { version = valueString; if (version == null) { AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.FormatNotAValidVersionString(versionString)", valueString)); } } if (version != null) { return(true); } else { Close(); return(false); } }
// Group: Functions // __________________________________________________________________________ /* Constructor: Error * A constructor for an error that occurs in a specific file. */ public Error(string message, Path file = default(Path), int lineNumber = 0, Config.PropertySource configSource = Config.PropertySource.NotDefined, string property = null) { this.message = message; this.file = file; this.lineNumber = lineNumber; this.propertySource = configSource; this.property = property; }
// Group: Functions // __________________________________________________________________________ /* Constructor: PropertyLocation */ public PropertyLocation(Config.PropertySource source, Path fileName = default(Path), int lineNumber = 0) { #if DEBUG if (IsFileBased(source)) { if (fileName == null) { throw new Exception("Must provide a file name for " + source + " PropertyLocations."); } } else { if (fileName != null || lineNumber != 0) { throw new Exception("Cannot provide a file name or line number for " + source + " PropertyLocations."); } } #endif this.source = source; this.fileName = fileName; this.lineNumber = lineNumber; }
public Style LoadStyle(string name, Errors.ErrorList errorList, Config.PropertySource propertySource) { return(LoadStyle(name, errorList, new Config.PropertyLocation(propertySource))); }
/* Function: AddLinkedFile */ public void AddLinkedFile(Path file, Config.PropertySource propertySource, PageType type = PageType.All) { AddLinkedFile(file, new Config.PropertyLocation(propertySource), type); }
/* Function: AddInheritedStyle */ public void AddInheritedStyle(string name, Config.PropertySource propertySource, Style styleObject = null) { AddInheritedStyle(name, new Config.PropertyLocation(propertySource), styleObject); }
/* Function: AddOnLoad */ public void AddOnLoad(string onLoadString, Config.PropertySource propertySource, PageType type = PageType.All) { AddOnLoad(onLoadString, new Config.PropertyLocation(propertySource), type); }
// Group: Static Functions // __________________________________________________________________________ /* Function: IsFileBased * Returns whether the passed <Config.Source> is file-based. */ public static bool IsFileBased(Config.PropertySource configSource) { return(configSource >= PropertySource.LowestFileValue && configSource <= PropertySource.HighestFileValue); }
// Group: Loading Functions // __________________________________________________________________________ /* Function: Load * * Loads the configuration file and parses it. Redundant information will be simplified out, such as an Alter * Language section that applies to a language defined in the same file. * * Parameters: * * filename - The <Path> where the file is located. * propertySource - The <Config.PropertySource> associated with the file. * fileLanguages - Returns a list of <ConfigFileLanguages> in no particular order. * fileIgnoredExtensions - Returns any ignored extensions as a string array. * errorList - If it couldn't successfully parse the file it will add error messages to this list. * * Returns: * * Whether it was able to successfully load and parse the file without any errors. */ public bool Load(Path filename, Config.PropertySource propertySource, out List <ConfigFileLanguage> fileLanguages, out List <string> fileIgnoredExtensions, Errors.ErrorList errorList) { fileLanguages = new List <ConfigFileLanguage>(); fileIgnoredExtensions = new List <string>(); StringTable <ConfigFileLanguage> fileLanguageNames = new StringTable <ConfigFileLanguage>(Engine.Languages.Manager.KeySettingsForLanguageName); int previousErrorCount = errorList.Count; using (ConfigFile file = new ConfigFile()) { // Can't make identifiers lowercase here or we'd lose the case of the comment type in prototype ender lines. bool openResult = file.Open(filename, propertySource, ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace | ConfigFile.FileFormatFlags.CondenseValueWhitespace, errorList); if (openResult == false) { return(false); } string identifier, lcIdentifier, value; ConfigFileLanguage currentLanguage = null; // We need this in addition to ConfigFileLanguage.AlterLanguage because an entry altering a type defined in the // same file would be combined into the original, yet we still need to know if that entry is Alter to properly // detect whether we need to use Add/Replace with certain properties. bool alterCurrentLanguage = false; char[] space = { ' ' }; System.Text.RegularExpressions.Match match; while (file.Get(out identifier, out value)) { lcIdentifier = identifier.ToLower(); // // Ignore Extensions // if (ignoreExtensionsRegex.IsMatch(lcIdentifier)) { currentLanguage = null; string[] ignoredExtensionsArray = value.Split(space); fileIgnoredExtensions.AddRange(ignoredExtensionsArray); } // // Language // else if (lcIdentifier == "language") { if (fileLanguageNames.ContainsKey(value)) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.LanguageAlreadyExists(name)", value) ); // Continue parsing. We'll throw this into the existing language even though it shouldn't be overwriting // its values because we want to find any other errors there are in the file. currentLanguage = fileLanguageNames[value]; alterCurrentLanguage = false; } else { currentLanguage = new ConfigFileLanguage(value, false, file.LineNumber); alterCurrentLanguage = false; fileLanguages.Add(currentLanguage); fileLanguageNames.Add(value, currentLanguage); } } // // Alter Language // else if (alterLanguageRegex.IsMatch(lcIdentifier)) { // If this language already exists, collapse it into the current definition. if (fileLanguageNames.ContainsKey(value)) { currentLanguage = fileLanguageNames[value]; alterCurrentLanguage = true; } // If it doesn't exist, create the new language anyway with the alter flag set because it may exist in another // file. else { currentLanguage = new ConfigFileLanguage(value, true, file.LineNumber); alterCurrentLanguage = true; fileLanguages.Add(currentLanguage); fileLanguageNames.Add(value, currentLanguage); } } // // Aliases // else if (aliasesRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Aliases") ); } else { currentLanguage.Aliases = value.Split(space); currentLanguage.AddAliases = false; } } // // Add/Replace Aliases // else if ((match = addReplaceAliasesRegex.Match(lcIdentifier)) != null && match.Success) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" && currentLanguage.Aliases != null) { string[] addAliases = value.Split(space); string[] newAliases = new string[addAliases.Length + currentLanguage.Aliases.Length]; currentLanguage.Aliases.CopyTo(newAliases, 0); addAliases.CopyTo(newAliases, currentLanguage.Aliases.Length); currentLanguage.Aliases = newAliases; currentLanguage.AddAliases = true; } // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have // anything defined. else { currentLanguage.Aliases = value.Split(space); currentLanguage.AddAliases = (match.Groups[1].Value == "add"); } } // // Extensions // else if (extensionsRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Extensions") ); } else { currentLanguage.Extensions = value.Split(space); currentLanguage.AddExtensions = false; } } // // Add/Replace Extensions // else if ((match = addReplaceExtensionsRegex.Match(lcIdentifier)) != null && match.Success) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" && currentLanguage.Extensions != null) { string[] addExtensions = value.Split(space); string[] newExtensions = new string[addExtensions.Length + currentLanguage.Extensions.Length]; currentLanguage.Extensions.CopyTo(newExtensions, 0); addExtensions.CopyTo(newExtensions, currentLanguage.Extensions.Length); currentLanguage.Extensions = newExtensions; currentLanguage.AddExtensions = true; } // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have // anything defined. else { currentLanguage.Extensions = value.Split(space); currentLanguage.AddExtensions = (match.Groups[1].Value == "add"); } } // // Shebang Strings // else if (shebangStringsRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Shebang Strings") ); } else { currentLanguage.ShebangStrings = value.Split(space); currentLanguage.AddShebangStrings = false; } } // // Add/Replace Shebang Strings // else if ((match = addReplaceShebangStringsRegex.Match(lcIdentifier)) != null && match.Success) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" && currentLanguage.ShebangStrings != null) { string[] addShebangStrings = value.Split(space); string[] newShebangStrings = new string[addShebangStrings.Length + currentLanguage.ShebangStrings.Length]; currentLanguage.ShebangStrings.CopyTo(newShebangStrings, 0); addShebangStrings.CopyTo(newShebangStrings, currentLanguage.ShebangStrings.Length); currentLanguage.ShebangStrings = newShebangStrings; currentLanguage.AddShebangStrings = true; } // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have // anything defined. else { currentLanguage.ShebangStrings = value.Split(space); currentLanguage.AddShebangStrings = (match.Groups[1].Value == "add"); } } // // Simple Identifier // else if (lcIdentifier == "simple identifier") { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (nonASCIILettersRegex.IsMatch(value)) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.SimpleIdentifierMustOnlyBeASCIILetters(name)", value) ); } else { currentLanguage.SimpleIdentifier = value; } } // // Line Comments // else if (lineCommentsRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else { currentLanguage.LineCommentStrings = value.Split(space); } } // // Block Comments // else if (blockCommentsRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else { string[] newBlockCommentStrings = value.Split(space); if (newBlockCommentStrings.Length % 2 != 0) { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.BlockCommentsMustHaveAnEvenNumberOfSymbols") ); } else { currentLanguage.BlockCommentStringPairs = newBlockCommentStrings; } } } // // Member Operator // else if (memberOperatorRegex.IsMatch(lcIdentifier)) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else { currentLanguage.MemberOperator = value; } } // // Line Extender // else if (lcIdentifier == "line extender") { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else { currentLanguage.LineExtender = value; } } // // Enum Values // else if (enumValuesRegex.IsMatch(lcIdentifier)) { string lcValue = value.ToLower(); if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (lcValue == "global") { currentLanguage.EnumValue = Language.EnumValues.Global; } else if (lcValue == "under type") { currentLanguage.EnumValue = Language.EnumValues.UnderType; } else if (lcValue == "under parent") { currentLanguage.EnumValue = Language.EnumValues.UnderParent; } else { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.InvalidEnumValue(value)", value) ); } } // // Case Sensitive // else if (caseSensitiveRegex.IsMatch(lcIdentifier)) { string lcValue = value.ToLower(); if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else if (yesRegex.IsMatch(lcValue)) { currentLanguage.CaseSensitive = true; } else if (noRegex.IsMatch(lcValue)) { currentLanguage.CaseSensitive = false; } else { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedValue(keyword, value)", "Case Sensitive", value) ); } } // // Prototype Enders // // Use identifier and not lcIdentifier to keep the case of the comment type. The regex will compensate. else if ((match = prototypeEndersRegex.Match(identifier)) != null && match.Success) { if (currentLanguage == null) { NeedsLanguageError(file, identifier); } else { string commentType = match.Groups[1].Value; string[] enderStrings = value.Split(space); currentLanguage.SetPrototypeEnderStrings(commentType, enderStrings); } } // // Deprecated keywords // else if (ignorePrefixesRegex.IsMatch(lcIdentifier) || lcIdentifier == "perl package" || lcIdentifier == "full language support") { // Ignore } // // Unrecognized keywords // else { file.AddError( Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedKeyword(keyword)", identifier) ); } } // while (file.Get) file.Close(); } if (errorList.Count == previousErrorCount) { return(true); } else { return(false); } }
/* Function: Add * Adds an error occurring in a particular file to the list. */ public void Add(string message, Path file = default(Path), int lineNumber = 0, Config.PropertySource configSource = Config.PropertySource.NotDefined, string property = null) { list.Add(new Error(message, file, lineNumber, configSource, property)); sorted = false; }
/* Function: Matches * Whether the error occurs in the passed location. */ public bool Matches(Path file = default(Path), int lineNumber = 0, Config.PropertySource propertySource = Config.PropertySource.NotDefined, string property = null) { return(this.file == file && this.lineNumber == lineNumber && this.propertySource == propertySource && this.property == property); }
/* Function: SetHomePage */ public void SetHomePage(Path file, Config.PropertySource propertySource) { SetHomePage(file, new Config.PropertyLocation(propertySource)); }