X-Git-Url: http://nitlanguage.org diff --git a/lib/console.nit b/lib/console.nit index d032886..3333cad 100644 --- a/lib/console.nit +++ b/lib/console.nit @@ -18,10 +18,153 @@ module console # A ANSI/VT100 escape sequence. abstract class TermEscape # The US-ASCII ESC character. - protected fun esc: Char do return 27.ascii + protected fun esc: Char do return 27.code_point + + # The Control Sequence Introducer (CSI). + protected fun csi: String do return "{esc}[" +end + +# Abstract class of the ANSI/VT100 escape sequences for directional moves. +abstract class TermDirectionalMove + super TermEscape + + # The length of the move. + var magnitude: Int = 1 is protected writable + + redef fun to_s do + if magnitude == 1 then return "{csi}{code}" + return "{csi}{magnitude}{code}" + end + + # The code of the command. + protected fun code: String is abstract +end + +# ANSI/VT100 code to move the cursor up by `magnitude` rows (CUU). +class TermMoveUp + super TermDirectionalMove + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "A" +end + +# ANSI/VT100 code to move the cursor down by `magnitude` rows (CUD). +class TermMoveDown + super TermDirectionalMove + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "B" +end + +# ANSI/VT100 code to move the cursor forward by `magnitude` columns (CUF). +class TermMoveFoward + super TermDirectionalMove + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "C" +end + +# ANSI/VT100 code to move the cursor backward by `magnitude` columns (CUB). +class TermMoveBackward + super TermDirectionalMove + + # Move by the specified number of cells. + init by(magnitude: Int) do self.magnitude = magnitude + + redef fun code do return "D" end -# ANSI/VT100 code to switch character attributes (SGR). +# ANSI/VT100 code to move the cursor at the specified position (CUP). +class TermMove + super TermEscape + + # Vertical position. + # + # 1 is the top. + var row: Int = 1 + + # Horizontal position. + # + # 1 is the left. + var column: Int = 1 + + # Move at the specified position. + # + # (1, 1) is the top-left corner of the display. + init at(row: Int, column: Int) do + self.row = row + self.column = column + end + + redef fun to_s do + if row == 1 then + if column == 1 then return "{csi}H" + return "{csi};{column}H" + else + if column == 1 then return "{csi}{row}H" + return "{csi}{row};{column}H" + end + end +end + +# ANSI/VT100 code to clear from the cursor to the end of the screen (ED 0). +class TermEraseDisplayDown + super TermEscape + redef fun to_s do return "{csi}J" +end + +# ANSI/VT100 code to clear from the cursor to the beginning of the screen (ED 1). +class TermEraseDisplayUp + super TermEscape + redef fun to_s do return "{csi}1J" +end + +# ANSI/VT100 code to clear the entire display and move the cursor to the top left of screen (ED 2). +# +# Note: Some terminals always move the cursor when the screen is cleared. So we +# force this behaviour to ensure interoperability of the code. +class TermClearDisplay + super TermEscape + redef fun to_s do return "{csi}2J{csi}H" +end + +# ANSI/VT100 code to erase anything after the cursor in the line (EL 0). +class TermEraseLineFoward + super TermEscape + redef fun to_s do return "{csi}K" +end + +# ANSI/VT100 code to erase anything before the cursor in the line (EL 1). +class TermEraseLineBackward + super TermEscape + redef fun to_s do return "{csi}1K" +end + +# ANSI/VT100 code to clear everything in the current line (EL 2). +class TermClearLine + super TermEscape + redef fun to_s do return "{csi}2K" +end + +# ANSI/VT100 code to save the current cursor position (SCP). +class TermSaveCursor + super TermEscape + redef fun to_s do return "{csi}s" +end + +# ANSI/VT100 code to restore the current cursor position (RCP). +class TermRestoreCursor + super TermEscape + redef fun to_s do return "{csi}u" +end + +# ANSI/VT100 code to change character look (SGR). # # By default, resets everything to the terminal’s defaults. # @@ -46,7 +189,7 @@ class TermCharFormat attributes.add_all(format.attributes) end - redef fun to_s: String do return "{esc}[{attributes.join(";")}m" + redef fun to_s do return "{csi}{attributes.join(";")}m" # Apply the specified SGR and return `self`. private fun apply(sgr: String): TermCharFormat do @@ -70,9 +213,9 @@ class TermCharFormat fun inverse: TermCharFormat do return apply("7") # Apply normal weight and return `self`. - fun normalWeight: TermCharFormat do return apply("22") + fun normal_weight: TermCharFormat do return apply("22") - # Add the attribute that disable inderlining and return `self`. + # Add the attribute that disable underlining and return `self`. fun not_underlined: TermCharFormat do return apply("24") # Add the attribute that disable blinking and return `self`. @@ -96,7 +239,7 @@ class TermCharFormat # Apply a blue foreground and return `self`. fun blue_fg: TermCharFormat do return apply("34") - # Apply a mangenta foreground and return `self`. + # Apply a magenta foreground and return `self`. fun magenta_fg: TermCharFormat do return apply("35") # Apply a cyan foreground and return `self`. @@ -108,31 +251,31 @@ class TermCharFormat # Apply the default foreground and return `self`. fun default_fg: TermCharFormat do return apply("39") - # Apply a black backgroud and return `self`. + # Apply a black background and return `self`. fun black_bg: TermCharFormat do return apply("40") - # Apply a red backgroud and return `self`. + # Apply a red background and return `self`. fun red_bg: TermCharFormat do return apply("41") - # Apply a green backgroud and return `self`. + # Apply a green background and return `self`. fun green_bg: TermCharFormat do return apply("42") - # Apply a yellow backgroud and return `self`. + # Apply a yellow background and return `self`. fun yellow_bg: TermCharFormat do return apply("43") - # Apply a blue backgroud and return `self`. + # Apply a blue background and return `self`. fun blue_bg: TermCharFormat do return apply("44") - # Apply a mangenta backgroud and return `self`. + # Apply a magenta background and return `self`. fun magenta_bg: TermCharFormat do return apply("45") - # Apply a cyan backgroud and return `self`. + # Apply a cyan background and return `self`. fun cyan_bg: TermCharFormat do return apply("46") - # Apply a white backgroud and return `self`. + # Apply a white background and return `self`. fun white_bg: TermCharFormat do return apply("47") - # Apply the default backgroud and return `self`. + # Apply the default background and return `self`. fun default_bg: TermCharFormat do return apply("49") end @@ -146,51 +289,123 @@ redef class String # Make the text appear in dark gray (or black) in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun gray: String do return apply_format(normal.black_fg) # Make the text appear in red in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun red: String do return apply_format(normal.red_fg) # Make the text appear in green in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun green: String do return apply_format(normal.green_fg) # Make the text appear in yellow in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun yellow: String do return apply_format(normal.yellow_fg) # Make the text appear in blue in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun blue: String do return apply_format(normal.blue_fg) - # Make the text appear in mangenta in a ANSI/VT100 terminal. + # Make the text appear in magenta in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun purple: String do return apply_format(normal.magenta_fg) # Make the text appear in cyan in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun cyan: String do return apply_format(normal.cyan_fg) # Make the text appear in light gray (or white) in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun light_gray: String do return apply_format(normal.white_fg) # Make the text appear in bold in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun bold: String do return apply_format(normal.bold) # Make the text underlined in a ANSI/VT100 terminal. # - # WARNING: SEE: `TermCharFormat` + # SEE: `TermCharFormat` fun underline: String do return apply_format(normal.underline) end + +# A dynamic progress bar displayable in console. +# +# Example: +# ~~~nitish +# var max = 10 +# var current = 0 +# var pb = new TermProgress(max, current) +# +# pb.display +# for i in [current + 1 .. max] do +# nanosleep(1, 0) +# pb.update(i) +# end +# +# print "\ndone" +# ~~~ +# +# Progress bar can accept metadata to display a small amount of data. +# +# Example with metadata: +# ~~~nitish +# var pb = new TermProgress(10, 0) +# for i in [0..10] do +# pb.update(i, "Step {i}") +# end +# ~~~ +class TermProgress + + # Max value of the progress bar (business value). + var max_value: Int + + # Current value of the progress bar (business value). + var current_value: Int + + # Number of columns used to display the progress bar. + var max_columns = 70 is writable + + # Get the current percent value. + fun current_percentage: Int do + return current_value * 100 / max_value + end + + # Display the progress bar. + # + # `metadata` can be used to pass a small amount of data to display after + # the progress bar. + fun display(metadata: nullable String) do + var percent = current_percentage + var p = current_value * max_columns / max_value + printn "\r{percent}% [" + for i in [1..max_columns] do + if i < p then + printn "=" + else if i == p then + printn ">" + else + printn " " + end + end + printn "]" + if metadata != null then printn " ({metadata})" + end + + # Update and display the progress bar. + # + # See `display`. + fun update(new_current: Int, metadata: nullable String) do + current_value = new_current + display(metadata) + end +end