Skip to content

Commit

Permalink
Add and prefer Terminal.move_xy() over built-in 'move' (erikrose#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
jquast authored Jan 18, 2020
2 parents 8e07054 + fc3dd52 commit 17511d3
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 104 deletions.
1 change: 0 additions & 1 deletion bin/colorchart.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def sort_colors():
def draw_chart(term):
"""Draw a chart of each X11 color represented as in 24-bit and as down-converted to 256, 16, and
8 color with the currently configured algorithm."""
term.move(0, 0)
sys.stdout.write(term.home)
width = term.width
line = ''
Expand Down
2 changes: 1 addition & 1 deletion bin/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def input_filter(keystroke):

def echo_yx(cursor, text):
"""Move to ``cursor`` and display ``text``."""
echo(cursor.term.move(cursor.y, cursor.x) + text)
echo(cursor.term.move_yx(cursor.y, cursor.x) + text)


Cursor = collections.namedtuple('Cursor', ('y', 'x', 'term'))
Expand Down
10 changes: 5 additions & 5 deletions bin/keymatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def refresh(term, board, level, score, inps):
bottom = 0
for keycode, attr in board.items():
echo(u''.join((
term.move(attr['row'], attr['column']),
term.move_yx(attr['row'], attr['column']),
term.color(level_color),
(term.reverse if attr['hit'] else term.bold),
keycode,
term.normal)))
bottom = max(bottom, attr['row'])
echo(term.move(term.height, 0) + 'level: %s score: %s' % (level, score,))
echo(term.move_yx(term.height, 0) + 'level: %s score: %s' % (level, score,))
if bottom >= (term.height - 5):
sys.stderr.write(
('\n' * (term.height // 2)) +
Expand All @@ -54,10 +54,10 @@ def refresh(term, board, level, score, inps):
term.center("(use a larger screen)") +
('\n' * (term.height // 2)))
sys.exit(1)
echo(term.move(bottom + 1, 0))
echo(term.move_yx(bottom + 1, 0))
echo('Press ^C to exit.')
for row, inp in enumerate(inps[(term.height - (bottom + 3)) * -1:], 1):
echo(term.move(bottom + row + 1, 0))
echo(term.move_yx(bottom + row + 1, 0))
echo('{0!r}, {1}, {2}'.format(
inp.__str__() if inp.is_sequence else inp,
inp.code,
Expand Down Expand Up @@ -128,7 +128,7 @@ def main():
inps.append(inp)

with term.cbreak():
echo(term.move(term.height))
echo(term.move_yx(term.height))
echo(
u'{term.clear_eol}Your final score was {score} '
u'at level {level}{term.clear_eol}\n'
Expand Down
4 changes: 2 additions & 2 deletions bin/plasma.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ def elapser():

def show_please_wait(term):
txt_wait = 'please wait ...'
outp = term.move(term.height - 1, 0) + term.clear_eol + term.center(txt_wait)
outp = term.move_yx(term.height - 1, 0) + term.clear_eol + term.center(txt_wait)
print(outp, end='')
sys.stdout.flush()


def show_paused(term):
txt_paused = 'paused'
outp = term.move(term.height - 1, int(term.width / 2 - len(txt_paused) / 2))
outp = term.move_yx(term.height - 1, int(term.width / 2 - len(txt_paused) / 2))
outp += txt_paused
print(outp, end='')
sys.stdout.flush()
Expand Down
10 changes: 5 additions & 5 deletions bin/progress_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"""
Example application for the 'blessed' Terminal library for python.
This isn't a real progress bar, just a sample "animated prompt" of sorts that demonstrates the
separate move_x() and move_y() functions, made mainly to test the `hpa' compatibility for 'screen'
terminal type which fails to provide one, but blessed recognizes that it actually does, and provides
a proxy.
This isn't a real progress bar, just a sample "animated prompt" of sorts that
demonstrates the separate move_x() and move_yx() capabilities, made mainly to
test the `hpa' compatibility for 'screen' terminal type which fails to provide
one, but blessed recognizes that it actually does, and provides a proxy.
"""
from __future__ import print_function

Expand All @@ -26,7 +26,7 @@ def main():
with term.cbreak():
inp = None
print("press 'X' to stop.")
sys.stderr.write(term.move(term.height, 0) + u'[')
sys.stderr.write(term.move_yx(term.height, 0) + u'[')
sys.stderr.write(term.move_x(term.width - 1) + u']' + term.move_x(1))
while inp != 'X':
if col >= (term.width - 2):
Expand Down
18 changes: 9 additions & 9 deletions bin/worms.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,21 +191,21 @@ def main():
color_worm = term.yellow_reverse
color_head = term.red_reverse
color_bg = term.on_blue
echo(term.move(1, 1))
echo(term.move_yx(1, 1))
echo(color_bg(term.clear))

# speed is actually a measure of time; the shorter, the faster.
speed = 0.1
modifier = 0.93
inp = None

echo(term.move(term.height, 0))
echo(term.move_yx(term.height, 0))
with term.hidden_cursor(), term.cbreak(), term.location():
while inp not in (u'q', u'Q'):

# delete the tail of the worm at worm_length
if len(worm) > worm_length:
echo(term.move(*worm.pop(0)))
echo(term.move_yx(*worm.pop(0)))
echo(color_bg(u' '))

# compute head location
Expand All @@ -229,22 +229,22 @@ def main():
# with a worm color for those portions that overlay.
for (yloc, xloc) in nibble_locations(*nibble):
echo(u''.join((
term.move(yloc, xloc),
term.move_yx(yloc, xloc),
(color_worm if (yloc, xloc) == head
else color_bg)(u' '),
term.normal)))
# and draw the new,
echo(term.move(*n_nibble.location) + (
echo(term.move_yx(*n_nibble.location) + (
color_nibble('{}'.format(n_nibble.value))))

# display new worm head
echo(term.move(*head) + color_head(head_glyph(direction)))
echo(term.move_yx(*head) + color_head(head_glyph(direction)))

# and its old head (now, a body piece)
if worm:
echo(term.move(*(worm[-1])))
echo(term.move_yx(*(worm[-1])))
echo(color_worm(u' '))
echo(term.move(*head))
echo(term.move_yx(*head))

# wait for keyboard input, which may indicate
# a new direction (up/down/left/right)
Expand All @@ -271,7 +271,7 @@ def main():

echo(term.normal)
score = (worm_length - 1) * 100
echo(u''.join((term.move(term.height - 1, 1), term.normal)))
echo(u''.join((term.move_yx(term.height - 1, 1), term.normal)))
echo(u''.join((u'\r\n', u'score: {}'.format(score), u'\r\n')))


Expand Down
2 changes: 1 addition & 1 deletion bin/x11_colorpicker.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def render(term, idx):
f'{term.number_of_colors} colors - '
f'{term.color_distance_algorithm}')

result += term.move(idx // term.width, idx % term.width)
result += term.move_yx(idx // term.width, idx % term.width)
result += term.on_color_rgb(*rgb_color)(' \b')
return result

Expand Down
24 changes: 24 additions & 0 deletions blessed/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,30 @@ def color(self):
return ParameterizingString(self._foreground_color,
self.normal, 'color')

def move_xy(self, x, y):
"""
A callable string that moves the cursor to the given ``(x, y)`` screen coordinates.
:arg int x: horizontal position.
:arg int y: vertical position.
:rtype: ParameterizingString
"""
# this is just a convenience alias to the built-in, but hidden 'move'
# attribute -- we encourage folks to use only (x, y) positional
# arguments, or, if they must use (y, x), then use the 'move_yx'
# alias.
return self.move(y, x)

def move_yx(self, y, x):
"""
A callable string that moves the cursor to the given ``(y, x)`` screen coordinates.
:arg int x: horizontal position.
:arg int y: vertical position.
:rtype: ParameterizingString
"""
return self.move(y, x)

def color_rgb(self, red, green, blue):
if self.number_of_colors == 1 << 24:
# "truecolor" 24-bit
Expand Down
60 changes: 30 additions & 30 deletions docs/history.rst
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
Version History
===============
1.17
* introduced: 24-bit color support, detected by ``term.number_of_colors == 1 << 24``,
and 24-bit color foreground method :meth:`~Terminal.color_rgb` and background method
:meth:`~Terminal.on_color_rgb`.
* introduced: 24-bit color support, detected by ``term.number_of_colors == 1 << 24``, and 24-bit
color foreground method :meth:`~Terminal.color_rgb` and background method
:meth:`~Terminal.on_color_rgb`, as well as 676 common X11 color attribute names are now
possible, such as ``term.aquamarine_on_wheat``.
* introduced: ``term.move_xy``, recommended over built-in ``move`` capability, as the return
positional arguments, ``(x, y)`` match the return value of :meth:`~.Terminal.get_location`,
and all other common graphics library calls, :ghissue:`65`.
values over the b``term.move``.
* bugfix: prevent error condition, ``ValueError: underlying buffer has been detached`` in rare
conditions where sys.__stdout__ has been detached in test frameworks. :ghissue:`126`.
* bugfix: off-by-one error in :meth:`~.Terminal.get_location`, now accounts for
``%i`` in cursor_report, :ghissue:`94`.
* bugfix :meth:`~Terminal.split_seqs` and related functions failed to match when the
color index was greater than 15, :ghissue:`101`.
* bugfix: Context Managers, :meth:`~.Terminal.fullscreen`,
:meth:`~.Terminal.hidden_cursor`, and :meth:`~Terminal.keypad`
now flush the stream after writing their sequences.
* bugfix: ``chr(127)``, ``\x7f`` has changed from keycode ``term.DELETE`` to the more
common match, ``term.BACKSPACE``, :ghissue:115` by :ghuser:`jwezel`.
* deprecated: the direct curses ``move()`` capability is no longer recommended,
suggest to use :meth:`~.Terminal.move_xy()`, which matches the return value of
:meth:`~.Terminal.get_location`.
* deprecated: ``superscript``, ``subscript``, ``shadow``, and ``dim`` are no
longer "compoundable" with colors, such as in phrase ``Terminal.blue_subscript('a')``.
These attributes are not typically supported, anyway. Use Unicode text or 256 or
24-bit color codes instead.
* deprecated: additional key names, such as ``KEY_TAB``, are no longer "injected" into
the curses module namespace.
* deprecated: :func:`curses.setupterm` is now called with :attr:`os.devnull`
as the file descriptor, let us know if this causes any issues. :ghissue:`59`.
* deprecated: :meth:`~Terminal.inkey` no longer raises RuntimeError when
:attr:`~Terminal.stream` is not a terminal, programs using
:meth:`~Terminal.inkey` to block indefinitely if a keyboard is not
attached. :ghissue:`69`.
* deprecated: using argument ``_intr_continue`` to method
:meth:`~Terminal.kbhit`, behavior is as though such value is always True
since 1.9.
* bugfix: off-by-one error in :meth:`~.Terminal.get_location`, now accounts for ``%i`` in
cursor_report, :ghissue:`94`.
* bugfix :meth:`~Terminal.split_seqs` and related functions failed to match when the color index
was greater than 15, :ghissue:`101`.
* bugfix: Context Managers, :meth:`~.Terminal.fullscreen`, :meth:`~.Terminal.hidden_cursor`, and
:meth:`~Terminal.keypad` now flush the stream after writing their sequences.
* bugfix: ``chr(127)``, ``\x7f`` has changed from keycode ``term.DELETE`` to the more common
match, ``term.BACKSPACE``, :ghissue:115` by :ghuser:`jwezel`.
* deprecated: the direct curses ``move()`` capability is no longer recommended, suggest to use
:meth:`~.Terminal.move_xy()`, which matches the return value of :meth:`~.Terminal.get_location`.
* deprecated: ``superscript``, ``subscript``, ``shadow``, and ``dim`` are no longer "compoundable"
with colors, such as in phrase ``Terminal.blue_subscript('a')``. These attributes are not
typically supported, anyway. Use Unicode text or 256 or 24-bit color codes instead.
* deprecated: additional key names, such as ``KEY_TAB``, are no longer "injected" into the curses
module namespace.
* deprecated: :func:`curses.setupterm` is now called with :attr:`os.devnull` as the file
descriptor, let us know if this causes any issues. :ghissue:`59`.
* deprecated: :meth:`~Terminal.inkey` no longer raises RuntimeError when :attr:`~Terminal.stream`
is not a terminal, programs using :meth:`~Terminal.inkey` to block indefinitely if a keyboard is
not attached. :ghissue:`69`.
* deprecated: using argument ``_intr_continue`` to method :meth:`~Terminal.kbhit`, behavior is as
though such value is always True since 1.9.

1.16
* introduced: Windows support?! :ghissue:`110` by :ghuser:`avylove`.
Expand Down
72 changes: 29 additions & 43 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,42 +184,27 @@ demonstration script.
Moving The Cursor
-----------------

When you want to move the cursor, you have a few choices:

- ``location(x=None, y=None)`` context manager.
- ``move(row, col)`` capability.
- ``move_y(row)`` capability.
- ``move_x(col)`` capability.

.. warning:: The :meth:`~.Terminal.location` method receives arguments in
positional order *(x, y)*, whereas the ``move()`` capability receives
arguments in order *(y, x)*. Please use keyword arguments as a later
release may correct the argument order of :meth:`~.Terminal.location`.

Finding The Cursor
------------------

We can determine the cursor's current position at anytime using
:meth:`~.get_location`, returning the current (y, x) location. This uses a
kind of "answer back" sequence that your terminal emulator responds to. If
the terminal may not respond, the :paramref:`~.get_location.timeout` keyword
argument can be specified to return coordinates (-1, -1) after a blocking
timeout::
If you just want to move and aren't worried about returning, do something like
this::

from blessed import Terminal

term = Terminal()
print(term.move_xy(10, 1) + 'Hi, mom!')

row, col = term.get_location(timeout=5)
There are three basic movement capabilities:

if row < term.height:
print(term.move_y(term.height) + 'Get down there!')

Moving Temporarily
~~~~~~~~~~~~~~~~~~
``move_xy(x, y)``
Position cursor at given **x**, **y**.
``move_x(x)``
Position cursor at column **x**.
``move_y(y)``
Position cursor at row **y**.
``home``
Position cursor at (0, 0).

A context manager, :meth:`~.Terminal.location` is provided to move the cursor
to an *(x, y)* screen position and restore the previous position upon exit::
to an *(x, y)* screen position and *restore the previous position* on exit::

from blessed import Terminal

Expand All @@ -236,32 +221,32 @@ keyword arguments::
with term.location(y=10):
print('We changed just the row.')

When omitted, it saves the cursor position and restore it upon exit::
When omitted, it saves the current cursor position, and restore it on exit::

with term.location():
print(term.move(1, 1) + 'Hi')
print(term.move(9, 9) + 'Mom')
print(term.move_xy(1, 1) + 'Hi')
print(term.move_xy(9, 9) + 'Mom')

.. note:: calls to :meth:`~.Terminal.location` may not be nested.

Finding The Cursor
------------------

Moving Permanently
~~~~~~~~~~~~~~~~~~

If you just want to move and aren't worried about returning, do something like
this::
We can determine the cursor's current position at anytime using
:meth:`~.get_location`, returning the current (y, x) location. This uses a
kind of "answer back" sequence that your terminal emulator responds to. If
the terminal may not respond, the :paramref:`~.get_location.timeout` keyword
argument can be specified to return coordinates (-1, -1) after a blocking
timeout::

from blessed import Terminal

term = Terminal()
print(term.move(10, 1) + 'Hi, mom!')

``move(y, x)``
Position cursor at given **y**, **x**.
``move_x(x)``
Position cursor at column **x**.
``move_y(y)``
Position cursor at row **y**.
row, col = term.get_location(timeout=5)

if row < term.height:
print(term.move_y(term.height) + 'Get down there!')

One-Notch Movement
~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -309,6 +294,7 @@ changes, you may author a callback for SIGWINCH_ signals::
# wait for keypress
term.inkey()

.. note:: This is not compatible with Windows!

Clearing The Screen
-------------------
Expand Down
1 change: 0 additions & 1 deletion tests/accessories.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def init_subproc_coverage(run_note):
os.path.dirname(__file__),
os.pardir, 'tox.ini')
cov = coverage.Coverage(config_file=_coveragerc)
cov.set_option("run:note", run_note)
cov.start()
return cov

Expand Down
Loading

0 comments on commit 17511d3

Please sign in to comment.