Example #1
0
		static bool BuildCodeSnippetsTxt(string SamplesDir, BuildActions Actions)
		{
			if ((Actions & BuildActions.Clean) != 0)
			{
				APISnippets.CleanAllFiles();
			}
			if ((Actions & BuildActions.Build) == 0)
			{
				return true;
			}

			//We should be able to trim this down further.
			DirectoryInfo Dir = new DirectoryInfo(SamplesDir);
			List<string> Files = new List<string>();
			foreach (string FileName in Directory.GetFiles(SamplesDir, "*.cpp", SearchOption.AllDirectories))
			{
				if (!FileName.EndsWith(".generated.cpp"))
				{
					Files.Add(FileName);
				}
			}
			foreach (string FileName in Directory.GetFiles(SamplesDir, "*.h", SearchOption.AllDirectories))
			{
				if (!FileName.EndsWith(".generated.h"))
				{
					Files.Add(FileName);
				}
			}

			//Do the harvesting work.
			{
				const string OpeningTag = "///CODE_SNIPPET_START:";
				const string ClosingTag = "///CODE_SNIPPET_END";
				const string SeeTag = "@see";
				APISnippets Snippets = new APISnippets();
				List<string> CurrentSnippetPageNames = new List<string>(4);		//Probably won't have a snippet that is shared by more than four different pages.
				List<string> SeePageNames = new List<string>(4);				//More than four of these on one line will probably not happen.
				string CurrentLine;
				char[] WhiteSpace = {' ', '\t'};		//Doubles as our token delimiter in one place - noted in comments.
				string[] ClassMemberDelimiters = new string[2] { "::", "()" };
				bool IsSnippetBeingProcessed = false;
				bool WasPreviousLineBlank = false;		//Two blank lines in a row will end a code block. Don't allow this to happen in a single snippet.

				foreach (string FileName in Files)
				{
					// Read the file and display it line by line.
					System.IO.StreamReader file = new System.IO.StreamReader(FileName);
					int LineNumber = 0;
					while ((CurrentLine = file.ReadLine()) != null)
					{
						++LineNumber;
						CurrentLine = CurrentLine.TrimStart(WhiteSpace);
						if (!CurrentLine.Contains(OpeningTag))
						{
							continue;
						}
						CurrentSnippetPageNames = CurrentLine.Split(WhiteSpace, StringSplitOptions.RemoveEmptyEntries).ToList<string>();		//Whitespace is used to delimit our API/snippet page names here.
						while ((CurrentSnippetPageNames.Count > 0) && (!CurrentSnippetPageNames[0].Contains(OpeningTag)))
						{
							CurrentSnippetPageNames.RemoveAt(0);											//Remove everything before the opening tag.
						}
						if (CurrentSnippetPageNames.Count > 0)
						{
							CurrentSnippetPageNames.RemoveAt(0);											//Remove the opening tag, which is always in position 0 by this point.
						}
						if (CurrentSnippetPageNames.Count < 1)
						{
							Console.WriteLine("Error: OpeningTag for snippet harvesting found without any API pages specified.");
							return false;
						}

						IsSnippetBeingProcessed = true;
						foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
						{
							Snippets.AddSnippet(CurrentSnippetPageName);
							if (!Snippets.AddSnippetText(CurrentSnippetPageName, "**" + Path.GetFileName(FileName) + "** at line " + LineNumber + ":" + Environment.NewLine + Environment.NewLine))
							{
								Console.WriteLine("Error: Failed to add header text to snippet for " + CurrentSnippetPageName + " from source file " + FileName + " at line " + LineNumber);
								return false;
							}
						}
						bool FinishSnippetAfterThisLine = false;
						while ((CurrentLine = file.ReadLine()) != null)
						{
							++LineNumber;
							string TrimmedLine = CurrentLine.TrimStart(WhiteSpace);		//This is actually a C# same-line whitespace check, not our token delimiters.
							string TrimmedLineLower = TrimmedLine.ToLower();
							if (TrimmedLine.Contains(OpeningTag))
							{
								//Snippets do not currently support overlapping. If they did, closing tags should be explicit about which entries are ending, and we'd need to skip lines with opening tags.
								Console.WriteLine("Error: Nested OpeningTag found in " + FileName + " at line " + LineNumber + "! This is not supported. Snippet harvesting process will fail.");
								return false;
							}
							else if (TrimmedLine.StartsWith(ClosingTag))
							{
								//We're done with this snippet now. Mark that we can end cleanly.
								IsSnippetBeingProcessed = false;
								foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
								{
									Snippets.FinishCurrentSnippet(CurrentSnippetPageName);
								}
								break;
							}
							else if (TrimmedLine.Contains(ClosingTag))
							{
								//We will be done this snippet once we add this line (minus the tag).
								FinishSnippetAfterThisLine = true;
								CurrentLine = CurrentLine.Replace(ClosingTag, "//");
							}
							for (int TrimmedLineStartingIndex = TrimmedLineLower.IndexOf(SeeTag); TrimmedLineStartingIndex >= 0; TrimmedLineStartingIndex = TrimmedLineLower.Substring(TrimmedLineStartingIndex + SeeTag.Length).Contains(SeeTag) ? (TrimmedLineStartingIndex + SeeTag.Length + TrimmedLineLower.Substring(TrimmedLineStartingIndex + SeeTag.Length).IndexOf(SeeTag)) : -2)
							{
								int FirstCharacter = TrimmedLineStartingIndex + SeeTag.Length;
								SeePageNames = TrimmedLine.Substring(FirstCharacter).Split(WhiteSpace, StringSplitOptions.RemoveEmptyEntries).ToList<string>();		//Whitespace is used to delimit our API/snippet page names here.

								if (SeePageNames.Count > 0)
								{
									string SeeText = SeePageNames[0];
									string[] SeeTextBreakdown = SeeText.Split(ClassMemberDelimiters, StringSplitOptions.RemoveEmptyEntries);
									foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
									{
										if (SeeTextBreakdown.Length == 2)
										{
											//This is considered "class::member" format.
											if (!Snippets.AddSeeText(CurrentSnippetPageName, "1. [](API:" + SeeText + ")" + Environment.NewLine))
											{
												Console.WriteLine("Error: Failed to add text to snippet's \"See Also\" portion for " + CurrentSnippetPageName + " from source file " + FileName + " at line " + LineNumber);
												return false;
											}
										}
										else
										{
											if (!Snippets.AddSeeText(CurrentSnippetPageName, "1. [](" + SeeText + ")" + Environment.NewLine))
											{
												Console.WriteLine("Error: Failed to add text to snippet's \"See Also\" portion for " + CurrentSnippetPageName + " from source file " + FileName + " at line " + LineNumber);
												return false;
											}
										}
									}
								}
							}

							if (CurrentLine.Trim().Length < 1)
							{
								if (WasPreviousLineBlank)
								{
									//Two (or more) blank lines in a row! Not permitted.
									continue;
								}
								else
								{
									WasPreviousLineBlank = true;
								}
							}
							else
							{
								WasPreviousLineBlank = false;
							}

							//This line should be added to the snippet(s) named in the "CODE_SNIPPET_START" line. Capture it. We need to add our own newline.
							foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
							{
								if (!Snippets.AddSnippetText(CurrentSnippetPageName, '\t' + CurrentLine + Environment.NewLine))
								{
									Console.WriteLine("Error: Failed to add text to snippet for " + CurrentSnippetPageName + " from source file " + FileName + " at line " + LineNumber);
									return false;
								}
							}
							if (FinishSnippetAfterThisLine)
							{
								IsSnippetBeingProcessed = false;
								foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
								{
									Snippets.FinishCurrentSnippet(CurrentSnippetPageName);
								}
								break;
							}
						}
					}
					//If we hit the end of the file while harvesting a snippet, we should fail or have a warning. We could also just ignore the failure to end cleanly and just store the text as-is.
					//Opting for outright failure at the moment so that these errors don't go unnoticed.
					if (IsSnippetBeingProcessed)
					{
						Console.WriteLine("Code snippet start tag not matched with code snippet end tag in " + FileName);
						return false;
					}
					file.Close();
				}

				if (!Snippets.WriteSnippetsToFiles())
				{
					Console.WriteLine("Error writing intermediate snippet files.");
					return false;
				}
			}
			//Completed without error.
			return true;
		}
Example #2
0
        static bool BuildCodeSnippetsTxt(string SamplesDir, BuildActions Actions)
        {
            if ((Actions & BuildActions.Clean) != 0)
            {
                APISnippets.CleanAllFiles();
            }
            if ((Actions & BuildActions.Build) == 0)
            {
                return true;
            }

            //We should be able to trim this down further.
            DirectoryInfo Dir = new DirectoryInfo(SamplesDir);
            List<string> Files = new List<string>();
            foreach (string FileName in Directory.GetFiles(SamplesDir, "*.cpp", SearchOption.AllDirectories))
            {
                if (!FileName.EndsWith(".generated.cpp"))
                {
                    Files.Add(FileName);
                }
            }
            foreach (string FileName in Directory.GetFiles(SamplesDir, "*.h", SearchOption.AllDirectories))
            {
                if (!FileName.EndsWith(".generated.h"))
                {
                    Files.Add(FileName);
                }
            }

            //Do the harvesting work.
            {
                const string OpeningTag = "///CODE_SNIPPET_START:";
                const string ClosingTag = "///CODE_SNIPPET_END";
                APISnippets Snippets = new APISnippets();
                List<string> CurrentSnippetPageNames = new List<string>(4);		//Probably won't have a snippet that is shared by more than four different pages.
                string CurrentLine;
                char[] WhiteSpace = {' ', '\t'};		//Doubles as our token delimiter in one place - noted in comments.
                bool IsSnippetBeingProcessed = false;
                bool WasPreviousLineBlank = false;		//Two blank lines in a row will end a code block. Don't allow this to happen in a single snippet.

                foreach (string FileName in Files)
                {
                    // Read the file and display it line by line.
                    System.IO.StreamReader file = new System.IO.StreamReader(FileName);
                    while ((CurrentLine = file.ReadLine()) != null)
                    {
                        CurrentLine = CurrentLine.TrimStart(WhiteSpace);
                        if (!CurrentLine.StartsWith(OpeningTag))
                        {
                            continue;
                        }
                        CurrentSnippetPageNames = CurrentLine.Split(WhiteSpace).ToList<string>();		//Whitespace is used to delimit our API/snippet page names here.
                        CurrentSnippetPageNames.RemoveAt(0);											//Remove the opening tag, which is always in position 0 after empties have been cleared out.
                        CurrentSnippetPageNames.RemoveAll(entry => (entry.Length < 1));					//Blank entries can show up in the list. Remove them.
                        if (CurrentSnippetPageNames.Count < 1)
                        {
                            Console.WriteLine("Warning: OpeningTag for snippet harvesting found without any API pages specified.");
                            continue;
                        }

                        IsSnippetBeingProcessed = true;
                        foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
                        {
                            Snippets.AddSnippet(CurrentSnippetPageName);
                        }
                        while ((CurrentLine = file.ReadLine()) != null)
                        {
                            string TrimmedLine = CurrentLine.TrimStart(WhiteSpace);		//This is actually a C# same-line whitespace check, not our token delimiters.
                            if (TrimmedLine.StartsWith(OpeningTag))
                            {
                                //Snippets do not currently support overlapping. If they did, closing tags should be explicit about which entries are ending, and we'd need to skip lines with opening tags.
                                Console.WriteLine("Error: Nested OpeningTag found! This is not supported. Snippet harvesting process will fail.");
                                return false;
                            }
                            else if (TrimmedLine.StartsWith(ClosingTag))
                            {
                                //We're done with this snippet now. Mark that we can end cleanly.
                                IsSnippetBeingProcessed = false;
                                break;
                            }
                            if (CurrentLine.Trim().Length < 1)
                            {
                                if (WasPreviousLineBlank)
                                {
                                    //Two (or more) blank lines in a row! Not permitted.
                                    continue;
                                }
                                else
                                {
                                    WasPreviousLineBlank = true;
                                }
                            }
                            else
                            {
                                WasPreviousLineBlank = false;
                            }

                            //This line should be added to the snippet(s) named in the "CODE_SNIPPET_START" line. Capture it. We need to add our own newline.
                            foreach (string CurrentSnippetPageName in CurrentSnippetPageNames)
                            {
                                if (!Snippets.AddSnippetText(CurrentSnippetPageName, CurrentLine + Environment.NewLine))
                                {
                                    Console.WriteLine("Error adding text to snippet for " + CurrentSnippetPageName);
                                    return false;
                                }
                            }
                        }
                    }
                    //If we hit the end of the file while harvesting a snippet, we should fail or have a warning. We could also just ignore the failure to end cleanly and just store the text as-is.
                    //Opting for outright failure at the moment so that these errors don't go unnoticed.
                    if (IsSnippetBeingProcessed)
                    {
                        Console.WriteLine("Code snippet start tag not matched with code snippet end tag in " + FileName);
                        return false;
                    }
                    file.Close();
                }

                if (!Snippets.WriteSnippetsToFiles())
                {
                    Console.WriteLine("Error writing intermediate snippet files.");
                    return false;
                }
            }
            //Completed without error.
            return true;
        }