//[TestMethod]
        public void VivadoCommandRecordTest()
        {
            var log = new VivadoCommandLog();

            var paramTypes = new List <string>()
            {
                "[-optional_flag]",
                "[<optional_name> <arg>]",
                "<required_value>",
                "[<patterns>...]",
                "<required_name> <arg>",
                "[<optional_value>]",
            };

            var fixes = new VivadoTCLFixes();

            foreach (var p in paramTypes)
            {
                var lines = new List <string>()
                {
                    "test_command",
                    "Syntax",
                    $"test_command {p}"
                };

                var record = new VivadoCommandRecord(log, fixes, "test_command", new VivdoCommandTextLines()
                {
                    Lines = lines
                });
            }
        }
        void GenerateVivadoTCLCategoriesBuilder(VivadoGeneratorContext generatorContext)
        {
            var generatedPath = generatorContext.generatedPath;
            var commandsData  = generatorContext.commandsData;

            foreach (var pair in generatorContext.mapCategoryToCommands)
            {
                var(category, commands) = pair;

                var builder = new IndentedStringBuilder();
                using (Header(builder))
                {
                    builder.AppendLine($"using Quokka.TCL.Tools;");
                    builder.AppendLine($"using System.Collections.Generic;");
                    builder.AppendLine("namespace Quokka.TCL.Vivado");
                    using (builder.CodeBlock())
                    {
                        builder.AppendLine($"public partial class {category}Commands<TTCL> where TTCL : TCLFile");
                        using (builder.CodeBlock())
                        {
                            builder.AppendLine($"private readonly TTCL _tcl;");
                            builder.AppendLine($"private readonly VivadoTCLBuilder _builder;");
                            builder.AppendLine($"public {category}Commands(TTCL tcl, VivadoTCLBuilder builder)");
                            using (builder.CodeBlock())
                            {
                                builder.AppendLine($"_tcl = tcl;");
                                builder.AppendLine($"_builder = builder;");
                            }

                            foreach (var command in commands.OrderBy(c => c))
                            {
                                var commandData = commandsData[command];
                                var record      = new VivadoCommandRecord(generatorContext.Log, generatorContext.Fixes, command, commandData);

                                GenerateCommandCall(record, builder, "TTCL", "_tcl");
                            }
                        }
                    }
                }

                var filePath = Path.Combine(generatedPath, $"{category}.cs");
                File.WriteAllText(filePath, builder.ToString());
            }
        }
        void GenerateCommandCall(
            VivadoCommandRecord record,
            IndentedStringBuilder builder,
            string returnType,
            string target)
        {
            GenerateCommandDocumentation(record, builder);

            var orderedParameters = record.orderedParameters;
            var args = MethodArguments(orderedParameters);

            var argsForward = orderedParameters.Select(a => a.CSName);

            builder.AppendLine($"public {returnType} {record.Name}({string.Join(", ", args)})");

            using (builder.CodeBlock())
            {
                builder.AppendLine($"// TCL Syntax: {record.Syntax}");
                builder.AppendLine($"{target}.Entry(_builder.{record.Name}({string.Join(", ", argsForward)}));");
                builder.AppendLine($"return {target};");
            }
        }
        void GenerateVivadoFlatTCL(VivadoGeneratorContext generatorContext)
        {
            var generatedPath = generatorContext.generatedPath;

            var vivadoTCL = new IndentedStringBuilder();

            using (Header(vivadoTCL))
            {
                vivadoTCL.AppendLine($"using Quokka.TCL.Tools;");
                vivadoTCL.AppendLine($"using System.Collections.Generic;");
                vivadoTCL.AppendLine("namespace Quokka.TCL.Vivado");
                using (vivadoTCL.CodeBlock())
                {
                    vivadoTCL.AppendLine($"public partial class VivadoTCL : FluentVivadoTCLFile<VivadoTCL>");
                    using (vivadoTCL.CodeBlock())
                    {
                        vivadoTCL.AppendLine($"public VivadoTCL(VivadoTCLBuilder builder = null) : base(builder)");
                        using (vivadoTCL.CodeBlock())
                        {
                        }

                        foreach (var command in generatorContext.commandsSet.OrderBy(c => c))
                        {
                            var commandData = generatorContext.commandsData[command];
                            var record      = new VivadoCommandRecord(generatorContext.Log, generatorContext.Fixes, command, commandData);

                            GenerateCommandCall(record, vivadoTCL, "VivadoTCL", "this");
                        }
                    }
                }
            }

            var vivadoTCLFilePath = Path.Combine(generatedPath, $"VivadoTCL.cs");

            File.WriteAllText(vivadoTCLFilePath, vivadoTCL.ToString());
        }
        void GenerateCommandDocumentation(
            VivadoCommandRecord record,
            IndentedStringBuilder builder)
        {
            builder.AppendLine($"/// <summary>");
            builder.AppendDocumentationLinesIfAny(record.ShortDescription.Escaped());
            builder.AppendDocumentationSeparator();
            builder.AppendLine($"/// TCL Syntax: {record.Syntax.Escaped()}");
            builder.AppendDocumentationSeparator();
            builder.AppendDocumentationLinesIfAny(record.Description.Escaped());
            builder.AppendDocumentationLinesIfAny(record.Examples.Escaped());
            builder.AppendDocumentationLines($"See {pdfName}, page {record.CommandData.Page}");
            builder.AppendLine($"/// </summary>");

            var orderedParameters = record.orderedParameters;

            foreach (var arg in orderedParameters)
            {
                var descriptionLines = new List <string>();

                switch (arg.Usage)
                {
                case VivadoCommandParameterUsage.Optional:
                    descriptionLines.Add("(Optional)");
                    break;

                case VivadoCommandParameterUsage.Required:
                    descriptionLines.Add("(Required)");
                    break;
                }

                descriptionLines.AddRange(arg.Description);

                // make single description line if it is short
                if (descriptionLines.Sum(l => l.Length) < 80)
                {
                    descriptionLines = new List <string>()
                    {
                        string.Join(" ", descriptionLines)
                    };
                }

                switch (descriptionLines.Count)
                {
                case 1:
                    builder.AppendLine($"/// <param name=\"{arg.ParamName}\">{descriptionLines[0].Escaped()}</param>");
                    break;

                default:
                    builder.AppendLine($"/// <param name=\"{arg.ParamName}\">");
                    builder.AppendDocumentationLines(descriptionLines.Escaped());
                    builder.AppendLine($"/// </param>");
                    break;
                }
            }

            if (record.Returns.Any())
            {
                builder.AppendDocumentationSection("returns", record.Returns.Escaped());
            }
        }
        void GenerateVivadoTCLBuilder(VivadoGeneratorContext generatorContext)
        {
            var generatedPath = generatorContext.generatedPath;
            var commandsData  = generatorContext.commandsData;

            var commandsBuilder = new IndentedStringBuilder();

            using (Header(commandsBuilder))
            {
                commandsBuilder.AppendLine($"using Quokka.TCL.Tools;");
                commandsBuilder.AppendLine($"using System.Collections.Generic;");
                commandsBuilder.AppendLine("namespace Quokka.TCL.Vivado");
                using (commandsBuilder.CodeBlock())
                {
                    foreach (var command in commandsData.Keys.OrderBy(k => k))
                    {
                        var commandData = commandsData[command];
                        var record      = new VivadoCommandRecord(generatorContext.Log, generatorContext.Fixes, command, commandData);
                        foreach (var p in record.Parameters.Where(t => t.EnumValues.Any()))
                        {
                            commandsBuilder.AppendLine($"public enum {record.Name}_{p.Name}");
                            using (commandsBuilder.CodeBlock())
                            {
                                foreach (var value in p.EnumValues)
                                {
                                    if (StaticData.keywords.Contains(value))
                                    {
                                        commandsBuilder.AppendLine($"[TCLWrite(\"{value}\")]");
                                        commandsBuilder.AppendLine($"{value.ToUpper()},");
                                        continue;
                                    }


                                    if (value.Contains(" ") || value.Contains("-"))
                                    {
                                        commandsBuilder.AppendLine($"[TCLWrite(\"{value}\")]");
                                        var langValue = Regex.Replace(value, @"[ \-]", "_");
                                        commandsBuilder.AppendLine($"{langValue},");
                                        continue;
                                    }

                                    if (value == "0")
                                    {
                                        commandsBuilder.AppendLine($"[TCLWrite(\"0\")]");
                                        commandsBuilder.AppendLine($"ZERO,");
                                        continue;
                                    }

                                    if (value == "1")
                                    {
                                        commandsBuilder.AppendLine($"[TCLWrite(\"1\")]");
                                        commandsBuilder.AppendLine($"ONE,");
                                        continue;
                                    }

                                    commandsBuilder.AppendLine($"{value},");
                                }
                            }
                        }
                    }

                    commandsBuilder.AppendLine($"public partial class VivadoTCLBuilder");
                    using (commandsBuilder.CodeBlock())
                    {
                        foreach (var command in commandsData.Keys.OrderBy(k => k))
                        {
                            var commandData = commandsData[command];
                            var record      = new VivadoCommandRecord(generatorContext.Log, generatorContext.Fixes, command, commandData);

                            GenerateCommandDeclaration(record, commandsBuilder);
                        }
                    }
                }
            }

            var commandsBuilderPath = Path.Combine(generatedPath, $"VivadoTCLBuilder.cs");

            File.WriteAllText(commandsBuilderPath, commandsBuilder.ToString());
        }
        void GenerateCommandDeclaration(
            VivadoCommandRecord record,
            IndentedStringBuilder builder)
        {
            GenerateCommandDocumentation(record, builder);

            var orderedParameters = record.orderedParameters;
            var args = MethodArguments(orderedParameters);

            builder.AppendLine($"public virtual SimpleTCLCommand {record.Name}({string.Join(", ", args)})");
            using (builder.CodeBlock())
            {
                builder.AppendLine($"// TCL Syntax: {record.Syntax}");
                builder.AppendLine($"return");

                using (builder.Indent())
                {
                    builder.AppendLine($"new SimpleTCLCommand(\"{record.Name}\")");
                    using (builder.Indent())
                    {
                        foreach (var arg in record.Parameters)
                        {
                            var argMethodParts = new List <string>();
                            if (arg.Usage == VivadoCommandParameterUsage.Optional)
                            {
                                argMethodParts.Add("Optional");
                            }
                            else
                            {
                                argMethodParts.Add("Required");
                            }

                            if (arg.IsNamed)
                            {
                                argMethodParts.Add("Named");
                            }

                            //if (arg.EnumName != null)
                            //    argMethodParts.Add("Enum");
                            if (arg.Type == VivadoCommandParameterType.Object)
                            {
                                argMethodParts.Add("Object");
                            }
                            else if (arg.Type == VivadoCommandParameterType.Flag)
                            {
                                argMethodParts.Add("Flag");
                            }
                            else if (arg.Type == VivadoCommandParameterType.Enum)
                            {
                                argMethodParts.Add("Enum");
                            }
                            else
                            {
                                argMethodParts.Add(arg.ElementType.Name);
                            }

                            if (arg.IsArray)
                            {
                                argMethodParts.Add("List");
                            }

                            var methodName = string.Join("", argMethodParts);

                            var fileArgumentNames = new HashSet <string>()
                            {
                                "file_name",
                                "files",
                                "dir",
                                "path"
                            };

                            var argValue = arg.CSName;
                            if (fileArgumentNames.Contains(arg.Name))
                            {
                                argValue = $"FileName({arg.CSName})";
                            }

                            builder.AppendLine($".{methodName}(\"{arg.Name}\", {argValue})");
                        }
                    }
                }

                builder.AppendLine($";");
            }
        }