Skip to content

Instantly share code, notes, and snippets.

@thomasballinger
Created October 3, 2013 20:50
Show Gist options
  • Select an option

  • Save thomasballinger/6816908 to your computer and use it in GitHub Desktop.

Select an option

Save thomasballinger/6816908 to your computer and use it in GitHub Desktop.

==========================================

fmtstr annotates portions of strings with terminal colors and formatting str(yourstring) will be the string with [ANSI escape codes] (http://en.wikipedia.org/wiki/ANSI_escape_code) specifying color and other formatting to a terminal.

fmtstr.FmtStr

fmtstr example screenshot

You can use convenience functions instead:

>>> from fmtstr.fmtfuncs import *
>>> blue(on_red('hey')) + " " + underline("there")
  • str(FmtStr) -> escape sequence-laden text bound that looks cool in a terminal
  • repr(FmtStr) -> how to create an identical FmtStr
  • FmtStr[3:10] -> a new FmtStr
  • FmtStr.upper() (any string method) -> a new FmtStr or list of FmtStrs or int (str.count)

See also

Details

One FmtStr can have several kinds of formatting applied to different parts of it.

>>> from fmtstr.fmtfuncs import *
>>> blue('asdf') + on_red('adsf')
blue("asdf")+on_red("adsf")

They allow slicing, which returns a new FmtStr object:

>>> from fmtstr.fmtfuncs import *
>>> (blue('asdf') + on_red('adsf'))[3:7]
blue("f")+on_red("ads")

FmtStrs are mutable - you can change them via slice assignment:

>>> from fmtstr.fmtfuncs import *
>>> f = blue('hey there') + on_red(' Tom!')
>>> f[1:3] = 'ot'
>>> f
blue("h")+"ot"+blue(" there")+on_red(" Tom!")

But you can't change their length:

>>> f[1:3] = 'something longer'

FmtStrs greedily absorb strings, but no formatting is applied

>>> from fmtstr.fmtfuncs import *
>>> f = blue("The story so far:") + "In the beginning..."
>>> type(f)
<class fmtstr.fmtstr.FmtStr>
>>> f
blue("The story so far:")+"In the beginning..."

It's easy to turn ANSI terminal formatted strings into FmtStrs:

>>> from fmtstr.fmtfuncs import *
>>> from fmtstr.fmtstr import FmtStr
>>> s = str(blue('tom'))
>>> s
'\x1b[34mtom\x1b[39m'
>>> FmtStr.from_str(str(blue('tom')))
blue("tom")

Using str methods on FmtStr objects

All sorts of string methods can be used on a FmtStr, so you can often use FmtStr objects where you had string in your program before:

>>> from fmtstr.fmtstr import *
>>> f = blue(underline('As you like it'))
>>> len(f)
14 
>>> f == underline(blue('As you like it')) + red('')
True
>>> blue(', ').join(['a', red('b')])
"a"+blue(", ")+red("b")

If FmtStr doesn't implement a method, it tries its best to use the string method, which often works pretty well:

>>> from fmtstr.fmtstr import *
>>> f = blue(underline('As you like it'))
>>> f.center(20)
blue(underline("   As you like it   "))
>>> f.count('i')
2
>>> f.endswith('it')
True
>>> f.index('you')
3
>>> f.split(' ')
[blue(underline("As")), blue(underline("you")), blue(underline("like")), blue(underline("it"))]

But formatting information will be lost for attributes which are not the same through the whole string

>>> from fmtstr.fmtstr import *
>>> f = bold(red('hi')+' '+on_blue('there'))
>>> f
bold(red('hi'))+bold(' ')+bold(on_blue('there'))
>>> f.center(10)
bold(" hi there ")

fmtstr.FSArray

2d array in which each line is a FmtStr

fsarray example screenshot

Terminal

Interact with the Terminal object by passing it 2d numpy arrays of characters; or even better, arrays of FmtStr objects! Terminal objects typically need a TerminalController passed to them in their init methods, which sets the terminal window up and catches input in raw mode. Context managers make it so fatal exceptions won't prevent necessary cleanup to make the terminal usable again. Putting all that together:

import sys
from fmtstr.fmtfuncs import *
from fmtstr.terminal import Terminal
from fmtstr.terminalcontrol import TerminalController

with TerminalController(sys.stdin, sys.stdout) as tc:
    with Terminal(tc) as t:
        rows, columns = t.tc.get_screen_size()
        while True:
            c = t.tc.get_event()
            if c == "�":
                sys.exit()
            elif c == "a":
                a = [blue(on_red(c*columns)) for _ in range(rows)]
                # covers the entire screen with blue a's on a red background
            elif c == "b":
                a = t.array_from_text("this is a small array")
                # renders a small array where the cursor is
            else:
                a = t.array_from_text("try a, b, or ctrl-D")
            t.render_to_terminal(a)

When a Terminal object is passed an array with more rows than it's height, it writes the entire array to the terminal, scrolling down so that the extra rows at the top of the 2d array end up out of view. This behavior is particularly useful for writing command line interfaces like the REPL scottwasright.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment