Skip to content

Commit ec23fb3

Browse files
committed
adding text editor project
1 parent 32487e0 commit ec23fb3

File tree

7 files changed

+625
-0
lines changed

7 files changed

+625
-0
lines changed

CircuitPython_Text_Editor/adafruit_editor/__init__.py

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

0 commit comments

Comments
 (0)