forked from cms-dev/cms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathterminal.py
129 lines (106 loc) · 4.59 KB
/
terminal.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python3
# Contest Management System - http://cms-dev.github.io/
# Copyright © 2015 Luca Versari <[email protected]>
# Copyright © 2018 Luca Chiodini <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import curses
import sys
class colors:
BLACK = curses.COLOR_BLACK
RED = curses.COLOR_RED
GREEN = curses.COLOR_GREEN
YELLOW = curses.COLOR_YELLOW
BLUE = curses.COLOR_BLUE
MAGENTA = curses.COLOR_MAGENTA
CYAN = curses.COLOR_CYAN
WHITE = curses.COLOR_WHITE
class directions:
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
def has_color_support(stream):
"""Try to determine if the given stream supports colored output.
Return True only if the stream declares to be a TTY, if it has a
file descriptor on which ncurses can initialize a terminal and if
that terminal's entry in terminfo declares support for colors.
stream (fileobj): a file-like object (that adheres to the API
declared in the `io' package).
return (bool): True if we're sure that colors are supported, False
if they aren't or if we can't tell.
"""
if stream.isatty():
try:
curses.setupterm(fd=stream.fileno())
# See `man terminfo` for capabilities' names and meanings.
if curses.tigetnum("colors") > 0:
return True
# fileno() can raise OSError.
except Exception:
pass
return False
def add_color_to_string(string, color, stream=sys.stdout, bold=False,
force=False):
"""Format the string to be printed with the given color.
Insert formatting characters that, when printed on a terminal, will
make the given string appear with the given foreground color if the
stream passed has color support. Else return the string as it is.
string (string): the string to color.
color (int): the color as a colors constant, like colors.BLACK.
stream (fileobj): a file-like object (that adheres to the API
declared in the `io' package). Defaults to sys.stdout.
bold (bool): True if the string should be bold.
force (bool): True if the string should be formatted even if the
given stream has no color support.
return (string): the formatted string.
"""
if force or has_color_support(stream):
return "%s%s%s%s" % (
curses.tparm(curses.tigetstr("setaf"), color).decode('ascii')
if color != colors.BLACK else "",
curses.tparm(curses.tigetstr("bold")).decode('ascii')
if bold else "",
string,
curses.tparm(curses.tigetstr("sgr0")).decode('ascii')
)
else:
return string
def move_cursor(direction, amount=1, stream=sys.stdout, erase=False):
"""Move the cursor.
If the stream is a TTY, print characters that will move the cursor
in the given direction and optionally erase the line. Else do nothing.
direction (int): the direction as a directions constant, like
directions.UP.
stream (fileobj): a file-like object (that adheres to the API
declared in the `io' package). Defaults to sys.stdout.
erase (bool): True if the line the cursor ends on should be erased.
"""
if stream.isatty():
if direction == directions.UP:
print(curses.tparm(curses.tigetstr("cuu"), amount).decode('ascii'),
file=stream, end='')
elif direction == directions.DOWN:
print(curses.tparm(curses.tigetstr("cud"), amount).decode('ascii'),
file=stream, end='')
elif direction == directions.LEFT:
print(curses.tparm(curses.tigetstr("cub"), amount).decode('ascii'),
file=stream, end='')
elif direction == directions.RIGHT:
print(curses.tparm(curses.tigetstr("cuf"), amount).decode('ascii'),
file=stream, end='')
if erase:
print(curses.tparm(curses.tigetstr("el")).decode('ascii'),
file=stream, end='')
stream.flush()