1*061da546Spatrick##===-- commandwin.py ----------------------------------------*- Python -*-===## 2*061da546Spatrick## 3*061da546Spatrick# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*061da546Spatrick# See https://llvm.org/LICENSE.txt for license information. 5*061da546Spatrick# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*061da546Spatrick## 7*061da546Spatrick##===----------------------------------------------------------------------===## 8*061da546Spatrick 9*061da546Spatrickimport cui 10*061da546Spatrickimport curses 11*061da546Spatrickimport lldb 12*061da546Spatrickfrom itertools import islice 13*061da546Spatrick 14*061da546Spatrick 15*061da546Spatrickclass History(object): 16*061da546Spatrick 17*061da546Spatrick def __init__(self): 18*061da546Spatrick self.data = {} 19*061da546Spatrick self.pos = 0 20*061da546Spatrick self.tempEntry = '' 21*061da546Spatrick 22*061da546Spatrick def previous(self, curr): 23*061da546Spatrick if self.pos == len(self.data): 24*061da546Spatrick self.tempEntry = curr 25*061da546Spatrick 26*061da546Spatrick if self.pos < 0: 27*061da546Spatrick return '' 28*061da546Spatrick if self.pos == 0: 29*061da546Spatrick self.pos -= 1 30*061da546Spatrick return '' 31*061da546Spatrick if self.pos > 0: 32*061da546Spatrick self.pos -= 1 33*061da546Spatrick return self.data[self.pos] 34*061da546Spatrick 35*061da546Spatrick def next(self): 36*061da546Spatrick if self.pos < len(self.data): 37*061da546Spatrick self.pos += 1 38*061da546Spatrick 39*061da546Spatrick if self.pos < len(self.data): 40*061da546Spatrick return self.data[self.pos] 41*061da546Spatrick elif self.tempEntry != '': 42*061da546Spatrick return self.tempEntry 43*061da546Spatrick else: 44*061da546Spatrick return '' 45*061da546Spatrick 46*061da546Spatrick def add(self, c): 47*061da546Spatrick self.tempEntry = '' 48*061da546Spatrick self.pos = len(self.data) 49*061da546Spatrick if self.pos == 0 or self.data[self.pos - 1] != c: 50*061da546Spatrick self.data[self.pos] = c 51*061da546Spatrick self.pos += 1 52*061da546Spatrick 53*061da546Spatrick 54*061da546Spatrickclass CommandWin(cui.TitledWin): 55*061da546Spatrick 56*061da546Spatrick def __init__(self, driver, x, y, w, h): 57*061da546Spatrick super(CommandWin, self).__init__(x, y, w, h, "Commands") 58*061da546Spatrick self.command = "" 59*061da546Spatrick self.data = "" 60*061da546Spatrick driver.setSize(w, h) 61*061da546Spatrick 62*061da546Spatrick self.win.scrollok(1) 63*061da546Spatrick 64*061da546Spatrick self.driver = driver 65*061da546Spatrick self.history = History() 66*061da546Spatrick 67*061da546Spatrick def enterCallback(content): 68*061da546Spatrick self.handleCommand(content) 69*061da546Spatrick 70*061da546Spatrick def tabCompleteCallback(content): 71*061da546Spatrick self.data = content 72*061da546Spatrick matches = lldb.SBStringList() 73*061da546Spatrick commandinterpreter = self.getCommandInterpreter() 74*061da546Spatrick commandinterpreter.HandleCompletion( 75*061da546Spatrick self.data, self.el.index, 0, -1, matches) 76*061da546Spatrick if matches.GetSize() == 2: 77*061da546Spatrick self.el.content += matches.GetStringAtIndex(0) 78*061da546Spatrick self.el.index = len(self.el.content) 79*061da546Spatrick self.el.draw() 80*061da546Spatrick else: 81*061da546Spatrick self.win.move(self.el.starty, self.el.startx) 82*061da546Spatrick self.win.scroll(1) 83*061da546Spatrick self.win.addstr("Available Completions:") 84*061da546Spatrick self.win.scroll(1) 85*061da546Spatrick for m in islice(matches, 1, None): 86*061da546Spatrick self.win.addstr(self.win.getyx()[0], 0, m) 87*061da546Spatrick self.win.scroll(1) 88*061da546Spatrick self.el.draw() 89*061da546Spatrick 90*061da546Spatrick self.startline = self.win.getmaxyx()[0] - 2 91*061da546Spatrick 92*061da546Spatrick self.el = cui.CursesEditLine( 93*061da546Spatrick self.win, 94*061da546Spatrick self.history, 95*061da546Spatrick enterCallback, 96*061da546Spatrick tabCompleteCallback) 97*061da546Spatrick self.el.prompt = self.driver.getPrompt() 98*061da546Spatrick self.el.showPrompt(self.startline, 0) 99*061da546Spatrick 100*061da546Spatrick def handleCommand(self, cmd): 101*061da546Spatrick # enter! 102*061da546Spatrick self.win.scroll(1) # TODO: scroll more for longer commands 103*061da546Spatrick if cmd == '': 104*061da546Spatrick cmd = self.history.previous('') 105*061da546Spatrick elif cmd in ('q', 'quit'): 106*061da546Spatrick self.driver.terminate() 107*061da546Spatrick return 108*061da546Spatrick 109*061da546Spatrick self.history.add(cmd) 110*061da546Spatrick ret = self.driver.handleCommand(cmd) 111*061da546Spatrick if ret.Succeeded(): 112*061da546Spatrick out = ret.GetOutput() 113*061da546Spatrick attr = curses.A_NORMAL 114*061da546Spatrick else: 115*061da546Spatrick out = ret.GetError() 116*061da546Spatrick attr = curses.color_pair(3) # red on black 117*061da546Spatrick self.win.addstr(self.startline, 0, out + '\n', attr) 118*061da546Spatrick self.win.scroll(1) 119*061da546Spatrick self.el.showPrompt(self.startline, 0) 120*061da546Spatrick 121*061da546Spatrick def handleEvent(self, event): 122*061da546Spatrick if isinstance(event, int): 123*061da546Spatrick if event == curses.ascii.EOT and self.el.content == '': 124*061da546Spatrick # When the command is empty, treat CTRL-D as EOF. 125*061da546Spatrick self.driver.terminate() 126*061da546Spatrick return 127*061da546Spatrick self.el.handleEvent(event) 128*061da546Spatrick 129*061da546Spatrick def getCommandInterpreter(self): 130*061da546Spatrick return self.driver.getCommandInterpreter() 131