2 from threading
import Lock
3 from .utils
import supports_terminal_sequences
, TERMINAL_SEQUENCES
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}'
29 class QuietMultilinePrinter(MultilinePrinterBase
):
33 class MultilineLogger(MultilinePrinterBase
):
34 def print_at_line(self
, text
, pos
):
35 # stream is the logger object, not an actual stream
36 self
.stream
.debug(self
._add
_line
_number
(text
, pos
))
39 class BreaklineStatusPrinter(MultilinePrinterBase
):
40 def print_at_line(self
, text
, pos
):
41 self
.stream
.write(self
._add
_line
_number
(text
, pos
) + '\n')
44 class MultilinePrinter(MultilinePrinterBase
):
45 def __init__(self
, stream
=None, lines
=1, preserve_output
=True):
46 super().__init
__(stream
, lines
)
47 self
.preserve_output
= preserve_output
48 self
._lastline
= self
._lastlength
= 0
49 self
._movelock
= Lock()
50 self
._HAVE
_FULLCAP
= supports_terminal_sequences(self
.stream
)
53 @functools.wraps(func
)
54 def wrapper(self
, *args
, **kwargs
):
56 return func(self
, *args
, **kwargs
)
59 def _move_cursor(self
, dest
):
60 current
= min(self
._lastline
, self
.maximum
)
61 self
.stream
.write('\r')
62 distance
= dest
- current
64 self
.stream
.write(TERMINAL_SEQUENCES
['UP'] * -distance
)
66 self
.stream
.write(TERMINAL_SEQUENCES
['DOWN'] * distance
)
70 def print_at_line(self
, text
, pos
):
71 if self
._HAVE
_FULLCAP
:
72 self
._move
_cursor
(pos
)
73 self
.stream
.write(TERMINAL_SEQUENCES
['ERASE_LINE'])
74 self
.stream
.write(text
)
77 text
= self
._add
_line
_number
(text
, pos
)
79 if self
._lastline
== pos
:
80 # move cursor at the start of progress when writing to same line
81 self
.stream
.write('\r')
82 if self
._lastlength
> textlen
:
83 text
+= ' ' * (self
._lastlength
- textlen
)
84 self
._lastlength
= textlen
86 # otherwise, break the line
87 self
.stream
.write('\n')
88 self
._lastlength
= textlen
89 self
.stream
.write(text
)
94 # move cursor to the end of the last line, and write line break
95 # so that other to_screen calls can precede
96 if self
._HAVE
_FULLCAP
:
97 self
._move
_cursor
(self
.maximum
)
98 if self
.preserve_output
:
99 self
.stream
.write('\n')
102 if self
._HAVE
_FULLCAP
:
104 TERMINAL_SEQUENCES
['ERASE_LINE']
105 + f
'{TERMINAL_SEQUENCES["UP"]}{TERMINAL_SEQUENCES["ERASE_LINE"]}' * self
.maximum
)
107 self
.stream
.write(' ' * self
._lastlength
)