Try the String Repeater

String Repetition and ANSI Escape Codes: How Progress Bars, Borders, and Terminal UIs Are Built

A terminal progress bar, a box-drawn menu, and colored CLI output all rely on the same underlying operation: repeating a character a calculated number of times, often combined with ANSI escape codes for color and cursor control. Here's how string repetition builds progress bars and borders, why Unicode box-drawing characters connect seamlessly at corners, and how terminal width affects repeated-character output.

By sadiqbd Β· June 13, 2026

Share:
String Repetition and ANSI Escape Codes: How Progress Bars, Borders, and Terminal UIs Are Built

Terminal colors, cursor movement, and "clear the screen" aren't features of the text itself β€” they're invisible character sequences embedded directly in the string, and repeating or generating these sequences programmatically is how progress bars, colored output, and terminal UIs actually work

ANSI escape codes are sequences of characters β€” starting with the "escape" character (ASCII code 27) followed by specific patterns β€” that terminals interpret as instructions rather than displayable text. Understanding how these sequences are constructed, and how repetition plays into generating terminal output programmatically, explains everything from colored ls output to progress bars to ASCII-art startup banners.


The basic structure of an ANSI escape code

An ANSI escape sequence typically looks like: ESC[ followed by one or more parameters, followed by a letter indicating the command. In most programming languages, ESC is represented as \x1b or \033 (octal) or \u001b.

Coloring text:

\x1b[31mThis text is red\x1b[0m

\x1b[31m sets the foreground color to red; \x1b[0m resets all formatting back to default. Everything between these two sequences is displayed in red β€” but the escape sequences themselves are not displayed as visible characters; the terminal interprets them as formatting instructions.

Cursor movement:

\x1b[2J    β€” clear the entire screen
\x1b[H     β€” move cursor to the top-left (home position)
\x1b[5;10H β€” move cursor to row 5, column 10

Repetition and escape codes: building progress bars

A terminal progress bar β€” [########## ] 50% β€” is typically built by:

  1. Moving the cursor back to the start of the line (often using \r, carriage return, which moves the cursor to column 0 without advancing to a new line β€” allowing the next output to overwrite the current line)
  2. Printing a string that's been constructed by repeating a "filled" character some number of times (proportional to progress), followed by repeating an "empty" character for the remainder
filled = int(50 * progress)
empty = 50 - filled
bar = "#" * filled + " " * empty
print(f"\r[{bar}] {int(progress*100)}%", end="")

This is exactly the string-repetition operation covered in the original string-repeater article β€” "#" * filled repeats the # character filled times β€” combined with the \r carriage-return trick to make the output appear to update in place, rather than printing a new line for each progress update.


ASCII art and box-drawing: repetition for borders

Terminal "boxes" β€” bordered regions for menus, dialogs, or section dividers β€” are built from repeated border characters:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Welcome to the installer  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The top and bottom borders are constructed by repeating the horizontal-line character (─, a Unicode box-drawing character, distinct from a regular hyphen) a number of times matching the desired width, with corner characters (β”Œ, ┐, β””, β”˜) at the ends.

width = 28
top = "β”Œ" + "─" * width + "┐"
bottom = "β””" + "─" * width + "β”˜"

Unicode box-drawing characters (in the U+2500–U+257F range) provide a standardized set of line/corner/junction characters specifically designed for this purpose β€” connecting seamlessly when adjacent (a horizontal line character placed next to a corner character produces a continuous-looking border, because the glyphs are designed with this in mind) β€” as opposed to using regular ASCII characters like - and | and +, which work but produce a visually "rougher" result (no seamless connections at corners).


Repetition for separators and visual rhythm in CLI output

Command-line tools frequently use repeated characters as visual separators between sections of output:

============================
  Build Results
============================
βœ“ 142 tests passed
βœ— 3 tests failed
============================

Why repetition (rather than a fixed-width separator) matters: a separator that's the same width as the content it's separating creates a more visually balanced result than a fixed-width separator that might be narrower or much wider than the content. Some CLI tools dynamically calculate separator width based on the terminal's current width (obtained via system calls that report terminal dimensions) β€” generating a repeated-character string whose length matches the full width of the user's current terminal window, so the separator always spans edge-to-edge regardless of how the user has sized their terminal.


Generative ASCII art: repetition as the basis of pattern generation

Beyond functional terminal UI, repetition is foundational to generative ASCII art β€” patterns built by repeating characters according to mathematical rules:

Simple repetition-based patterns:

for i in range(1, 11):
    print("*" * i)

produces a triangle:

*
**
***
****
...
**********

Sierpinski triangle (a classic fractal pattern) can be generated using repetition combined with bitwise operations β€” for each row, each column position is checked against a simple condition (related to the binary representations of the row/column indices), and a character is repeated (or a space substituted) based on that condition β€” producing the recognizable recursive-triangle fractal pattern entirely from text repetition logic, without any graphics β€” a popular "fun" programming exercise specifically because it demonstrates how a simple, repetitive operation (printing characters in a loop) can produce a visually complex-looking, mathematically meaningful result.


Terminal width considerations and wrapping

A practical consideration when generating repeated-character output for terminals: if the repeated string is longer than the terminal's current width, most terminals will wrap the line β€” which can break the intended visual effect of a "single repeated line" (a border that's supposed to span one row visually wraps onto two rows, breaking the box-drawing alignment).

Programmatically querying terminal width (via OS-specific calls β€” different on Unix-like systems vs Windows, though most languages' standard libraries or common packages abstract this) and generating repeated-character strings sized to fit within the current width (rather than using a fixed, hardcoded width) is the robust approach for CLI tools that need to work correctly across users' differently-sized terminal windows.


How to use the String Repeater tool on sadiqbd.com

  1. Generate border/separator strings for use in scripts β€” repeat a box-drawing character or simple character (-, =, *) to a specific width for use as a visual separator in CLI output or text-based reports
  2. Prototype ASCII-art patterns β€” repeat characters to explore simple pattern generation before implementing the full logic in your programming language of choice
  3. Generate test strings for terminal-width testing β€” create strings of specific lengths to test how your CLI tool handles content at, just-under, and just-over your target terminal width

Frequently Asked Questions

Why do some terminal "colors" not work in certain environments (like some CI/CD logs)? ANSI escape codes are interpreted by terminal emulators β€” environments that aren't genuine interactive terminals (some CI/CD log viewers, some text editors' "output" panels, files that output has been redirected to) may not interpret these escape sequences β€” in which case, the raw escape-code characters (\x1b[31m etc.) either display as visible, garbled characters, or are stripped/ignored depending on the specific tool. Many CLI tools detect whether their output is going to an interactive terminal vs being redirected/piped, and disable color/escape-code output automatically when not writing to an interactive terminal β€” to avoid this garbled-output problem.

Is there a difference between \n (newline) and using escape codes to move the cursor down a line? Yes β€” \n is a standard text character (line feed) that virtually all text-processing contexts understand as "start a new line," and advances the cursor down and to the start of the next line. ANSI cursor-movement escape codes (like \x1b[1B, "move cursor down 1 line") provide more granular control β€” e.g., moving the cursor down without also resetting to column 0, or moving it to an arbitrary row/column position β€” capabilities that plain \n doesn't provide. For most simple "print line by line" output, \n is sufficient; ANSI cursor-movement codes are needed for more dynamic terminal UI (progress bars updating in place, multi-region terminal layouts, etc.).

Is the String Repeater free? Yes β€” completely free, no sign-up required.

Try the String Repeater free at sadiqbd.com β€” repeat any text or character any number of times instantly.

Share:
Try the related tool:
Open String Repeater

More String Repeater articles