summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/utils/lui/cui.py
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/utils/lui/cui.py
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/utils/lui/cui.py')
-rwxr-xr-xgnu/llvm/lldb/utils/lui/cui.py338
1 files changed, 338 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/utils/lui/cui.py b/gnu/llvm/lldb/utils/lui/cui.py
new file mode 100755
index 00000000000..fffb812fbb9
--- /dev/null
+++ b/gnu/llvm/lldb/utils/lui/cui.py
@@ -0,0 +1,338 @@
+##===-- cui.py -----------------------------------------------*- Python -*-===##
+##
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+##
+##===----------------------------------------------------------------------===##
+
+import curses
+import curses.ascii
+import threading
+
+
+class CursesWin(object):
+
+ def __init__(self, x, y, w, h):
+ self.win = curses.newwin(h, w, y, x)
+ self.focus = False
+
+ def setFocus(self, focus):
+ self.focus = focus
+
+ def getFocus(self):
+ return self.focus
+
+ def canFocus(self):
+ return True
+
+ def handleEvent(self, event):
+ return
+
+ def draw(self):
+ return
+
+
+class TextWin(CursesWin):
+
+ def __init__(self, x, y, w):
+ super(TextWin, self).__init__(x, y, w, 1)
+ self.win.bkgd(curses.color_pair(1))
+ self.text = ''
+ self.reverse = False
+
+ def canFocus(self):
+ return False
+
+ def draw(self):
+ w = self.win.getmaxyx()[1]
+ text = self.text
+ if len(text) > w:
+ #trunc_length = len(text) - w
+ text = text[-w + 1:]
+ if self.reverse:
+ self.win.addstr(0, 0, text, curses.A_REVERSE)
+ else:
+ self.win.addstr(0, 0, text)
+ self.win.noutrefresh()
+
+ def setReverse(self, reverse):
+ self.reverse = reverse
+
+ def setText(self, text):
+ self.text = text
+
+
+class TitledWin(CursesWin):
+
+ def __init__(self, x, y, w, h, title):
+ super(TitledWin, self).__init__(x, y + 1, w, h - 1)
+ self.title = title
+ self.title_win = TextWin(x, y, w)
+ self.title_win.setText(title)
+ self.draw()
+
+ def setTitle(self, title):
+ self.title_win.setText(title)
+
+ def draw(self):
+ self.title_win.setReverse(self.getFocus())
+ self.title_win.draw()
+ self.win.noutrefresh()
+
+
+class ListWin(CursesWin):
+
+ def __init__(self, x, y, w, h):
+ super(ListWin, self).__init__(x, y, w, h)
+ self.items = []
+ self.selected = 0
+ self.first_drawn = 0
+ self.win.leaveok(True)
+
+ def draw(self):
+ if len(self.items) == 0:
+ self.win.erase()
+ return
+
+ h, w = self.win.getmaxyx()
+
+ allLines = []
+ firstSelected = -1
+ lastSelected = -1
+ for i, item in enumerate(self.items):
+ lines = self.items[i].split('\n')
+ lines = lines if lines[len(lines) - 1] != '' else lines[:-1]
+ if len(lines) == 0:
+ lines = ['']
+
+ if i == self.getSelected():
+ firstSelected = len(allLines)
+ allLines.extend(lines)
+ if i == self.selected:
+ lastSelected = len(allLines) - 1
+
+ if firstSelected < self.first_drawn:
+ self.first_drawn = firstSelected
+ elif lastSelected >= self.first_drawn + h:
+ self.first_drawn = lastSelected - h + 1
+
+ self.win.erase()
+
+ begin = self.first_drawn
+ end = begin + h
+
+ y = 0
+ for i, line in list(enumerate(allLines))[begin:end]:
+ attr = curses.A_NORMAL
+ if i >= firstSelected and i <= lastSelected:
+ attr = curses.A_REVERSE
+ line = '{0:{width}}'.format(line, width=w - 1)
+
+ # Ignore the error we get from drawing over the bottom-right char.
+ try:
+ self.win.addstr(y, 0, line[:w], attr)
+ except curses.error:
+ pass
+ y += 1
+ self.win.noutrefresh()
+
+ def getSelected(self):
+ if self.items:
+ return self.selected
+ return -1
+
+ def setSelected(self, selected):
+ self.selected = selected
+ if self.selected < 0:
+ self.selected = 0
+ elif self.selected >= len(self.items):
+ self.selected = len(self.items) - 1
+
+ def handleEvent(self, event):
+ if isinstance(event, int):
+ if len(self.items) > 0:
+ if event == curses.KEY_UP:
+ self.setSelected(self.selected - 1)
+ if event == curses.KEY_DOWN:
+ self.setSelected(self.selected + 1)
+ if event == curses.ascii.NL:
+ self.handleSelect(self.selected)
+
+ def addItem(self, item):
+ self.items.append(item)
+
+ def clearItems(self):
+ self.items = []
+
+ def handleSelect(self, index):
+ return
+
+
+class InputHandler(threading.Thread):
+
+ def __init__(self, screen, queue):
+ super(InputHandler, self).__init__()
+ self.screen = screen
+ self.queue = queue
+
+ def run(self):
+ while True:
+ c = self.screen.getch()
+ self.queue.put(c)
+
+
+class CursesUI(object):
+ """ Responsible for updating the console UI with curses. """
+
+ def __init__(self, screen, event_queue):
+ self.screen = screen
+ self.event_queue = event_queue
+
+ curses.start_color()
+ curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
+ curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK)
+ curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
+ self.screen.bkgd(curses.color_pair(1))
+ self.screen.clear()
+
+ self.input_handler = InputHandler(self.screen, self.event_queue)
+ self.input_handler.daemon = True
+
+ self.focus = 0
+
+ self.screen.refresh()
+
+ def focusNext(self):
+ self.wins[self.focus].setFocus(False)
+ old = self.focus
+ while True:
+ self.focus += 1
+ if self.focus >= len(self.wins):
+ self.focus = 0
+ if self.wins[self.focus].canFocus():
+ break
+ self.wins[self.focus].setFocus(True)
+
+ def handleEvent(self, event):
+ if isinstance(event, int):
+ if event == curses.KEY_F3:
+ self.focusNext()
+
+ def eventLoop(self):
+
+ self.input_handler.start()
+ self.wins[self.focus].setFocus(True)
+
+ while True:
+ self.screen.noutrefresh()
+
+ for i, win in enumerate(self.wins):
+ if i != self.focus:
+ win.draw()
+ # Draw the focused window last so that the cursor shows up.
+ if self.wins:
+ self.wins[self.focus].draw()
+ curses.doupdate() # redraw the physical screen
+
+ event = self.event_queue.get()
+
+ for win in self.wins:
+ if isinstance(event, int):
+ if win.getFocus() or not win.canFocus():
+ win.handleEvent(event)
+ else:
+ win.handleEvent(event)
+ self.handleEvent(event)
+
+
+class CursesEditLine(object):
+ """ Embed an 'editline'-compatible prompt inside a CursesWin. """
+
+ def __init__(self, win, history, enterCallback, tabCompleteCallback):
+ self.win = win
+ self.history = history
+ self.enterCallback = enterCallback
+ self.tabCompleteCallback = tabCompleteCallback
+
+ self.prompt = ''
+ self.content = ''
+ self.index = 0
+ self.startx = -1
+ self.starty = -1
+
+ def draw(self, prompt=None):
+ if not prompt:
+ prompt = self.prompt
+ (h, w) = self.win.getmaxyx()
+ if (len(prompt) + len(self.content)) / w + self.starty >= h - 1:
+ self.win.scroll(1)
+ self.starty -= 1
+ if self.starty < 0:
+ raise RuntimeError('Input too long; aborting')
+ (y, x) = (self.starty, self.startx)
+
+ self.win.move(y, x)
+ self.win.clrtobot()
+ self.win.addstr(y, x, prompt)
+ remain = self.content
+ self.win.addstr(remain[:w - len(prompt)])
+ remain = remain[w - len(prompt):]
+ while remain != '':
+ y += 1
+ self.win.addstr(y, 0, remain[:w])
+ remain = remain[w:]
+
+ length = self.index + len(prompt)
+ self.win.move(self.starty + length / w, length % w)
+
+ def showPrompt(self, y, x, prompt=None):
+ self.content = ''
+ self.index = 0
+ self.startx = x
+ self.starty = y
+ self.draw(prompt)
+
+ def handleEvent(self, event):
+ if not isinstance(event, int):
+ return # not handled
+ key = event
+
+ if self.startx == -1:
+ raise RuntimeError('Trying to handle input without prompt')
+
+ if key == curses.ascii.NL:
+ self.enterCallback(self.content)
+ elif key == curses.ascii.TAB:
+ self.tabCompleteCallback(self.content)
+ elif curses.ascii.isprint(key):
+ self.content = self.content[:self.index] + \
+ chr(key) + self.content[self.index:]
+ self.index += 1
+ elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS:
+ if self.index > 0:
+ self.index -= 1
+ self.content = self.content[
+ :self.index] + self.content[self.index + 1:]
+ elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT:
+ self.content = self.content[
+ :self.index] + self.content[self.index + 1:]
+ elif key == curses.ascii.VT: # CTRL-K
+ self.content = self.content[:self.index]
+ elif key == curses.KEY_LEFT or key == curses.ascii.STX: # left or CTRL-B
+ if self.index > 0:
+ self.index -= 1
+ elif key == curses.KEY_RIGHT or key == curses.ascii.ACK: # right or CTRL-F
+ if self.index < len(self.content):
+ self.index += 1
+ elif key == curses.ascii.SOH: # CTRL-A
+ self.index = 0
+ elif key == curses.ascii.ENQ: # CTRL-E
+ self.index = len(self.content)
+ elif key == curses.KEY_UP or key == curses.ascii.DLE: # up or CTRL-P
+ self.content = self.history.previous(self.content)
+ self.index = len(self.content)
+ elif key == curses.KEY_DOWN or key == curses.ascii.SO: # down or CTRL-N
+ self.content = self.history.next()
+ self.index = len(self.content)
+ self.draw()