Skip to content

Commit ae08e57

Browse files
authored
Merge pull request #2727 from FoamyGuy/add_text_editor
Adding Text editor project code
2 parents 32487e0 + f2815d4 commit ae08e57

File tree

7 files changed

+632
-0
lines changed

7 files changed

+632
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2024 Tim Cocks
2+
#
3+
# SPDX-License-Identifier: MIT
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import select
6+
import sys
7+
# pylint: disable=no-self-use
8+
9+
try:
10+
import termios
11+
12+
_orig_attr = None # pylint: disable=invalid-name
13+
14+
def _nonblocking():
15+
global _orig_attr # pylint: disable=global-statement
16+
_orig_attr = termios.tcgetattr(sys.stdin)
17+
attr = termios.tcgetattr(sys.stdin)
18+
attr[3] &= ~(termios.ECHO | termios.ICANON)
19+
attr[6][termios.VMIN] = 1
20+
attr[6][termios.VTIME] = 0
21+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, attr)
22+
23+
def _blocking():
24+
if _orig_attr is not None:
25+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, _orig_attr)
26+
27+
except ImportError:
28+
29+
def _nonblocking():
30+
pass
31+
32+
def _blocking():
33+
pass
34+
35+
36+
LINES = 24
37+
COLS = 80
38+
39+
special_keys = {
40+
"\x1b": ..., # all prefixes of special keys must be entered as Ellipsis
41+
"\x1b[": ...,
42+
"\x1b[5": ...,
43+
"\x1b[6": ...,
44+
"\x1b[A": "KEY_UP",
45+
"\x1b[B": "KEY_DOWN",
46+
"\x1b[C": "KEY_RIGHT",
47+
"\x1b[D": "KEY_LEFT",
48+
"\x1b[H": "KEY_HOME",
49+
"\x1b[F": "KEY_END",
50+
"\x1b[5~": "KEY_PGUP",
51+
"\x1b[6~": "KEY_PGDN",
52+
"\x1b[3~": "KEY_DELETE",
53+
}
54+
55+
56+
class Screen:
57+
def __init__(self):
58+
self._poll = select.poll()
59+
self._poll.register(sys.stdin, select.POLLIN)
60+
self._pending = ""
61+
62+
def _sys_stdin_readable(self):
63+
return hasattr(sys.stdin, "readable") and sys.stdin.readable()
64+
65+
def _sys_stdout_flush(self):
66+
if hasattr(sys.stdout, "flush"):
67+
sys.stdout.flush()
68+
69+
def _terminal_read_blocking(self):
70+
return sys.stdin.read(1)
71+
72+
def _terminal_read_timeout(self, timeout):
73+
if self._sys_stdin_readable() or self._poll.poll(timeout):
74+
r = sys.stdin.read(1)
75+
return r
76+
return None
77+
78+
def move(self, y, x):
79+
print(end=f"\033[{y+1};{x+1}H")
80+
81+
def erase(self):
82+
print(end="\033H\033[2J")
83+
84+
def addstr(self, y, x, text):
85+
self.move(y, x)
86+
print(end=text)
87+
88+
def getkey(self):
89+
self._sys_stdout_flush()
90+
pending = self._pending
91+
if pending and (code := special_keys.get(pending)) is None:
92+
self._pending = pending[1:]
93+
return pending[0]
94+
95+
while True:
96+
if pending:
97+
c = self._terminal_read_timeout(50)
98+
if c is None:
99+
self._pending = pending[1:]
100+
return pending[0]
101+
else:
102+
c = self._terminal_read_blocking()
103+
c = pending + c
104+
105+
code = special_keys.get(c)
106+
107+
if code is None:
108+
self._pending = c[1:]
109+
return c[0]
110+
if code is not Ellipsis:
111+
return code
112+
113+
pending = c
114+
115+
116+
def wrapper(func, *args, **kwds):
117+
stdscr = Screen()
118+
try:
119+
_nonblocking()
120+
return func(stdscr, *args, **kwds)
121+
finally:
122+
_blocking()
123+
stdscr.move(LINES - 1, 0)
124+
print("\n")

0 commit comments

Comments
 (0)