public override bool Start(Errors.ErrorList errorList) { int errors = errorList.Count; StartupIssues newStartupIssues = StartupIssues.None; // // Validate the output folder. // if (System.IO.Directory.Exists(config.Folder) == false) { errorList.Add(Locale.Get("NaturalDocs.Engine", "Error.FolderDoesntExist(type, name)", "output", config.Folder)); return(false); } // // Load and validate the styles, including any inherited styles. // string styleName = config.ProjectInfo.StyleName; Style_txt styleParser = new Style_txt(); if (styleName == null) { style = EngineInstance.Styles.LoadStyle("Default", errorList, Config.PropertySource.SystemDefault); } else if (EngineInstance.Styles.StyleExists(styleName)) { style = EngineInstance.Styles.LoadStyle(styleName, errorList, config.ProjectInfo.StyleNamePropertyLocation); } // Check if it's an empty folder we want to generate a default Style.txt for else if (System.IO.Directory.Exists(EngineInstance.Config.ProjectConfigFolder + '/' + styleName) && !System.IO.File.Exists(EngineInstance.Config.ProjectConfigFolder + '/' + styleName + "/Style.txt")) { style = new Styles.Advanced(EngineInstance.Config.ProjectConfigFolder + '/' + styleName + "/Style.txt"); // Inherit Default so everything still works before it's filled out. style.AddInheritedStyle("Default", Config.PropertySource.SystemGenerated); if (!styleParser.Save((Styles.Advanced)style, errorList, false)) { return(false); } // Now we have to reload it so it loads the inherited style as well. style = EngineInstance.Styles.LoadStyle(styleName, errorList, config.ProjectInfo.StyleNamePropertyLocation); } else { errorList.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindStyle(name)", styleName), config.ProjectInfo.StyleNamePropertyLocation); return(false); } stylesWithInheritance = style.BuildInheritanceList(); // // Load Config.nd // Config_nd binaryConfigParser = new Config_nd(); List <Style> previousStyles; List <FileSourceInfo> previousFileSourceInfoList; bool hasBinaryConfigFile = false; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh)) { hasBinaryConfigFile = binaryConfigParser.Load(WorkingDataFolder + "/Config.nd", out previousStyles, out previousFileSourceInfoList); } else // start fresh { previousStyles = new List <Style>(); previousFileSourceInfoList = new List <FileSourceInfo>(); } // // Compare to the previous list of styles. // bool inPurgingOperation = false; if (!hasBinaryConfigFile) { // If we don't have the binary config file we have to purge every style folder because some of them may no longer be in // use and we won't know which. PurgeAllStyleFolders(ref inPurgingOperation); newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; } else // (hasBinaryConfigFile) { // Purge the style folders for any no longer in use. foreach (var previousStyle in previousStyles) { bool stillExists = false; foreach (var currentStyle in stylesWithInheritance) { if (currentStyle.IsSameFundamentalStyle(previousStyle)) { stillExists = true; break; } } if (!stillExists) { PurgeStyleFolder(previousStyle.Name, ref inPurgingOperation); } } // Reparse styles on anything new. If a style is new we can't assume all its files are going to be sent to the // IChangeWatcher functions because another output target may have been using it, and thus they are already in // Files.Manager. foreach (var currentStyle in stylesWithInheritance) { bool foundMatch = false; foreach (var previousStyle in previousStyles) { if (previousStyle.IsSameFundamentalStyle(currentStyle)) { foundMatch = true; break; } } if (!foundMatch) { newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; break; } } } // // Compare to the previous list of FileSources. // if (!hasBinaryConfigFile) { // If we don't have the binary config file we need to rebuild all the output because we don't know which FileSource was // previously set to which number, which determines which output folder they use, like /files vs /files2. newStartupIssues |= StartupIssues.NeedToRebuildAllOutput; // This also means we have to purge every source or image output folder because we won't know which changed or are // no longer in use. PurgeAllSourceAndImageFolders(ref inPurgingOperation); } else // (hasBinaryConfigFile) { bool hasDeletions = false; bool hasAdditions = false; // Purge the output folders of any deleted FileSources foreach (var previousFileSourceInfo in previousFileSourceInfoList) { bool stillExists = false; foreach (var fileSource in EngineInstance.Files.FileSources) { if (previousFileSourceInfo.IsSameFundamentalFileSource(fileSource)) { stillExists = true; break; } } if (!stillExists) { hasDeletions = true; Path outputFolder; if (previousFileSourceInfo.Type == InputType.Source) { outputFolder = Paths.SourceFile.OutputFolder(OutputFolder, previousFileSourceInfo.Number); } else if (previousFileSourceInfo.Type == InputType.Image) { outputFolder = Paths.Image.OutputFolder(OutputFolder, previousFileSourceInfo.Number, previousFileSourceInfo.Type); } else { throw new NotImplementedException(); } PurgeFolder(outputFolder, ref inPurgingOperation); } } // Check if any FileSources were added foreach (var fileSource in EngineInstance.Files.FileSources) { if (fileSource.Type == InputType.Source || fileSource.Type == InputType.Image) { bool foundMatch = false; foreach (var previousFileSourceInfo in previousFileSourceInfoList) { if (previousFileSourceInfo.IsSameFundamentalFileSource(fileSource)) { foundMatch = true; break; } } if (!foundMatch) { hasAdditions = true; break; } } } // If there were both additions and deletions, force a rebuild. This covers if a FileSource was simply moved from one // number to another, in which case the rebuild is required to populate the new folder. This also covers if a folder // FileSource is replaced by one for its parent folder, in which case a rebuild is required to recreate the output for the // files in the child folder. if (hasAdditions && hasDeletions) { newStartupIssues |= StartupIssues.NeedToRebuildAllOutput; } } // // Load BuildState.nd // BuildState_nd buildStateParser = new BuildState_nd(); bool hasBinaryBuildStateFile = false; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh | StartupIssues.FileIDsInvalidated | StartupIssues.CodeIDsInvalidated | StartupIssues.CommentIDsInvalidated)) { hasBinaryBuildStateFile = buildStateParser.Load(WorkingDataFolder + "/BuildState.nd", out buildState, out unprocessedChanges); } else // start fresh { buildState = new BuildState(); unprocessedChanges = new UnprocessedChanges(); } if (!hasBinaryBuildStateFile) { // If we don't have a build state file we need to reparse all the source files because we need to know sourceFilesWithContent // and classesWithContent. We also need to rebuild all the output because we don't know if there was anything left in // sourceFilesToRebuild from the last run. But those two flags actually aren't enough, because it will reparse those files, send // them to CodeDB, and then CodeDB won't send topic updates if the underlying content hasn't changed. We'd actually need // to add all files and classes to UnprocessedChanges, but the Files module isn't started yet. So f**k it, blow it all up and start // over. newStartupIssues |= StartupIssues.NeedToStartFresh; // Purge everything so no stray files are left behind from the previous build. PurgeAllSourceAndImageFolders(ref inPurgingOperation); PurgeAllClassFolders(ref inPurgingOperation); PurgeAllDatabaseFolders(ref inPurgingOperation); PurgeAllStyleFolders(ref inPurgingOperation); PurgeAllMenuFolders(ref inPurgingOperation); PurgeAllSearchIndexFolders(ref inPurgingOperation); } // // We're done with anything that could purge. // FinishedPurging(ref inPurgingOperation); // // Resave the Style.txt-based styles. // foreach (var style in stylesWithInheritance) { if (style is Styles.Advanced) { var advancedStyle = style as Styles.Advanced; bool isSystemStyle = EngineInstance.Config.SystemStyleFolder.Contains(advancedStyle.ConfigFile); // No error on save for system styles. styleParser.Save(advancedStyle, errorList, noErrorOnFail: isSystemStyle); } } // // Save Config.nd. // if (!System.IO.Directory.Exists(WorkingDataFolder)) { System.IO.Directory.CreateDirectory(WorkingDataFolder); } List <FileSourceInfo> fileSourceInfoList = new List <FileSourceInfo>(); foreach (var fileSource in EngineInstance.Files.FileSources) { if (fileSource.Type == Files.InputType.Source || fileSource.Type == Files.InputType.Image) { FileSourceInfo fileSourceInfo = new FileSourceInfo(); fileSourceInfo.CopyFrom(fileSource); fileSourceInfoList.Add(fileSourceInfo); } ; } binaryConfigParser.Save(WorkingDataFolder + "/Config.nd", stylesWithInheritance, fileSourceInfoList); // // Always rebuild the scaffolding since they're quick. If you ever make this differential, remember that FramePage depends // on the project name and other information. // unprocessedChanges.AddFramePage(); unprocessedChanges.AddMainStyleFiles(); // // Load up unprocessedChanges if we're rebuilding // if (EngineInstance.HasIssues(StartupIssues.NeedToRebuildAllOutput) || (newStartupIssues & StartupIssues.NeedToRebuildAllOutput) != 0) { unprocessedChanges.AddSourceFiles(buildState.sourceFilesWithContent); unprocessedChanges.AddClasses(buildState.classesWithContent); unprocessedChanges.AddImageFiles(buildState.usedImageFiles); newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; unprocessedChanges.AddMainStyleFiles(); unprocessedChanges.AddMainSearchFiles(); unprocessedChanges.AddFramePage(); unprocessedChanges.AddMenu(); // We'll handle search prefixes after starting SearchIndex } // // Create the search index, watch other modules, and apply new StartupIssues // searchIndex = new SearchIndex.Manager(this); EngineInstance.CodeDB.AddChangeWatcher(this); EngineInstance.Files.AddChangeWatcher(this); searchIndex.AddChangeWatcher(this); EngineInstance.AddStartupWatcher(this); if (newStartupIssues != StartupIssues.None) { EngineInstance.AddStartupIssues(newStartupIssues, dontNotify: this); } searchIndex.Start(errorList); // // If we're rebuilding everything, add the search index prefixes now that that's started // if (EngineInstance.HasIssues(StartupIssues.NeedToRebuildAllOutput)) { var usedPrefixes = searchIndex.UsedPrefixes(); foreach (var searchPrefix in usedPrefixes) { unprocessedChanges.AddSearchPrefix(searchPrefix); } } return(errors == errorList.Count); }
/* Function: Load * Loads the information in <Config.nd> and returns whether it was successful. If not all the out parameters will still * return objects, they will just be empty. */ public bool Load(Path filename, out Config.ProjectInfo projectInfo, out List <Style> styles, out List <FileSourceInfo> fileSourceInfoList) { projectInfo = new Config.ProjectInfo(); styles = new List <Style>(); fileSourceInfoList = new List <FileSourceInfo>(); BinaryFile binaryFile = new BinaryFile(); bool result = true; try { if (binaryFile.OpenForReading(filename, "2.2") == false) { result = false; } else { // [String: Project Title or null] // [String: Project Subtitle or null] // [String: Project Copyright or null] // [String: Project Timestamp Code or null] projectInfo.Title = binaryFile.ReadString(); projectInfo.TitlePropertyLocation = Config.PropertySource.PreviousRun; projectInfo.Subtitle = binaryFile.ReadString(); projectInfo.SubtitlePropertyLocation = Config.PropertySource.PreviousRun; projectInfo.Copyright = binaryFile.ReadString(); projectInfo.CopyrightPropertyLocation = Config.PropertySource.PreviousRun; projectInfo.TimestampCode = binaryFile.ReadString(); projectInfo.TimestampCodePropertyLocation = Config.PropertySource.PreviousRun; // [String: Style Path] // (properties) // [String: Style Path] // ... // [String: null] string stylePath = binaryFile.ReadString(); while (stylePath != null) { Style style; if (stylePath.EndsWith(".css", StringComparison.OrdinalIgnoreCase)) { style = new Styles.CSSOnly(stylePath); } else { style = new Styles.Advanced(stylePath); } styles.Add(style); // [String: Inherit] ... [String: null] string inheritStatement = binaryFile.ReadString(); while (inheritStatement != null) { // Find the name in the list of styles so we can connect the objects together properly. There should only // be one style per name so we can just compare by name. Also, this list is stored in the order in which // they must be applied, which means inherited styles will appear before the ones that inherit from them, // so we can search the list we've built so far instead of waiting until they're all loaded. Style matchingStyle = null; for (int i = 0; i < styles.Count; i++) { if (string.Compare(inheritStatement, styles[i].Name, StringComparison.OrdinalIgnoreCase) == 0) { matchingStyle = styles[i]; break; } } // If there's no match just add it as null. style.AddInheritedStyle(inheritStatement, Config.PropertySource.PreviousRun, matchingStyle); inheritStatement = binaryFile.ReadString(); } // [String: OnLoad] [Byte: Page Type] ... [String: null] string onLoadStatement = binaryFile.ReadString(); while (onLoadStatement != null) { Engine.Styles.PageType pageType = (Engine.Styles.PageType)binaryFile.ReadByte(); style.AddOnLoad(onLoadStatement, Config.PropertySource.PreviousRun, pageType); onLoadStatement = binaryFile.ReadString(); } // [String: Link] [Byte: Page Type] ... [String: null] string linkStatement = binaryFile.ReadString(); while (linkStatement != null) { Engine.Styles.PageType pageType = (Engine.Styles.PageType)binaryFile.ReadByte(); style.AddLinkedFile(linkStatement, Config.PropertySource.PreviousRun, pageType); linkStatement = binaryFile.ReadString(); } // [String: Home Page or null] string homePage = binaryFile.ReadString(); if (homePage != null) { style.SetHomePage(homePage, Config.PropertySource.PreviousRun); } // Next style path stylePath = binaryFile.ReadString(); } projectInfo.StyleName = styles[styles.Count - 1].Name; projectInfo.StyleNamePropertyLocation = Config.PropertySource.PreviousRun; // [Int32: Source FileSource Number] [String: Source FileSource UniqueIDString] // [Int32: Source FileSource Number] [String: Source FileSource UniqueIDString] // ... // [Int32: 0] FileSourceInfo fileSourceInfo = new FileSourceInfo(); fileSourceInfo.Type = Files.InputType.Source; for (;;) { fileSourceInfo.Number = binaryFile.ReadInt32(); if (fileSourceInfo.Number == 0) { break; } fileSourceInfo.UniqueIDString = binaryFile.ReadString(); fileSourceInfoList.Add(fileSourceInfo); } // [Int32: Image FileSource Number] [String: Image FileSource UniqueIDString] // [Int32: Image FileSource Number] [String: Image FileSource UniqueIDString] // ... // [Int32: 0] fileSourceInfo.Type = Files.InputType.Image; for (;;) { fileSourceInfo.Number = binaryFile.ReadInt32(); if (fileSourceInfo.Number == 0) { break; } fileSourceInfo.UniqueIDString = binaryFile.ReadString(); fileSourceInfoList.Add(fileSourceInfo); } } } catch { result = false; } finally { binaryFile.Dispose(); } if (result == false) { projectInfo = new Config.ProjectInfo(); styles.Clear(); fileSourceInfoList.Clear(); } return(result); }
/* Function: Load * Loads <Style.txt> and returns it as a <Styles.Advanced> object. If there are any errors found in <Style.txt> they will be added * to the list and the function will return null. */ public Styles.Advanced Load(Path path, Errors.ErrorList errors) { Styles.Advanced style = new Styles.Advanced(path); using (ConfigFile file = new ConfigFile()) { if (!file.Open(path, Config.PropertySource.StyleConfigurationFile, ConfigFile.FileFormatFlags.MakeIdentifiersLowercase | ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors)) { return(null); } int errorCount = errors.Count; string lcIdentifier, value; System.Text.RegularExpressions.Match match; while (file.Get(out lcIdentifier, out value)) { // Inherit if (inheritRegex.IsMatch(lcIdentifier)) { style.AddInheritedStyle(value, file.PropertyLocation, null); continue; } // Link match = linkRegex.Match(lcIdentifier); if (match.Success) { PageType pageType = PageType.All; if (match.Groups[1].Success) { PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString()); if (pageTypeTemp == null) { file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } else { pageType = pageTypeTemp.Value; } } Path linkedFile = value; if (!Styles.Manager.LinkableFileExtensions.Contains(linkedFile.Extension)) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkFileWithExtension(extension)", linkedFile.Extension)); } else if (linkedFile.Extension.ToLower() == "css" && pageType != PageType.All) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkCSSFileToSpecificPageTypes(pageType)", PageTypes.NameOf(pageType))); } else { if (linkedFile.IsRelative) { linkedFile = style.Folder + "/" + linkedFile; } if (!System.IO.File.Exists(linkedFile)) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindLinkedFile(name)", linkedFile)); } else if (!style.Folder.Contains(linkedFile)) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.LinkedFileMustBeInStyleFolder(name, folder)", linkedFile, style.Folder)); } else { style.AddLinkedFile(linkedFile, file.PropertyLocation, pageType); } } continue; } // OnLoad match = onLoadRegex.Match(lcIdentifier); if (match.Success) { PageType pageType = PageType.All; if (match.Groups[1].Success) { PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString()); if (pageTypeTemp == null) { file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } else { pageType = pageTypeTemp.Value; } } style.AddOnLoad(value, file.PropertyLocation, pageType); continue; } // Home Page if (homePageRegex.IsMatch(lcIdentifier)) { Path homePageFile = value; string lcExtension = homePageFile.Extension.ToLower(); if (lcExtension != "html" && lcExtension != "htm") { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageMustHaveHTMLExtension(extension)", homePageFile.Extension)); } else { if (homePageFile.IsRelative) { homePageFile = style.Folder + "/" + homePageFile; } if (!System.IO.File.Exists(homePageFile)) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindHomePageFile(name)", homePageFile)); } else if (!style.Folder.Contains(homePageFile)) { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageFileMustBeInStyleFolder(name, folder)", homePageFile, style.Folder)); } else { style.SetHomePage(homePageFile, file.PropertyLocation); } } continue; } file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } // Check for files or JavaScript linked to custom home pages since they wouldn't apply. if (style.HomePage != null) { if (style.Links != null) { foreach (var link in style.Links) { if (link.Type == PageType.Home) { errors.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantUseHomeLinksWithCustomHomePage"), link.PropertyLocation); } } } if (style.OnLoad != null) { foreach (var onLoad in style.OnLoad) { if (onLoad.Type == PageType.Home) { errors.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantUseHomeOnLoadWithCustomHomePage"), onLoad.PropertyLocation); } } } } if (errorCount == errors.Count) { return(style); } else { return(null); } } }
/* Function: Save * Saves the passed style's <Style.txt>. */ public bool Save(Styles.Advanced style, Errors.ErrorList errorList, bool noErrorOnFail) { System.Text.StringBuilder output = new System.Text.StringBuilder(512); // Header output.AppendLine("Format: " + Engine.Instance.VersionString); output.AppendLine(); output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.Header.multiline")); output.AppendLine(); output.AppendLine(); // Inheritance output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.InheritanceHeader.multiline")); output.AppendLine(); if (style.Inherits != null) { foreach (var inheritedStyle in style.Inherits) { output.Append("Inherit: "); output.AppendLine(inheritedStyle.Name); } output.AppendLine(); output.AppendLine(); } output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.InheritanceReference.multiline")); output.AppendLine(); output.AppendLine(); // Linked Files output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.LinkedFilesHeader.multiline")); output.AppendLine(); if (style.Links != null) { foreach (var link in style.Links) { if (link.Type != PageType.All) { output.Append(PageTypes.NameOf(link.Type)); output.Append(' '); } output.Append("Link: "); output.AppendLine(style.MakeRelative(link.File)); } output.AppendLine(); output.AppendLine(); } output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.LinkedFilesReference.multiline")); output.AppendLine(); output.AppendLine(); // OnLoad output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.OnLoadHeader.multiline")); output.AppendLine(); if (style.OnLoad != null) { foreach (var onLoadStatement in style.OnLoad) { if (onLoadStatement.Type != PageType.All) { output.Append(PageTypes.NameOf(onLoadStatement.Type)); output.Append(' '); } output.Append("OnLoad: "); output.AppendLine(onLoadStatement.Statement); output.AppendLine(); } output.AppendLine(); } output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.OnLoadReference.multiline")); output.AppendLine(); output.AppendLine(); // Home Page output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageHeader.multiline")); output.AppendLine(); if (style.HomePage != null) { output.Append("Home Page: "); output.AppendLine(style.MakeRelative(style.HomePage)); output.AppendLine(); output.AppendLine(); } output.Append(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageReference.multiline")); return(ConfigFile.SaveIfDifferent(style.ConfigFile, output.ToString(), noErrorOnFail, errorList)); }
/* Function: Load * Loads <Style.txt> and returns it as a <Styles.Advanced> object. If there are any errors found in <Style.txt> they will be added * to the list and the function will return null. */ public Styles.Advanced Load(Path path, Errors.ErrorList errors) { Styles.Advanced style = new Styles.Advanced(path); using (ConfigFile file = new ConfigFile()) { if (!file.Open(path, Config.PropertySource.StyleConfigurationFile, ConfigFile.FileFormatFlags.MakeIdentifiersLowercase | ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors)) { return(null); } int errorCount = errors.Count; string lcIdentifier, value; System.Text.RegularExpressions.Match match; while (file.Get(out lcIdentifier, out value)) { // Inherit if (inheritRegex.IsMatch(lcIdentifier)) { style.AddInheritedStyle(value, file.PropertyLocation, null); continue; } // Link match = linkRegex.Match(lcIdentifier); if (match.Success) { PageType pageType = PageType.All; if (match.Groups[1].Success) { PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString()); if (pageTypeTemp == null) { file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } else { pageType = pageTypeTemp.Value; } } Path linkedFile = value; if (linkableFileExtensionsRegex.IsMatch(linkedFile.Extension)) { Path fullLinkedFile = style.Folder + "/" + linkedFile; if (System.IO.File.Exists(fullLinkedFile)) { style.AddLinkedFile(fullLinkedFile, file.PropertyLocation, pageType); } else { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindLinkedFile(name)", fullLinkedFile)); } } else { file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkFileWithExtension(extension)", linkedFile.Extension)); } continue; } // OnLoad match = onLoadRegex.Match(lcIdentifier); if (match.Success) { PageType pageType = PageType.All; if (match.Groups[1].Success) { PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString()); if (pageTypeTemp == null) { file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } else { pageType = pageTypeTemp.Value; } } style.AddOnLoad(value, file.PropertyLocation, pageType); continue; } file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier)); } if (errorCount == errors.Count) { return(style); } else { return(null); } } }