marmots/util.py

147 lines
4.9 KiB
Python

# This file is part of MarMOTS.
#
# MarMOTS 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.
#
# MarMOTS 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 MarMOTS. If not,
# see <https://www.gnu.org/licenses/>.
#
# Copyright 2009, 2010, 2011, 2020 Jeremy Penner
from tpers import TPrs
import ansi_cython as ansi
# probably reinventing the wheel :/
class Rgseq(TPrs):
def InitPersistent(self, *rgseq):
self.rgseq = rgseq
def __len__(self):
return sum([len(seq) for seq in self.rgseq])
def __getitem__(self, i):
c = 0
for seq in self.rgseq:
cSeq = len(seq)
if i < c + cSeq:
return seq[i - c]
c = c + cSeq
raise IndexError
def index(self, o):
c = 0
for seq in self.rgseq:
try:
iSeq = seq.index(o)
return iSeq + c
except ValueError:
c = c + len(seq)
raise ValueError
class Snippet(object):
def __init__(self, st, ichStart, ichLim):
self.st = st
self.ichStart = ichStart
self.ichLim = ichLim
def RgstWrapped(st, w, fForEditing = False, dxStart = 0):
return [snippet.st for snippet in RgSnippetWrapped(st, w, fForEditing, dxStart)]
def RgSnippetWrapped(st, w, fForEditing = False, xStart = 0):
ichWrap = -1
ichStart = 0
for ich, ch in enumerate(st):
if ch == '\n':
assert not fForEditing, "no support yet for editing strings with newlines"
ichWrap = ich
if not fForEditing and ch == ' ':
ichWrap = ich
if (ich == ichStart + w - xStart) or (ch == '\n'):
ichStartNew = ichWrap + 1
if ichWrap < 0:
ichWrap = ich
ichStartNew = ich
elif fForEditing: # don't swallow spaces
ichWrap = ichStartNew
yield Snippet(st[ichStart:ichWrap], ichStart, ichStartNew)
ichStart = ichStartNew
ichWrap = -1
xStart = 0
if fForEditing and ch == ' ':
ichWrap = ich
if ichStart < len(st) or ichStart == 0:
yield Snippet(st[ichStart:], ichStart, len(st))
# selection helpers
def IoInc(rgo, io, fnSelectable, fRebound = True):
io = io + 1
while io < len(rgo) and not fnSelectable(rgo[io]):
io = io + 1
if io >= len(rgo) or not fnSelectable(rgo[io]):
if fRebound:
return IoDec(rgo, io, fnSelectable, False)
return -1
return io
def IoDec(rgo, io, fnSelectable, fRebound = True):
io = io - 1
while io > 0 and not fnSelectable(rgo[io]):
io = io - 1
if io < 0 or not fnSelectable(rgo[io]):
if fRebound:
return IoInc(rgo, io, fnSelectable, False)
return -1
return io
class Stedit(TPrs):
def InitPersistent(self, dgEnter = None, stInitial = ""):
self.dgEnter = dgEnter
self.SetValue(stInitial)
def SetValue(self, st):
self.st = st
self.ich = len(st)
def GetValue(self):
return self.st
def StForSize(self, fSel = True):
if fSel and self.ich == len(self.st):
return self.st + "_"
return self.st
def HandleKey(self, key):
if key == ansi.K_LEFT and self.ich > 0:
self.ich = self.ich - 1
elif key == ansi.K_RIGHT and self.ich < len(self.st):
self.ich = self.ich + 1
elif key == ansi.K_BACKSPACE and self.ich > 0:
self.st = self.st[:self.ich - 1] + self.st[self.ich:]
self.ich = self.ich - 1
elif key == ansi.K_DEL and self.ich < len(self.st):
self.st = self.st[:self.ich] + self.st[self.ich + 1:]
elif key == ansi.K_HOME:
self.ich = 0
elif key == ansi.K_END:
self.ich = len(self.st)
elif ansi.FKeyPrintable(key):
self.st = self.st[:self.ich] + key + self.st[self.ich:]
self.ich = self.ich + 1
elif ansi.FEnter(key) and self.dgEnter != None:
if not self.dgEnter(self.st):
self.st = ""
self.ich = 0
else:
return False
return True
def DrawCursor(self, ascr, x, y, colFg, colBg, snippet):
if self.ich >= snippet.ichStart and (snippet.ichLim < 0 or self.ich < snippet.ichLim):
if self.ich == len(self.st):
ch = ' '
else:
ch = self.st[self.ich]
ascr.PutAch(ansi.MkAch(ch, colFg, colBg), x + self.ich - snippet.ichStart, y)