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