xref: /openbsd-src/gnu/llvm/lldb/utils/lui/commandwin.py (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
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