[TUTORIAL] Crear una sección de ayuda (de consola) de forma dinámica usando XML

Iniciado por Eleкtro, 5 Enero 2014, 16:44 PM

0 Miembros y 1 Visitante están viendo este tema.

Eleкtro

Este mini-tutorial es sólomente apto para los amantes de las aplicaciones commandline.





¿Les gusta la imagen de arriba?, ¿Creen que pueden mejorarlo?, entonces me alegro mucho ya que les voy a explicar como pueden hacer lo mismo de forma muy sencilla.

Se me ocurrió la idea de darle un poco de 'vida' a las secciones de ayuda de mis aplicaciones así que ideé un metodo de uso genérico ...y a mi parecer creo que quedó sencillo y eficaz.

Los pasos a seguir son estos:

1. Copien y peguen esta Class que contiene la documentación de ayuda, en su proyecto:

Código (vbnet) [Seleccionar]
' Name.......: Help Section
' Author.....: Elektro
' Description: Class that manages the Help documentation of a Console application with colorization capabilities.
' Last Update: 05/01/2014
' References.: LINQ, 'WriteColoredText' method by Elektro.
' Indications: Use *F##* as the ForeColor beginning delimiter, use *-F* to restore the console forecolor.
'              Use *B##* as the BackColor beginning delimiter, use *-B* to restore the console BackColor.


#Region " Usage Examples "

#Region " Example Without Colorization "

'Module Module1

'    Sub Main()

'        Console.Title = HelpSection.Help.<Title>.Value

'        Dim sb As New System.Text.StringBuilder
'        sb.AppendLine(HelpSection.Help.<Logo>.Value)
'        sb.AppendLine(HelpSection.Help.<Separator>.Value)
'        sb.AppendLine(String.Format("    Executable name.......: {0}", HelpSection.Help.<Process>.Value))
'        sb.AppendLine(String.Format("    Application name......: {0}", HelpSection.Help.<Name>.Value))
'        sb.AppendLine(String.Format("    Application version...: {0}", HelpSection.Help.<Version>.Value))
'        sb.AppendLine(String.Format("    Application author....: {0}", HelpSection.Help.<Author>.Value))
'        sb.AppendLine(String.Format("    Application copyright.: {0}", HelpSection.Help.<Copyright>.Value))
'        sb.AppendLine(String.Format("    Author website........: {0}", HelpSection.Help.<Website>.Value))
'        sb.AppendLine(String.Format("    Author Skype..........: {0}", HelpSection.Help.<Skype>.Value))
'        sb.AppendLine(String.Format("    Author Email..........: {0}", HelpSection.Help.<Email>.Value))
'        sb.AppendLine(HelpSection.Help.<Separator>.Value)
'        sb.AppendLine(HelpSection.Help.<Syntax>.Value)
'        sb.AppendLine(HelpSection.Help.<SyntaxExtra>.Value)
'        sb.AppendLine(HelpSection.Help.<UsageExamples>.Value)

'         HelpSection.WriteLine(sb.ToString)

'        Threading.Thread.Sleep(60000)

'    End Sub

'End Module

#End Region

#Region " Example With Colorization "

'Module Module1

'    Sub Main()

'        Console.Title = HelpSection.ColorizedHelp.<Title>.Value

'        Dim sb As New System.Text.StringBuilder
'        sb.AppendLine(HelpSection.ColorizedHelp.<Logo>.Value)
'        sb.AppendLine(HelpSection.ColorizedHelp.<Separator>.Value)
'        sb.AppendLine(String.Format("    Executable name.......: {0}", HelpSection.ColorizedHelp.<Process>.Value))
'        sb.AppendLine(String.Format("    Application name......: {0}", HelpSection.ColorizedHelp.<Name>.Value))
'        sb.AppendLine(String.Format("    Application version...: {0}", HelpSection.ColorizedHelp.<Version>.Value))
'        sb.AppendLine(String.Format("    Application author....: {0}", HelpSection.ColorizedHelp.<Author>.Value))
'        sb.AppendLine(String.Format("    Application copyright.: {0}", HelpSection.ColorizedHelp.<Copyright>.Value))
'        sb.AppendLine(String.Format("    Author website........: {0}", HelpSection.ColorizedHelp.<Website>.Value))
'        sb.AppendLine(String.Format("    Author Skype..........: {0}", HelpSection.ColorizedHelp.<Skype>.Value))
'        sb.AppendLine(String.Format("    Author Email..........: {0}", HelpSection.ColorizedHelp.<Email>.Value))
'        sb.AppendLine(HelpSection.ColorizedHelp.<Separator>.Value)
'        sb.AppendLine(HelpSection.ColorizedHelp.<Syntax>.Value)
'        sb.AppendLine(HelpSection.ColorizedHelp.<SyntaxExtra>.Value)
'        sb.AppendLine(HelpSection.ColorizedHelp.<UsageExamples>.Value)

'        WriteColoredTextLine(sb.ToString, {"*"c})

'        Threading.Thread.Sleep(60000)

'    End Sub

'End Module

#End Region

#End Region

#Region " ConsoleColor Enumeration Helper "

' Black = 0
' DarkBlue = 1
' DarkGreen = 2
' DarkCyan = 3
' DarkRed = 4
' DarkMagenta = 5
' DarkYellow = 6
' Gray = 7
' DarkGray = 8
' Blue = 9
' Green = 10
' Cyan = 11
' Red = 12
' Magenta = 13
' Yellow = 14
' White = 15

#End Region

#Region " HelpSection "

Friend Class HelpSection

#Region " Members "

   ''' <summary>
   ''' Indicates dynamically the name of the current process.
   ''' </summary>
   Private Shared ReadOnly ProcessName As String =
       Process.GetCurrentProcess().MainModule.ModuleName

   ''' <summary>
   ''' Use this var into an XML if need to escape an 'GreaterThan' character.
   ''' </summary>
   Private ReadOnly c_GreaterThan As Char = ">"c

   ''' <summary>
   ''' Use this var into an XML if need to escape an 'LowerThan' character.
   ''' </summary>
   Private ReadOnly c_LowerThan As Char = "<"c

#End Region

#Region " Help Text "

   ''' <summary>
   ''' Contains Help information such as Author, Syntax and Example usages.
   ''' </summary>
   Friend Shared ReadOnly Help As XElement =
<Help>

   <!-- Current process name -->
   <!-- That means even when the user manually changes the executable name -->
   <Process><%= ProcessName %></Process>

   <!-- Application title -->
   <Title>My Application .:: By Elektro ::.</Title>

   <!-- Application name -->
   <Name>My Application</Name>

   <!-- Application author -->
   <Author>Elektro</Author>

   <!-- Application version -->
   <Version>1.0</Version>

   <!-- Copyright information -->
   <Copyright>© Elektro Software 2014</Copyright>

   <!-- Website information -->
   <Website>http://foro.elhacker.net</Website>

   <!-- Skype contact information -->
   <Skype>ElektroStudios</Skype>

   <!-- Email contact information -->
   <Email>ElektroStudios@ElHacker.Net</Email>

   <!-- Application Logotype -->
   <Logo>
   .____                        
   |    |    ____   ____   ____  
   |    |   / _  \ / ___\ /  _ \
   |    |__( |_|  ) /_/  >  |_| )
   |_______ \____/\___  / \____/
           \/     /____/  
   </Logo>

   <!-- Separator shape -->
   <Separator>
   ------------------------------------------------------>>>>
   </Separator>

   <!-- Application Syntax -->
   <Syntax>
   [+] Syntax

       <%= ProcessName %> (SWITCH)=(VALUE) (IN FILE)
   </Syntax>

   <!-- Application Syntax (Additional Specifications) -->
   <SyntaxExtra>
   [+] Switches

       /Switch1  | Description.
       /Switch2  | Description.
                 |
       /?        | Display this help.


   [+] Switch value types

       /Switch1  (INT)
       /Switch2  (X,Y)
   </SyntaxExtra>

   <!-- Application Usage Examples -->
   <UsageExamples>
   [+] Usage examples

       <%= ProcessName %> /Switch1=Value "C:\File.txt"
       ( Command explanation )
   </UsageExamples>

</Help>

   ''' <summary>
   ''' Contains Help information such as Author, Syntax and Example usages.
   ''' These strings are color-delimited to print a colorized output console,
   ''' using the 'WriteColoredText' methods written by Elektro.
   ''' </summary>
   Friend Shared ReadOnly ColorizedHelp As XElement =
<Help>

   <!-- Current process name -->
   <!-- That means even when the user manually changes the executable name -->
   <Process>*F10*<%= ProcessName %>*-F*</Process>

   <!-- Application title -->
   <Title>My Application .:: By Elektro ::.</Title>

   <!-- Application name -->
   <Name>*F10*My Application*-F*</Name>

   <!-- Application author -->
   <Author>*f10*Elektro*-F*</Author>

   <!-- Application version -->
   <Version>*F10*1.0*-F*</Version>

   <!-- Copyright information -->
   <Copyright>*F10*© Elektro Software 2014*-F*</Copyright>

   <!-- Website information -->
   <Website>*F10*http://foro.elhacker.net*-F*</Website>

   <!-- Skype contact information -->
   <Skype>*F10*ElektroStudios*-F*</Skype>

   <!-- Email contact information -->
   <Email>*F10*ElektroStudios@ElHacker.Net*-F*</Email>

   <!-- Application Logotype -->
   <Logo>*F11*
   .____                        
   |    |    ____   ____   ____  
   |    |   / _  \ / ___\ /  _ \
   |    |__( |_|  ) /_/  >  |_| )
   |_______ \____/\___  / \____/
           \/     /____/  
   *-F*</Logo>

   <!-- Separator shape -->
   <Separator>
   *F11*------------------------------------------------------>>>>*-F*
   </Separator>

   <!-- Application Syntax -->
   <Syntax>
   *F11*[+]*-F* *F14*Syntax*-F*

       <%= ProcessName %> *F10*(SWITCH)*-F*=*F10*(VALUE)*-F* *F10*(IN FILE)*-F*
   </Syntax>

   <!-- Application Syntax (Additional Specifications) -->
   <SyntaxExtra>
   *F11*[+]*-F* *F14*Switches*-F*

       *F10*/Switch1*-F*  | *F11*Description.*-F*
       *F10*/Switch2*-F*  | *F11*Description.*-F*
       *F10*        *-F*  |
       *F10*/?      *-F*  | *F11*Display this help.*-F*


   *F11*[+]*-F* *F14*Switch value types*-F*

       *F10*/Switch1*-F*  (*F11*INT*-F*)
       *F10*/Switch2*-F*  (*F11*X,Y*-F*)
   </SyntaxExtra>

   <!-- Application Usage Examples -->
   <UsageExamples>
   *F11*[+]*-F* *F14*Usage examples*-F*

       <%= ProcessName %> /Switch1=Value "C:\File.txt"
       *F11*( Command explanation )*-F*
   </UsageExamples>

</Help>

#End Region

End Class

#End Region


2. Copien y peguen en su proyecto estos métodos para parsear y colorear los strings:

Código (vbnet) [Seleccionar]
#Region " Write Colored Text "

   ' Name.......: Write Colored Text
   ' Author.....: Elektro
   ' Description: Methods to write colorized strings.
   ' Last Update: 05/01/2014
   ' References.: LINQ
   ' Indications: Use *F##* as the ForeColor beginning delimiter, use *-F* to restore the console forecolor.
   '              Use *B##* as the BackColor beginning delimiter, use *-B* to restore the console BackColor.
   '
   ' Example Usages:
   '
   ' WriteColoredText(    " Hello World! ", ConsoleColor.Blue,    ConsoleColor.Blue)
   ' WriteColoredTextLine(" Hello World! ", ConsoleColor.Magenta, ConsoleColor.Gray)
   ' WriteColoredTextLine(" Hello World! ", Nothing,              Nothing)
   '
   ' WriteColoredText("*F10*Hello *F14*World!*-F*", {"*"c})
   ' WriteColoredTextLine("{B15}{F12} Hello World! {-F}{-B}", {"{"c, "}"c})
   ' WriteColoredTextLine(String.Format("*B15**F12* {0} *F0*{1} *-F**-B*", "Hello", "World!"), {"*"c})

   ''' <summary>
   ''' Writes colored text on the Console.
   ''' </summary>
   ''' <param name="Text">Indicates the color-delimited text to parse and then write.</param>
   ''' <param name="Delimiters">Indicates a set of (1 or 2) delimiters to parse a color-delimited string.</param>
   Friend Sub WriteColoredText(ByVal Text As String,
                               ByVal Delimiters As Char())

       ' Store the current console colors to restore them later.
       Dim CurrentForegroundColor As ConsoleColor = Console.ForegroundColor
       Dim CurrentBackgroundColor As ConsoleColor = Console.BackgroundColor

       ' Split the string to retrieve and parse the color-delimited strings.
       Dim StringParts As String() =
           Text.Split(Delimiters, StringSplitOptions.RemoveEmptyEntries)

       ' Parse the string parts
       For Each part As String In StringParts

           If part.ToUpper Like "F#" _
           OrElse part.ToUpper Like "F##" Then ' Change the ForeColor.

               Console.ForegroundColor = CInt(part.Substring(1))

           ElseIf part.ToUpper Like "B#" _
           OrElse part.ToUpper Like "B##" Then ' Change the BackgroundColor.

               Console.BackgroundColor = CInt(part.Substring(1))

           ElseIf part.ToUpper Like "-F" Then  ' Restore the original Forecolor.

               Console.ForegroundColor = CurrentForegroundColor

           ElseIf part.ToUpper Like "-B" Then ' Restore the original BackgroundColor.

               Console.BackgroundColor = CurrentBackgroundColor

           Else ' String part is not a delimiter so we can print it.

               Console.Write(part)

           End If

       Next part

       ' Finish by restoring the original console colors.
       Console.BackgroundColor = CurrentBackgroundColor
       Console.ForegroundColor = CurrentForegroundColor

   End Sub

   ''' <summary>
   ''' Writes colored text on the Console.
   ''' </summary>
   ''' <param name="Text">Indicates the text to write.</param>
   ''' <param name="ForeColor">Indicates the text color.</param>
   ''' <param name="BackColor">Indicates the background color.</param>
   Friend Sub WriteColoredText(ByVal Text As String,
                               ByVal ForeColor As ConsoleColor,
                               ByVal BackColor As ConsoleColor)

       ' Store the current console colors to restore them later.
       Dim CurrentForegroundColor As ConsoleColor = Console.ForegroundColor
       Dim CurrentBackgroundColor As ConsoleColor = Console.BackgroundColor

       ' Set the new temporal console colors.
       Console.ForegroundColor = If(ForeColor = Nothing, CurrentForegroundColor, ForeColor)
       Console.BackgroundColor = If(BackColor = Nothing, CurrentBackgroundColor, BackColor)

       ' Print the text.
       Console.Write(Text)

       ' Finish by restoring the original console colors.
       Console.ForegroundColor = CurrentForegroundColor
       Console.BackgroundColor = CurrentBackgroundColor

   End Sub

   ''' <summary>
   ''' Writes colored text on the Console and adds an empty line at the end.
   ''' </summary>
   ''' <param name="Text">Indicates the color-delimited text to parse and then write.</param>
   ''' <param name="Delimiters">Indicates a set of (1 or 2) delimiters to parse a color-delimited string.</param>
   Friend Sub WriteColoredTextLine(ByVal Text As String,
                                   ByVal Delimiters As Char())

       WriteColoredText(Text & Environment.NewLine, Delimiters)

   End Sub

   ''' <summary>
   ''' Writes colored text on the Console and adds an empty line at the end.
   ''' </summary>
   ''' <param name="Text">Indicates the color-delimited text to parse and then write.</param>
   ''' <param name="ForeColor">Indicates the text color.</param>
   ''' <param name="BackColor">Indicates the background color.</param>
   Friend Sub WriteColoredTextLine(ByVal Text As String,
                                   ByVal ForeColor As ConsoleColor,
                                   ByVal BackColor As ConsoleColor)

       WriteColoredText(Text & Environment.NewLine, ForeColor, BackColor)

   End Sub

#End Region



3. En la sección regionada 'Help Text' deben especificar lo que deseen, el logo, la sintaxis, la información de contacto, etc... eso es lo único que deben hardcodear (óbviamente no va a ser un click&go, pues toda aplicación tiene distintos parámetros así pues distinta información).

Por ejemplo, inspeccionemos este nodo:
Código (xml) [Seleccionar]
   <!-- Application Usage Examples -->
   <UsageExamples>
   {f11}[+]{-f} {f14}Usage examples{-f}

       <%= ProcessName %> /Switch1=Value "C:\File.txt"
       {f11}( Command explanation ){-f}
   </UsageExamples>


¿Que significan todos esos parámetros 'F'?, bien, son los delimitadores que establecí para indicar el principio y el fínal de un cambio de color (color de texto o color de fondo),
un cambio de color de texto debe empezar con la letra "F" (de Forecolor), y un cambio de color de fondo debe empezar con la letra "B" (de BackgroundColor),
seguídamente le añadiremos un número del 0-15 que hace referencia a un color de consola (solo existen 15), por ejemplo: el inicio de cambio de color de texto "{F11}" hace referencia al color de consola número 11, que es el color 'Cyan'

Para restaurar el color original usaremos el delimitador {-f} o {-b} respectívamente del tipo de cambio de color del que se trate.

Y para mostrar el texto coloreado es necesario usar un método que ideé el cual se encarga de parsear los delimitadores de cambio de colores.


Un ejemplo de uso de los método:

Código (vbnet) [Seleccionar]
Module Module1

   Sub Main()

       Console.Title = HelpSection.ColorizedHelp.<Title>.Value

       Dim sb As New System.Text.StringBuilder
       sb.AppendLine(HelpSection.ColorizedHelp.<Logo>.Value)
       sb.AppendLine(HelpSection.ColorizedHelp.<Separator>.Value)
       sb.AppendLine(HelpSection.ColorizedHelp.<Syntax>.Value)
       sb.AppendLine(HelpSection.ColorizedHelp.<UsageExamples>.Value)

       WriteColoredTextLine(sb.ToString, {"*"c})
       ' WriteColoredText(sb.ToString, {"*"c})

       Threading.Thread.Sleep(60000)

   End Sub

End Module


Además, los métodos son de uso genérico y hay 1 overload para los dos métodos, esto significa que pueden reutilizarlos de forma individual en cualquier otro tipo de proyecto, de la siguiente manera:
Código (vbnet) [Seleccionar]

WriteColoredText(" Hello World! ", ConsoleColor.Blue, ConsoleColor.Blue)
WriteColoredTextLine(" Hello World! ", ConsoleColor.Magenta, ConsoleColor.Gray)
WriteColoredTextLine(" Hello World! ", Nothing, Nothing)

WriteColoredText("*F10*Hello *F14*World!*-F*", {"*"c})
WriteColoredTextLine("{B15}{F12} Hello World! {-F}{-B}", {"{"c, "}"c})
WriteColoredTextLine(String.Format("*B15**F12* {0} *F0*{1} *-F**-B*", "Hello", "World!"), {"*"c})


Eso es todo, ¿te resultó facil?, espero que este mini-tutorial le haya servido a alguien.

Saludos!