Skip to content

Commit

Permalink
Revert "Refactor termios stuff in unix console"
Browse files Browse the repository at this point in the history
This reverts commit 2a7e81d.
  • Loading branch information
pablogsal committed Apr 29, 2024
1 parent aa9eaf3 commit 8c368d0
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 375 deletions.
68 changes: 68 additions & 0 deletions Lib/_pyrepl/_minimal_curses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Minimal '_curses' module, the low-level interface for curses module
which is not meant to be used directly.
Based on ctypes. It's too incomplete to be really called '_curses', so
to use it, you have to import it and stick it in sys.modules['_curses']
manually.
Note that there is also a built-in module _minimal_curses which will
hide this one if compiled in.
"""

import ctypes
import ctypes.util


class error(Exception):
pass


def _find_clib():
trylibs = ["ncursesw", "ncurses", "curses"]

for lib in trylibs:
path = ctypes.util.find_library(lib)
if path:
return path
raise ModuleNotFoundError("curses library not found", name="_minimal_curses")


_clibpath = _find_clib()
clib = ctypes.cdll.LoadLibrary(_clibpath)

clib.setupterm.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.POINTER(ctypes.c_int)]
clib.setupterm.restype = ctypes.c_int

clib.tigetstr.argtypes = [ctypes.c_char_p]
clib.tigetstr.restype = ctypes.POINTER(ctypes.c_char)

clib.tparm.argtypes = [ctypes.c_char_p] + 9 * [ctypes.c_int]
clib.tparm.restype = ctypes.c_char_p

OK = 0
ERR = -1

# ____________________________________________________________


def setupterm(termstr, fd):
err = ctypes.c_int(0)
result = clib.setupterm(termstr, fd, ctypes.byref(err))
if result == ERR:
raise error("setupterm() failed (err=%d)" % err.value)


def tigetstr(cap):
if not isinstance(cap, bytes):
cap = cap.encode("ascii")
result = clib.tigetstr(cap)
if ctypes.cast(result, ctypes.c_void_p).value == ERR:
return None
return ctypes.cast(result, ctypes.c_char_p).value


def tparm(str, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0):
result = clib.tparm(str, i1, i2, i3, i4, i5, i6, i7, i8, i9)
if result is None:
raise error("tparm() returned NULL")
return result
223 changes: 13 additions & 210 deletions Lib/_pyrepl/fancy_termios.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import curses
import termios


class InvalidTerminal(RuntimeError):
pass


class TermState:
def __init__(self, tuples):
(
Expand Down Expand Up @@ -60,212 +55,20 @@ def tcsetattr(fd, when, attrs):
termios.tcsetattr(fd, when, attrs.as_list())


class TermCapability:
"""Base class for all terminal capabilities we need"""

def __init__(self, buffer):
self._buffer = buffer
self._args = []

self._bytes = curses.tigetstr(self.name)
if self._bytes is None and not self.optional:
raise InvalidTerminal(
f"terminal doesn't have the required {self.name!r} capability"
)

self.supported = self._bytes is not None

def __call__(self, *args):
if self.supported:
self._args = args
self._buffer.push(self)

def text(self):
return curses.tparm(self._bytes, *self._args)


class Bell(TermCapability):
"""Audible signal (bell)"""

name = "bel"
optional = False


class CursorInvisible(TermCapability):
"""Make cursor invisible"""

name = "civis"
optional = True


class ClearScreen(TermCapability):
"""Clear screen and home cursor"""

name = "clear"
optional = False


class CursorNormal(TermCapability):
"""Make cursor appear normal (undo civis/cvvis)"""

name = "cnorm"
optional = True


class ParmLeftCursor(TermCapability):
"""Move #1 characters to the left"""

name = "cub"
optional = True


class CursorLeft(TermCapability):
"""Move left one space"""

name = "cub1"
optional = True

def text(self):
assert len(self._args) == 1 # cursor_down needs to have been called with dx
return curses.tparm(self._args[0] * self._bytes)


class ParmDownCursor(TermCapability):
"""Down #1 lines"""

name = "cud"
optional = True


class CursorDown(TermCapability):
"""Down one line"""

name = "cud1"
optional = True

def text(self):
assert len(self._args) == 1 # cursor_down needs to have been called with dy
return curses.tparm(self._args[0] * self._bytes)


class ParmRightCursor(TermCapability):
"""Move #1 characters to the right"""

name = "cuf"
optional = True


class CursorRight(TermCapability):
"""Non-destructive space (move right one space)"""

name = "cuf1"
optional = True

def text(self):
assert len(self._args) == 1 # cursor_down needs to have been called with dx
return curses.tparm(self._args[0] * self._bytes)


class CursorAddress(TermCapability):
"""Move to row #1 columns #2"""

name = "cup"
optional = False


class ParmUpCursor(TermCapability):
"""Up #1 lines"""

name = "cuu"
optional = True


class CursorUp(TermCapability):
"""Up 1 line"""

name = "cuu1"
optional = True

def text(self):
assert len(self._args) == 1 # cursor_down needs to have been called with dy
return curses.tparm(self._args[0] * self._bytes)


class ParmDeleteCharacter(TermCapability):
"""Delete #1 characters"""

name = "dch"
optional = True


class DeleteCharacter(TermCapability):
"""Delete character"""

name = "dch1"
optional = True


class ClearEol(TermCapability):
"""Clear to end of line"""

name = "el"
optional = False


class ColumnAddress(TermCapability):
"""Horizontal position #1, absolute"""

name = "hpa"
optional = True


class ParmInsertCharacter(TermCapability):
"""Insert #1 characters"""

name = "ich"
optional = True


class InsertCharacter(TermCapability):
"""Insert character"""

name = "ich1"
optional = True


class ScrollForward(TermCapability):
"""Scroll text up"""

name = "ind"
optional = True


class PadChar(TermCapability):
"""Padding char (instead of null)"""

name = "pad"
optional = True

def text(self, nchars):
return self._bytes * nchars


class ScrollReverse(TermCapability):
"""Scroll text down"""

name = "ri"
optional = True


class KeypadLocal(TermCapability):
"""Leave 'keyboard_transmit' mode"""
class Term(TermState):
TS__init__ = TermState.__init__

name = "rmkx"
optional = True
def __init__(self, fd=0):
self.TS__init__(termios.tcgetattr(fd))
self.fd = fd
self.stack = []

def save(self):
self.stack.append(self.as_list())

class KeypadXmit(TermCapability):
"""Enter 'keyboard_transmit' mode"""
def set(self, when=termios.TCSANOW):
termios.tcsetattr(self.fd, when, self.as_list())

name = "smkx"
optional = True
def restore(self):
self.TS__init__(self.stack.pop())
self.set()
Loading

0 comments on commit 8c368d0

Please sign in to comment.