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