Skip to content

Commit 7892d04

Browse files
committed
Using TermSize everywhere (larger commit.)
1 parent 229d700 commit 7892d04

3 files changed

Lines changed: 117 additions & 46 deletions

File tree

scrolltext/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def main():
2626
try:
2727
cfg = init_utils(write_config)
2828
action = action or _str_to_action_type(cfg["main"]["action"])
29-
action(write_config)
29+
action(cfg)
3030
except KeyError as e:
3131
print("KeyError occured: " + str(e) + "\nProbalby check config?")
3232
except NameError as e:

scrolltext/cursestext.py

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from curses import wrapper, error
55
import curses
66
import logging
7-
from .utils import CharacterScroller, IS_WINDOWS, init_utils
7+
from .utils import CharacterScroller, IS_WINDOWS, TermSize
88

99

1010
QUIT_CHARACTERS = ["\x1B", "Q", "q"]
@@ -13,84 +13,130 @@
1313
log = logging.getLogger(__name__)
1414

1515

16-
def curses_scroller(win, write_config):
16+
def curses_scroller(win, cfg):
1717
"""
1818
Curses-main: render a text in a side-scrolling manner, using curses.
1919
2020
:param win: Internal curses based object
2121
:type win: curses._window
22-
:param write_config: Write initial config
23-
:type: bool
22+
:param cfg: Config object
23+
:type: configparser.ConfigParser
2424
"""
25-
winsize = win.getmaxyx()
26-
log.debug("win dimensions: (columns, rows) (%d, %d)", winsize[1], winsize[0])
27-
28-
cfg = init_utils(write_config)
29-
box = cfg["cursestext"].getboolean("box")
30-
# try:
31-
if box:
25+
if cfg["cursestext"].getboolean("box"):
3226
win.box()
3327
if not IS_WINDOWS:
3428
curses.curs_set(0) # Hide the cursor
3529

30+
term_size = TermSize(0, 0)
31+
update_term_size(win, cfg["cursestext"].getboolean("box"), term_size)
3632
argv = {}
37-
argv["term_rows"] = winsize[0] - (2 if box else 1)
38-
argv["term_columns"] = winsize[1] - (2 if box else 0)
3933
argv["min_scroll_line"] = 3
40-
scroller = CharacterScroller(cfg, **argv)
34+
scroller = CharacterScroller(cfg, term_size, **argv)
35+
draw_items(win, cfg["cursestext"].getboolean("box"),
36+
argv["min_scroll_line"], scroller, term_size)
4137

42-
win.addstr(1, 10, "Scroll-Text")
43-
add_quit_text(win, box, scroller.line, argv["term_rows"])
4438
win.timeout(100)
4539
try:
46-
do_textloop(win, box, term_size, scroller, term_size.get_rows())
40+
do_textloop(win, cfg, term_size, scroller, argv["min_scroll_line"])
4741
except KeyboardInterrupt:
4842
pass
4943

5044

51-
def do_textloop(win, box, scroller, visibile_height):
45+
def do_textloop(win, cfg, term_size, scroller, min_scroll_line):
5246
"""
5347
This method loops over the scrolled text
5448
"""
49+
box = cfg["cursestext"].getboolean("box")
50+
term_too_small_printed = False
5551
for text in scroller:
5652
win_text = text
57-
if not box and scroller.line == visibile_height:
53+
# hack: When writing to the last line we prevent adding an immediate newline and thus
54+
# moving the text upwards, by removing the last character of the visibile text.
55+
if not box and scroller.line == term_size.get_rows():
5856
win_text = text[:-1]
59-
win.addstr(scroller.line, (1 if box else 0), win_text)
60-
win.redrawwin()
61-
if check_quit(win):
57+
if scroller.line >= min_scroll_line:
58+
_addstr_wrapper(win, scroller.line, (1 if box else 0), win_text)
59+
term_too_small_printed = False
60+
win.redrawwin()
61+
else:
62+
if not term_too_small_printed:
63+
log.debug("Terminal is too small cols: %d rows: %d",
64+
term_size.get_cols(), term_size.get_rows())
65+
term_too_small_printed = True
66+
character = get_char(win)
67+
if character == curses.KEY_EXIT:
6268
return
69+
if character == curses.KEY_RESIZE:
70+
update_term_size(win, box, term_size)
71+
draw_items(win, box, min_scroll_line, scroller, term_size)
6372

6473

65-
def add_quit_text(win, box, line, visibile_height):
74+
def add_quit_text(win, box, line, term_size):
6675
"""
6776
Adds a hint message to win.
68-
TODO: visibile_height, winsize, ...??
6977
"""
70-
if not box and line == visibile_height:
71-
win.addstr(visibile_height - 2, 0, " You can quit with 'q' or 'Q'.")
78+
if term_size.get_cols() < len(" You can quit with 'q' or 'Q'.") + 2:
79+
return
80+
if not box and line == term_size.get_rows():
81+
_addstr_wrapper(win, term_size.get_rows() - 2, 0, " You can quit with 'q' or 'Q'.")
7282
else:
73-
win.addstr(visibile_height, (2 if box else 0), " You can quit with 'q' or 'Q'.")
83+
_addstr_wrapper(win, term_size.get_rows(),
84+
(2 if box else 0), " You can quit with 'q' or 'Q'.")
7485

7586

76-
def check_quit(win):
87+
def get_char(win):
7788
"""
78-
:returns: True, if a quit character is entered, False, otherwise.
79-
:rtype: Boolean
89+
:returns: curses.KEY_EXIT, if a quit character is entered, the current character, otherwise.
90+
:rtype: int
8091
"""
81-
character = win.getch(4, 0)
92+
log.debug("getch")
93+
character = None
94+
character = win.getch(0, 0)
8295
if character != -1:
8396
log.debug("got key (%d) type %s", character, type(character))
8497
if character != -1 and (chr(character) in QUIT_CHARACTERS):
85-
return True
86-
return False
98+
return curses.KEY_EXIT
99+
return character
100+
101+
102+
def update_term_size(win, box, term_size):
103+
"""
104+
Updates TermSize object.
105+
"""
106+
winsize = win.getmaxyx()
107+
log.debug("win dimensions: (columns, rows) (%d, %d)", winsize[1], winsize[0])
108+
available_rows = winsize[0] - (2 if box else 1)
109+
available_columns = winsize[1] - (2 if box else 0)
110+
term_size.set_size(available_columns, available_rows)
111+
112+
113+
def draw_items(win, box, min_scroll_line, scroller, term_size):
114+
"""
115+
Add strings to the curses window.
116+
"""
117+
# clear the window contents
118+
win.clear()
119+
120+
# and redraw screen
121+
if scroller.line != 1 and term_size.get_cols() > len("Scroll-Text"):
122+
_addstr_wrapper(win, 1, 10, "Scroll-Text")
123+
if term_size.get_rows() > min_scroll_line:
124+
add_quit_text(win, box, scroller.line, term_size)
125+
126+
127+
def _addstr_wrapper(win, row, column, text):
128+
log.debug("addstr to line %d", row)
129+
try:
130+
win.addstr(row, column, text)
131+
except: # pylint: disable=W0702 (bare-except)
132+
log.exception("Error in addstr")
87133

88134

89-
def work(write_config):
135+
def work(cfg):
90136
"""Main usese curses.wrapper. See curses doc for details.
91137
"""
92138
try: # noqa: C901 ignoring 'TryExcept 42' is too complex - fix later
93-
wrapper(curses_scroller, write_config)
139+
wrapper(curses_scroller, cfg)
94140
except error as ex:
95141
log.exception(ex)
96142
finally:

scrolltext/linescroller.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
"""
22
A simple side scrolling text application.
33
"""
4+
import logging
45
import shutil
56
from time import sleep
6-
from .utils import CLEAR, HOME, IS_WINDOWS, UP_ONE_ROW, CharacterScroller, init_utils
7+
from .utils import CLEAR, HOME, IS_WINDOWS, UP_ONE_ROW, CharacterScroller, TermSize
78

89
if not IS_WINDOWS:
910
from scrolltext.getchtimeout import GetchWithTimeout
1011

1112

12-
VISIBILE_TEXT_LENGTH = shutil.get_terminal_size()[0]
13+
last_term_rows = -1 # pylint: disable=C0103 (invalid-name)
14+
log = logging.getLogger(__name__)
1315

1416

15-
def linescroller(write_config):
17+
def linescroller(cfg):
1618
"""
1719
Main entry point for linescroller.
1820
:param write_config: Write initial config
@@ -22,35 +24,43 @@ def linescroller(write_config):
2224
if not IS_WINDOWS:
2325
getch = GetchWithTimeout()
2426
try:
25-
_linescroller(getch, write_config)
27+
_linescroller(getch, cfg)
2628
except RuntimeError:
2729
pass
2830
finally:
2931
if not IS_WINDOWS:
3032
getch.cleanup()
3133

3234

33-
def _linescroller(getch, write_config):
35+
def _linescroller(getch, cfg):
3436
"""
3537
Prints a text in a side-scrolling manner.
3638
"""
37-
cfg = init_utils(write_config)
39+
term_size = TermSize(0, 0)
40+
_update_term_size(term_size)
3841
argv = {}
39-
argv["term_rows"] = shutil.get_terminal_size()[1]
40-
argv["term_columns"] = shutil.get_terminal_size()[0] - (1 if IS_WINDOWS else 0)
4142
argv["min_scroll_line"] = 0
42-
scroller = CharacterScroller(cfg, **argv)
43+
scroller = CharacterScroller(cfg, term_size, **argv)
4344

4445
print(f"{CLEAR}{HOME}", end="")
4546
if scroller.line > 0:
4647
_move_to_line(scroller.line)
48+
cnt = 0
4749
for text in scroller:
48-
win_text = text
50+
if scroller.line < term_size.get_rows() - 1:
51+
win_text = text
52+
else:
53+
win_text = text[:-1]
4954
print(win_text, end="\r")
5055
if IS_WINDOWS:
5156
sleep(.15)
5257
else:
5358
_check_input(getch)
59+
cnt += 1
60+
if _update_term_size(term_size):
61+
print(f"{CLEAR}{HOME}", end="")
62+
if scroller.line > 0:
63+
_move_to_line(scroller.line)
5464
if IS_WINDOWS:
5565
print(f"{UP_ONE_ROW}", end="")
5666

@@ -60,6 +70,8 @@ def _check_input(getch):
6070
Use getchtimeout to get a character. If "Q" or "q" is given, then it raises SystemExit
6171
"""
6272
character = getch.getch(timeout=.1)
73+
if isinstance(character, int) == int:
74+
log.debug("Got key '%d'", character)
6375
if character is not None and character in ["\033", "\x1b", "", "\r", "", " ", "Q", "q"]:
6476
raise RuntimeError()
6577

@@ -75,3 +87,16 @@ def _move_to_line(line):
7587
else:
7688
for _ in range(line):
7789
print("\033[1B", end="")
90+
91+
92+
def _update_term_size(term_size):
93+
global last_term_rows # pylint: disable=W0603 (global-statement)
94+
available_rows = shutil.get_terminal_size()[1]
95+
available_columns = shutil.get_terminal_size()[0] - (1 if IS_WINDOWS else 0)
96+
term_size.set_size(available_columns, available_rows)
97+
if last_term_rows == -1:
98+
last_term_rows = term_size.get_rows()
99+
if term_size.get_rows() != last_term_rows:
100+
last_term_rows = term_size.get_rows()
101+
return True
102+
return False

0 commit comments

Comments
 (0)