Mini Shell
#
# Extended VT100 terminal text editor, etc. widgets
# Copyright (c) 2015 Paul Sokolovsky
# Distributed under MIT License
#
import sys
import os
from .editor import *
# Edit single line, quit on Enter/Esc
class LineEditor(Editor):
def handle_cursor_keys(self, key):
if super().handle_cursor_keys(key):
self.just_started = False
return True
return False
def handle_key(self, key):
if key in (KEY_ENTER, KEY_ESC):
return key
if self.just_started:
# Overwrite initial string with new content
self.set_lines([""])
self.col = 0
self.just_started = False
return super().handle_key(key)
def edit(self, line):
self.set_lines([line])
self.col = len(line)
self.adjust_cursor_eol()
self.just_started = True
key = self.loop()
if key == KEY_ENTER:
return self.content[0]
return None
class Viewer(Editor):
def handle_key(self, key):
if key in (KEY_ENTER, KEY_ESC):
return key
if super().handle_cursor_keys(key):
return True
# Viewer with colored lines, (whole line same color)
class LineColorViewer(Viewer):
def show_line(self, l, i):
if self.is_dict_color:
c = self.lines_c.get(i, self.def_c)
else:
try:
c = self.lines_c[i]
except IndexError:
c = self.def_c
self.attr_color(c)
super().show_line(l, i)
self.attr_reset()
def set_line_colors(self, default_color, color_list={}):
self.def_c = default_color
self.lines_c = color_list
self.is_dict_color = isinstance(color_list, dict)
# Viewer with color support, (echo line may consist of spans
# of different colors)
class CharColorViewer(Viewer):
def show_line(self, l, i):
# TODO: handle self.margin, self.width
length = 0
for span in l:
if isinstance(span, tuple):
span, c = span
else:
c = self.def_c
self.attr_color(c)
self.wr(span)
length += len(span)
self.attr_color(self.def_c)
self.clear_num_pos(self.width - length)
self.attr_reset()
def set_def_color(self, default_color):
self.def_c = default_color
class EditorExt(Editor):
screen_width = 80
def __init__(self, left=0, top=0, width=80, height=24):
super().__init__(left, top, width, height)
# +1 assumes there's a border around editor pane
self.status_y = top + height + 1
def get_cur_line(self):
return self.content[self.cur_line]
def line_visible(self, no):
return self.top_line <= no < self.top_line + self.height
# If line "no" is already on screen, just reposition cursor to it and
# return False. Otherwise, show needed line either at the center of
# screen or at the top, and return True.
def goto_line(self, no, col=None, center=True):
self.cur_line = no
if self.line_visible(no):
self.row = no - self.top_line
if col is not None:
self.col = col
if self.adjust_cursor_eol():
self.redraw()
self.set_cursor()
return False
if center:
c = self.height // 2
if no > c:
self.top_line = no - c
self.row = c
else:
self.top_line = 0
self.row = no
else:
self.top_line = no
self.row = 0
if col is not None:
self.col = col
self.adjust_cursor_eol()
self.redraw()
return True
def show_status(self, msg):
self.cursor(False)
self.goto(0, self.status_y)
self.wr(msg)
self.clear_to_eol()
self.set_cursor()
self.cursor(True)
def show_cursor_status(self):
self.cursor(False)
self.goto(0, 31)
self.wr("% 3d:% 3d" % (self.cur_line, self.col + self.margin))
self.set_cursor()
self.cursor(True)
def dialog_edit_line(self, left=None, top=8, width=40, height=3, line="", title=""):
if left is None:
left = (self.screen_width - width) / 2
self.dialog_box(left, top, width, height, title)
e = LineEditor(left + 1, top + 1, width - 2, height - 2)
return e.edit(line)
if __name__ == "__main__":
with open(sys.argv[1]) as f:
content = f.read().splitlines()
#content = f.readlines()
#os.write(1, b"\x1b[18t")
#key = os.read(0, 32)
#print(repr(key))
#key = os.read(0, 32)
#print(repr(key))
#1/0
e = EditorExt(left=1, top=1, width=60, height=25)
e.init_tty()
e.enable_mouse()
s = e.dialog_edit_line(10, 5, 40, 3, title="Enter name:", line="test")
e.cls()
e.deinit_tty()
print()
print(s)
1/0
# e.cls()
e.draw_box(0, 0, 62, 27)
e.set_lines(content)
e.loop()
e.deinit_tty()
Zerion Mini Shell 1.0