예제 #1
0
 /* Function: Validate
  * Checks whether the file source is valid and adds an error to the list if not.  The default implementation simply
  * returns true.
  */
 virtual public bool Validate(Errors.ErrorList errors)
 {
     return(true);
 }
예제 #2
0
        /* Function: LoadStyle
         * Converts a style path to a <HTMLStyle> object, loading its <Style.txt> if appropriate.  If there are any errors found
         * in <Style.txt> they will be added to the list and the function will return null.
         */
        public static HTMLStyle LoadStyle(Path stylePath, Errors.ErrorList errors)
        {
            HTMLStyle style = new HTMLStyle(stylePath);

            if (style.IsCSSOnly)
            {
                return(style);
            }

            using (ConfigFile file = new ConfigFile())
            {
                if (!file.Open(stylePath, ConfigFile.FileFormatFlags.MakeIdentifiersLowercase |
                               ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors))
                {
                    return(null);
                }

                int    errorCount = errors.Count;
                string lcIdentifier, value;
                System.Text.RegularExpressions.Match match;

                Regex.Styles.HTML.Inherit inheritRegex = new Regex.Styles.HTML.Inherit();
                Regex.Styles.HTML.Link    linkRegex = new Regex.Styles.HTML.Link();
                Regex.Styles.HTML.OnLoad  onLoadRegex = new Regex.Styles.HTML.OnLoad();
                Regex.Styles.HTML.LinkableFileExtensions linkableFileExtensionsRegex = new Regex.Styles.HTML.LinkableFileExtensions();

                while (file.Get(out lcIdentifier, out value))
                {
                    if (inheritRegex.IsMatch(lcIdentifier))
                    {
                        style.AddInheritedStyle(value);
                        continue;
                    }

                    match = linkRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypeOf(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(linkedFile, pageType);
                            }
                            else
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.CantFindLinkedFile(name)", fullLinkedFile));
                            }
                        }
                        else
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.CantLinkFileWithExtension(extension)",
                                                     linkedFile.Extension));
                        }

                        continue;
                    }

                    match = onLoadRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypeOf(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        style.AddOnLoad(value, pageType);
                        continue;
                    }

                    file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                }

                if (errorCount == errors.Count)
                {
                    return(style);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #3
0
        /* Function: SaveStyle
         * Saves the passed <HTMLStyle> as <Style.txt>, provided it's not CSS-only.
         */
        static public bool SaveStyle(HTMLStyle style, Errors.ErrorList errorList, bool noErrorOnFail)
        {
            if (style.IsCSSOnly)
            {
                throw new InvalidOperationException();
            }

            System.Text.StringBuilder output = new System.Text.StringBuilder(512);


            // Header

            output.AppendLine("Format: " + Engine.Instance.VersionString);
            output.AppendLine();
            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.Header.multiline"));
            output.AppendLine();
            output.AppendLine();


            // Inheritance

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.InheritanceHeader.multiline"));
            output.AppendLine();

            if (style.Inherits != null)
            {
                foreach (string inheritedStyleName in style.Inherits)
                {
                    output.Append("Inherit: ");
                    output.AppendLine(inheritedStyleName);
                }

                output.AppendLine();
                output.AppendLine();
            }

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.InheritanceReference.multiline"));
            output.AppendLine();
            output.AppendLine();


            // Linked Files

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.LinkedFilesHeader.multiline"));
            output.AppendLine();

            if (style.Links != null)
            {
                foreach (HTMLStyleFileLink link in style.Links)
                {
                    if (link.Type != PageType.All)
                    {
                        output.Append(PageTypeNameOf(link.Type));
                        output.Append(' ');
                    }

                    output.Append("Link: ");
                    output.AppendLine(link.File);
                }

                output.AppendLine();
                output.AppendLine();
            }

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.LinkedFilesReference.multiline"));
            output.AppendLine();
            output.AppendLine();


            // OnLoad

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.OnLoadHeader.multiline"));
            output.AppendLine();

            if (style.OnLoad != null)
            {
                foreach (HTMLStyleOnLoadStatement onLoadStatement in style.OnLoad)
                {
                    if (onLoadStatement.Type != PageType.All)
                    {
                        output.Append(PageTypeNameOf(onLoadStatement.Type));
                        output.Append(' ');
                    }

                    output.Append("OnLoad: ");
                    output.AppendLine(onLoadStatement.Statement);
                    output.AppendLine();
                }

                output.AppendLine();
            }

            output.Append(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.OnLoadReference.multiline"));


            return(ConfigFile.SaveIfDifferent(style.ConfigFile, output.ToString(), noErrorOnFail, errorList));
        }
예제 #4
0
        /* Function: Start
         *
         * Loads and combines the two versions of <Languages.txt>, returning whether it was successful.  If there were any errors
         * they will be added to errorList.
         *
         * Dependencies:
         *
         *		- <Config.Manager> and <CommentTypes.Manager> must be started before using the rest of the class.
         */
        public bool Start(Errors.ErrorList errorList)
        {
            List <ConfigFileLanguage> systemLanguageList;
            List <ConfigFileLanguage> projectLanguageList;
            List <string>             ignoredSystemExtensions;
            List <string>             ignoredProjectExtensions;

            List <Language> binaryLanguages;
            List <KeyValuePair <string, int> > binaryAliases;
            List <KeyValuePair <string, int> > binaryExtensions;
            List <KeyValuePair <string, int> > binaryShebangStrings;
            List <string> binaryIgnoredExtensions;

            // The return value, which is whether we were able to successfully load and parse the system Languages.txt, and if
            // it exists, the project Languages.txt.  The project Languages.txt not existing is not a failure.
            bool success = true;

            // Whether anything has changed since the last run, as determined by Languages.nd.  If Languages.nd doesn't exist
            // or is corrupt, we have to assume something changed.
            bool changed = false;


            // First add all the predefined languages, since they may be subclassed.

            foreach (Language language in predefinedLanguages)
            {
                languages.Add(language);
            }


            // We need the ID numbers to stay consistent between runs, so we create all the languages from the binary file
            // next.  We'll worry about comparing their attributes with the text files and seeing if any were added or deleted later.

            Languages_nd languagesNDParser = new Languages_nd(this);

            // Don't bother going through the effort if we're rebuilding everything anyway.
            if (EngineInstance.Config.ReparseEverything == true)
            {
                binaryLanguages         = new List <Language>();
                binaryAliases           = new List <KeyValuePair <string, int> >();
                binaryExtensions        = new List <KeyValuePair <string, int> >();
                binaryShebangStrings    = new List <KeyValuePair <string, int> >();
                binaryIgnoredExtensions = new List <string>();

                changed = true;
            }

            else if (languagesNDParser.Load(EngineInstance.Config.WorkingDataFolder + "/Languages.nd", out binaryLanguages,
                                            out binaryAliases, out binaryExtensions, out binaryShebangStrings, out binaryIgnoredExtensions) == false)
            {
                changed = true;
                // Even though it failed, LoadBinaryFiles will still have created valid empty objects for them.
            }

            else             // LoadBinaryFile succeeded
            {
                // We use a try block so if anything screwy happens, like two languages having the same ID number and thus
                // causing an exception when added, we can continue as if the binary file didn't parse at all.
                try
                {
                    foreach (Language binaryLanguage in binaryLanguages)
                    {
                        // We don't add the binary language itself because we only want those for comparison purposes.  We otherwise
                        // want the languages to be at their default values because the Languages.txt versions will only set some
                        // attributes, not all.

                        // Check for predefined languages of the same name.  If any of the binary languages' IDs collide with the
                        // predefined languages' ones, it will be taken care of by the exception handler.
                        Language existingLanguage = languages[binaryLanguage.Name];

                        if (existingLanguage == null)
                        {
                            Language newLanguage = new Language(this, binaryLanguage.Name);
                            newLanguage.ID           = binaryLanguage.ID;
                            newLanguage.InBinaryFile = true;

                            languages.Add(newLanguage);
                        }
                        else
                        {
                            existingLanguage.InBinaryFile = true;
                        }
                    }
                }
                catch
                {
                    languages.Clear();
                    changed = true;

                    foreach (Language predefinedLanguage in predefinedLanguages)
                    {
                        languages.Add(predefinedLanguage);
                    }

                    // Clear them since they may be used later in this function.
                    binaryLanguages.Clear();
                    binaryAliases.Clear();
                    binaryExtensions.Clear();
                    binaryShebangStrings.Clear();
                    binaryIgnoredExtensions.Clear();

                    // Otherwise ignore the exception and continue.
                }
            }


            Path systemFile  = EngineInstance.Config.SystemConfigFolder + "/Languages.txt";
            Path projectFile = EngineInstance.Config.ProjectConfigFolder + "/Languages.txt";

            Languages_txt languagesTxtParser = new Languages_txt();


            // Load the files.

            if (!languagesTxtParser.Load(systemFile, out systemLanguageList, out ignoredSystemExtensions, errorList))
            {
                success = false;
                // Continue anyway because we want to show errors from both files.
            }

            if (System.IO.File.Exists(projectFile))
            {
                if (!languagesTxtParser.Load(projectFile, out projectLanguageList, out ignoredProjectExtensions, errorList))
                {
                    success = false;
                }
            }
            else
            {
                // The project file not existing is not an error condition.  Fill in the variables with empty structures.
                projectLanguageList      = new List <ConfigFileLanguage>();
                ignoredProjectExtensions = new List <string>();
            }

            if (success == false)
            {
                return(false);
            }


            // Combine the ignored extensions.

            StringSet ignoredExtensions = new StringSet(KeySettingsForExtensions);

            foreach (string extension in ignoredSystemExtensions)
            {
                ignoredExtensions.Add(extension);
            }

            foreach (string extension in ignoredProjectExtensions)
            {
                ignoredExtensions.Add(extension);
            }


            // Add the languages.  We don't need to do separate passes for standard entries and alter entries because alter
            // entries should only appear in the project file and only apply to types in the system file.  Anything else is either an
            // error (system file can't alter a project entry) or would have been simplified out by LoadFile (a file with an alter
            // entry applying to a language in the same file.)  Start_AddLanguage() also prevents inappropriate properties from
            // being set on languages, like Line Comment on one with full language support.

            foreach (ConfigFileLanguage configFileLanguage in systemLanguageList)
            {
                if (!Start_AddLanguage(configFileLanguage, systemFile, true, ignoredExtensions, errorList))
                {
                    success = false;
                }
            }

            foreach (ConfigFileLanguage configFileLanguage in projectLanguageList)
            {
                if (!Start_AddLanguage(configFileLanguage, projectFile, false, ignoredExtensions, errorList))
                {
                    success = false;
                }
            }

            if (success == false)
            {
                return(false);
            }


            // Now that everything's in languages we can delete the ones that weren't in the config files, such as predefined
            // languages that were removed or languages that were in the binary file from the last run but were deleted.  We
            // have to put them on a list and delete them in a second pass because deleting them while iterating through would
            // screw up the iterator.

            List <string> deletedLanguageNames = new List <string>();

            foreach (Language language in languages)
            {
                if (language.InConfigFiles == false)
                {
                    deletedLanguageNames.Add(language.Name);

                    // Check this flag so we don't set it to changed if we're deleting a predefined language that wasn't in the binary
                    // file.
                    if (language.InBinaryFile == true)
                    {
                        changed = true;
                    }
                }
            }

            foreach (string deletedLanguageName in deletedLanguageNames)
            {
                languages.Remove(deletedLanguageName);
            }


            // Everything is okay at this point.  Save the files again to reformat them.  If the project file didn't exist, saving it
            // with the empty structures will create it.

            Start_FixCapitalization(systemLanguageList);
            Start_FixCapitalization(projectLanguageList);

            if (!languagesTxtParser.Save(projectFile, projectLanguageList, ignoredProjectExtensions, errorList, true, false))
            {
                success = false;
            }
            ;

            if (!languagesTxtParser.Save(systemFile, systemLanguageList, ignoredSystemExtensions, errorList, false, true))
            {
                success = false;
            }
            ;


            // Generate alternate comment styles.  We don't want these included in the config files but we do want them in the
            // binary files in case the generation method changes in a future version.

            foreach (Language language in languages)
            {
                if (language.Type == Language.LanguageType.BasicSupport)
                {
                    language.GenerateJavadocCommentStrings();
                    language.GenerateXMLCommentStrings();
                }
            }


            // Compare the structures with the binary ones to see if anything changed.

            if (binaryLanguages.Count != languages.Count ||
                binaryAliases.Count != aliases.Count ||
                binaryExtensions.Count != extensions.Count ||
                binaryShebangStrings.Count != shebangStrings.Count ||
                binaryIgnoredExtensions.Count != ignoredExtensions.Count)
            {
                changed = true;
            }
            else if (changed == false)
            {
                // Do a detailed comparison now.

                foreach (Language binaryLanguage in binaryLanguages)
                {
                    Language language = languages[binaryLanguage.Name];

                    if (language == null || binaryLanguage != language)
                    {
                        changed = true;
                        break;
                    }
                }

                if (changed == false)
                {
                    foreach (string binaryIgnoredExtension in binaryIgnoredExtensions)
                    {
                        if (ignoredExtensions.Contains(binaryIgnoredExtension) == false)
                        {
                            changed = true;
                            break;
                        }
                    }
                }

                if (changed == false)
                {
                    foreach (KeyValuePair <string, int> binaryAliasPair in binaryAliases)
                    {
                        // We can use ID instead of Name because we know they match now.
                        if (aliases.ContainsKey(binaryAliasPair.Key) == false ||
                            aliases[binaryAliasPair.Key].ID != binaryAliasPair.Value)
                        {
                            changed = true;
                            break;
                        }
                    }
                }

                if (changed == false)
                {
                    foreach (KeyValuePair <string, int> binaryExtensionPair in binaryExtensions)
                    {
                        // We can use ID instead of Name because we know they match now.
                        if (extensions.ContainsKey(binaryExtensionPair.Key) == false ||
                            extensions[binaryExtensionPair.Key].ID != binaryExtensionPair.Value)
                        {
                            changed = true;
                            break;
                        }
                    }
                }

                if (changed == false)
                {
                    foreach (KeyValuePair <string, int> binaryShebangStringPair in binaryShebangStrings)
                    {
                        // We can use ID instead of Name because we know they match now.
                        if (shebangStrings.ContainsKey(binaryShebangStringPair.Key) == false ||
                            shebangStrings[binaryShebangStringPair.Key].ID != binaryShebangStringPair.Value)
                        {
                            changed = true;
                            break;
                        }
                    }
                }
            }


            languagesNDParser.Save(EngineInstance.Config.WorkingDataFolder + "/Languages.nd",
                                   languages, aliases, extensions, shebangStrings, ignoredExtensions);


            if (success == true && changed == true)
            {
                EngineInstance.Config.ReparseEverything = true;
            }

            return(success);
        }
예제 #5
0
        /* Function: Start_CantDefinePropertyError
         * A helper function used only by <Start()> and its other helper functions which adds an error saying the passed
         * property cannot be defined for the current language type.
         */
        private void Start_CantDefinePropertyError(ConfigFileLanguage configFileLanguage, Language.LanguageType type,
                                                   Path sourceFile, string propertyName, Errors.ErrorList errorList)
        {
            string typeString;

            if (type == Language.LanguageType.TextFile)
            {
                typeString = "TextFiles";
            }
            else if (type == Language.LanguageType.Container)
            {
                typeString = "Containers";
            }
            else if (type == Language.LanguageType.FullSupport)
            {
                typeString = "FullLanguageSupport";
            }
            else             // BasicSupport
            {
                typeString = "BasicLanguageSupport";
            }

            errorList.Add(
                Locale.Get("NaturalDocs.Engine", "Languages.txt.CantDefinePropertyFor" + typeString + "(property, language)",
                           propertyName, configFileLanguage.Name),
                sourceFile, configFileLanguage.LineNumber
                );
        }
예제 #6
0
        /* Function: Start_AddLanguage
         * A helper function that is used only by <Start()> to add a <ConfigFileLanguage> into <languages>.
         * Returns whether it was able to do so without any errors.
         */
        private bool Start_AddLanguage(ConfigFileLanguage configFileLanguage, Path sourceFile, bool isSystemFile,
                                       StringSet ignoredExtensions, Errors.ErrorList errorList)
        {
            bool success = true;


            // Validate or create the language.

            if (configFileLanguage.AlterLanguage == true)
            {
                // If altering a language that doesn't exist at all, at least not in the config files...
                if (languages.Contains(configFileLanguage.Name) == false ||
                    languages[configFileLanguage.Name].InConfigFiles == false)
                {
                    errorList.Add(
                        Locale.Get("NaturalDocs.Engine", "Languages.txt.AlteredLanguageDoesntExist(name)", configFileLanguage.Name),
                        sourceFile, configFileLanguage.LineNumber
                        );

                    success = false;
                }
            }

            else             // define language, not alter
            {
                // Error if defining a language that already exists in the config files.  Having it exist otherwise is fine.
                if (languages.Contains(configFileLanguage.Name))
                {
                    if (languages[configFileLanguage.Name].InConfigFiles == true)
                    {
                        errorList.Add(
                            Locale.Get("NaturalDocs.Engine", "Languages.txt.LanguageAlreadyExists(name)", configFileLanguage.Name),
                            sourceFile, configFileLanguage.LineNumber
                            );

                        success = false;
                    }
                }
                else
                {
                    Language newLanguage = new Language(this, configFileLanguage.Name);
                    languages.Add(newLanguage);
                }

                if (isSystemFile)
                {
                    languages[configFileLanguage.Name].InSystemFile = true;
                }
                else
                {
                    languages[configFileLanguage.Name].InProjectFile = true;
                }
            }

            if (success == false)
            {
                return(false);
            }


            // Apply the properties.

            Language language = languages[configFileLanguage.Name];

            if (configFileLanguage.SimpleIdentifier != null)
            {
                language.SimpleIdentifier = configFileLanguage.SimpleIdentifier;
            }

            if (configFileLanguage.LineCommentStrings != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Line Comment", errorList);
                    success = false;
                }
                else
                {
                    language.LineCommentStrings = configFileLanguage.LineCommentStrings;
                }
            }

            if (configFileLanguage.BlockCommentStringPairs != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Block Comment", errorList);
                    success = false;
                }
                else
                {
                    language.BlockCommentStringPairs = configFileLanguage.BlockCommentStringPairs;
                }
            }

            if (configFileLanguage.MemberOperator != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport && language.Type != Language.LanguageType.TextFile)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Member Operator", errorList);
                    success = false;
                }
                else
                {
                    language.MemberOperator = configFileLanguage.MemberOperator;
                }
            }

            if (configFileLanguage.LineExtender != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Line Extender", errorList);
                    success = false;
                }
                else
                {
                    language.LineExtender = configFileLanguage.LineExtender;
                }
            }

            if (configFileLanguage.EnumValue != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport && language.Type != Language.LanguageType.TextFile)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Enum Value", errorList);
                    success = false;
                }
                else
                {
                    language.EnumValue = (Language.EnumValues)configFileLanguage.EnumValue;
                }
            }

            if (configFileLanguage.CaseSensitive != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport && language.Type != Language.LanguageType.TextFile)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Case Sensitive", errorList);
                    success = false;
                }
                else
                {
                    language.CaseSensitive = (bool)configFileLanguage.CaseSensitive;
                }
            }

            string[] commentTypeNamesWithPrototypeEnders = configFileLanguage.GetCommentTypeNamesWithPrototypeEnders();

            if (commentTypeNamesWithPrototypeEnders != null)
            {
                if (language.Type != Language.LanguageType.BasicSupport)
                {
                    Start_CantDefinePropertyError(configFileLanguage, language.Type, sourceFile, "Prototype Enders", errorList);
                    success = false;
                }
                else
                {
                    foreach (string commentTypeName in commentTypeNamesWithPrototypeEnders)
                    {
                        CommentTypes.CommentType commentType = EngineInstance.CommentTypes.FromName(commentTypeName);

                        if (commentType == null)
                        {
                            errorList.Add(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.PrototypeEnderCommentTypeDoesntExist(name)", commentTypeName),
                                sourceFile, configFileLanguage.LineNumber
                                );

                            success = false;
                        }
                        else
                        {
                            string[]        prototypeEnderStrings = configFileLanguage.GetPrototypeEnderStrings(commentTypeName);
                            PrototypeEnders prototypeEnders       = new PrototypeEnders(prototypeEnderStrings);
                            language.SetPrototypeEnders(commentType.ID, prototypeEnders);
                        }
                    }
                }
            }


            // Apply the aliases, extensions, and shebang strings.

            if (configFileLanguage.Aliases != null)
            {
                // If using Replace Aliases, find all existing aliases pointing to this language and remove them.
                if (configFileLanguage.AlterLanguage == true && configFileLanguage.AddAliases == false)
                {
                    List <string> removedAliases = new List <string>();

                    foreach (KeyValuePair <string, Language> pair in aliases)
                    {
                        if ((object)pair.Value == (object)language)
                        {
                            removedAliases.Add(pair.Key);
                        }
                    }

                    foreach (string removedAlias in removedAliases)
                    {
                        aliases.Remove(removedAlias);
                    }
                }

                // Add new aliases.
                foreach (string alias in configFileLanguage.Aliases)
                {
                    aliases[alias] = language;
                }
            }

            if (configFileLanguage.Extensions != null)
            {
                // If using Replace Extensions, find all existing extensions pointing to this language and remove them.
                if (configFileLanguage.AlterLanguage == true && configFileLanguage.AddExtensions == false)
                {
                    List <string> removedExtensions = new List <string>();

                    foreach (KeyValuePair <string, Language> pair in extensions)
                    {
                        if ((object)pair.Value == (object)language)
                        {
                            removedExtensions.Add(pair.Key);
                        }
                    }

                    foreach (string removedExtension in removedExtensions)
                    {
                        extensions.Remove(removedExtension);
                    }
                }

                // Add new extensions.
                foreach (string extension in configFileLanguage.Extensions)
                {
                    if (ignoredExtensions.Contains(extension) == false)
                    {
                        extensions[extension] = language;
                    }
                }
            }

            if (configFileLanguage.ShebangStrings != null)
            {
                // If using Replace Shebang Strings, find all existing shebang strings pointing to this language and remove them.
                if (configFileLanguage.AlterLanguage == true && configFileLanguage.AddShebangStrings == false)
                {
                    List <string> removedShebangStrings = new List <string>();

                    foreach (KeyValuePair <string, Language> pair in shebangStrings)
                    {
                        if ((object)pair.Value == (object)language)
                        {
                            removedShebangStrings.Add(pair.Key);
                        }
                    }

                    foreach (string removedShebangString in removedShebangStrings)
                    {
                        shebangStrings.Remove(removedShebangString);
                    }
                }

                // Add new shebang strings.
                foreach (string shebangString in configFileLanguage.ShebangStrings)
                {
                    shebangStrings[shebangString] = language;
                }
            }


            return(success);
        }