2 from threading
import Lock
3 from .utils
import supports_terminal_sequences
, TERMINAL_SEQUENCES
, write_string
6 class MultilinePrinterBase
:
7 def __init__(self
, stream
=None, lines
=1):
9 self
.maximum
= lines
- 1
14 def __exit__(self
, *args
):
17 def print_at_line(self
, text
, pos
):
23 def _add_line_number(self
, text
, line
):
25 return f
'{line + 1}: {text}'
28 def write(self
, *text
):
29 write_string(''.join(text
), self
.stream
)
32 class QuietMultilinePrinter(MultilinePrinterBase
):
36 class MultilineLogger(MultilinePrinterBase
):
37 def write(self
, *text
):
38 self
.stream
.debug(''.join(text
))
40 def print_at_line(self
, text
, pos
):
41 # stream is the logger object, not an actual stream
42 self
.write(self
._add
_line
_number
(text
, pos
))
45 class BreaklineStatusPrinter(MultilinePrinterBase
):
46 def print_at_line(self
, text
, pos
):
47 self
.write(self
._add
_line
_number
(text
, pos
), '\n')
50 class MultilinePrinter(MultilinePrinterBase
):
51 def __init__(self
, stream
=None, lines
=1, preserve_output
=True):
52 super().__init
__(stream
, lines
)
53 self
.preserve_output
= preserve_output
54 self
._lastline
= self
._lastlength
= 0
55 self
._movelock
= Lock()
56 self
._HAVE
_FULLCAP
= supports_terminal_sequences(self
.stream
)
59 @functools.wraps(func
)
60 def wrapper(self
, *args
, **kwargs
):
62 return func(self
, *args
, **kwargs
)
65 def _move_cursor(self
, dest
):
66 current
= min(self
._lastline
, self
.maximum
)
68 distance
= dest
- current
70 yield TERMINAL_SEQUENCES
['UP'] * -distance
72 yield TERMINAL_SEQUENCES
['DOWN'] * distance
76 def print_at_line(self
, text
, pos
):
77 if self
._HAVE
_FULLCAP
:
78 self
.write(*self
._move
_cursor
(pos
), TERMINAL_SEQUENCES
['ERASE_LINE'], text
)
80 text
= self
._add
_line
_number
(text
, pos
)
82 if self
._lastline
== pos
:
83 # move cursor at the start of progress when writing to same line
85 if self
._lastlength
> textlen
:
86 text
+= ' ' * (self
._lastlength
- textlen
)
87 self
._lastlength
= textlen
89 # otherwise, break the line
91 self
._lastlength
= textlen
92 self
.write(prefix
, text
)
97 # move cursor to the end of the last line, and write line break
98 # so that other to_screen calls can precede
99 text
= self
._move
_cursor
(self
.maximum
) if self
._HAVE
_FULLCAP
else []
100 if self
.preserve_output
:
101 self
.write(*text
, '\n')
104 if self
._HAVE
_FULLCAP
:
106 *text
, TERMINAL_SEQUENCES
['ERASE_LINE'],
107 f
'{TERMINAL_SEQUENCES["UP"]}{TERMINAL_SEQUENCES["ERASE_LINE"]}' * self
.maximum
)
109 self
.write(*text
, ' ' * self
._lastlength
)