# 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 foward 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.
#
attributes.add_all(format.attributes)
end
- redef fun to_s: String do return "{esc}[{attributes.join(";")}m"
+ redef fun to_s: String do return "{csi}{attributes.join(";")}m"
# Apply the specified SGR and return `self`.
private fun apply(sgr: String): TermCharFormat do
# WARNING: SEE: `TermCharFormat`
fun underline: String do return apply_format(normal.underline)
end
+
+# A dynamic progressbar 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"
+# ~~~
+#
+# Progressbar 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 progressbar.
+ 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 progresssbar.
+ #
+ # See `display`.
+ fun update(new_current: Int, metadata: nullable String) do
+ current_value = new_current
+ display(metadata)
+ end
+end