diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index a1a56473e3d..19affbe02c9 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -33,6 +33,8 @@ import struct import sys import base64 import re +import subprocess +import time if sys.version_info[0] >= 3: xrange = range @@ -72,19 +74,71 @@ SeparateLatin1StringFormat, \ SeparateUtf8StringFormat \ = range(100, 112) -def hasPlot(): - fileName = "/usr/bin/gnuplot" - return os.path.isfile(fileName) and os.access(fileName, os.X_OK) - +# +# matplot based display for array-like structures. +# try: - import subprocess - def arrayForms(): - if hasPlot(): - return "Normal,Plot" - return "Normal" + # FIXME: That might not be the one we want. + pythonExecutable = sys.executable + subprocess.check_call([pythonExecutable, '-c', 'import matplotlib']) + hasPlot = True except: - def arrayForms(): - return "Normal" + hasPlot = False + + +matplotFigure = {} +matplotCount = 0 + +matplotProc = subprocess.Popen(args=[pythonExecutable, "-i"], + bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + +matplotProc.stdin.write(b"import sys\n") +matplotProc.stdin.write(b"sys.ps1=''\n") +matplotProc.stdin.write(b"from matplotlib import pyplot\n") +matplotProc.stdin.write(b"import time\n") +matplotProc.stdin.write(b"pyplot.ion()\n") +matplotProc.stdin.flush() + +def matplotSend(iname, show, data): + global matplotFigure + global matplotCount + + def s(line): + matplotProc.stdin.write(line.encode("latin1")) + matplotProc.stdin.write(b"\n") + sys.stdout.flush() + matplotProc.stdin.flush() + + if show: + s("pyplot.ion()") + if not iname in matplotFigure: + matplotCount += 1 + matplotFigure[iname] = matplotCount + s("pyplot.figure(%s)" % matplotFigure[iname]) + s("pyplot.suptitle('%s')" % iname) + s("data = %s" % data) + s("pyplot.plot([i for i in range(len(data))], data, 'b.')") + time.sleep(0.2) + s("pyplot.draw()") + matplotProc.stdin.flush() + else: + if iname in matplotFigure: + s("pyplot.figure(%s)" % matplotFigure[iname]) + s("pyplot.close()") + del matplotFigure[iname] + + matplotProc.stdin.flush() + +def matplotQuit(): + matplotProc.stdin.write(b"exit") + matplotProc.kill() + +def arrayForms(): + global hasPlot + return "Normal,Plot" if hasPlot else "Normal" + +def mapForms(): + return "Normal,Compact" class ReportItem: @@ -168,12 +222,6 @@ class Blob(object): def extractFloat(self, offset = 0): return struct.unpack_from("f", self.data, offset)[0] -# -# Gnuplot based display for array-like structures. -# -gnuplotPipe = {} -gnuplotPid = {} - def warn(message): print("XXX: %s\n" % message.encode("latin1")) @@ -1409,42 +1457,19 @@ class DumperBase: def putPlotData(self, base, n, typeobj, plotFormat = 2): if self.isExpanded(): self.putArrayData(base, n, typeobj) - if not hasPlot(): - return - if not self.isSimpleType(typeobj): - #self.putValue(self.currentValue.value + " (not plottable)") - self.putValue(self.currentValue.value) - self.putField("plottable", "0") - return - global gnuplotPipe - global gnuplotPid - format = self.currentItemFormat() - iname = self.currentIName - if format != plotFormat: - if iname in gnuplotPipe: - os.kill(gnuplotPid[iname], 9) - del gnuplotPid[iname] - gnuplotPipe[iname].terminate() - del gnuplotPipe[iname] - return - base = self.createPointerValue(base, typeobj) - if not iname in gnuplotPipe: - gnuplotPipe[iname] = subprocess.Popen(["gnuplot"], - stdin=subprocess.PIPE) - gnuplotPid[iname] = gnuplotPipe[iname].pid - f = gnuplotPipe[iname].stdin; - # On Ubuntu install gnuplot-x11 - f.write("set term wxt noraise\n") - f.write("set title 'Data fields'\n") - f.write("set xlabel 'Index'\n") - f.write("set ylabel 'Value'\n") - f.write("set grid\n") - f.write("set style data lines;\n") - f.write("plot '-' title '%s'\n" % iname) - for i in range(0, n): - f.write(" %s\n" % base.dereference()) - base += 1 - f.write("e\n") + if hasPlot: + if self.isSimpleType(typeobj): + show = self.currentItemFormat() == plotFormat + iname = self.currentIName + data = [] + if show: + base = self.createPointerValue(base, typeobj) + data = [str(base[i]) for i in range(0, toInteger(n))] + matplotSend(iname, show, data) + else: + #self.putValue(self.currentValue.value + " (not plottable)") + self.putValue(self.currentValue.value) + self.putField("plottable", "0") def putSpecialArgv(self, value): """ @@ -1638,11 +1663,3 @@ DisplayUtf8String \ = range(6) -def mapForms(): - return "Normal,Compact" - -def arrayForms(): - if hasPlot(): - return "Normal,Plot" - return "Normal" - diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 0b8b7bbb5e7..6dd2157c43b 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -2090,6 +2090,14 @@ def addExtraDumper(args): registerCommand("addExtraDumper", addExtraDumper) +def exitGdb(arg): + if hasPlot: + matplotQuit() + gdb.execute("quit") + return "" + +registerCommand("exitGdb", exitGdb) + ####################################################################### # # Native Mixed diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c25bab5160c..ed9926cd6ad 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1922,7 +1922,7 @@ void GdbEngine::notifyAdapterShutdownOk() case QProcess::Running: if (startParameters().closeMode == KillAndExitMonitorAtClose) postCommand("monitor exit"); - postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit)); + postCommand("exitGdb", GdbEngine::ExitRequest, CB(handleGdbExit)); break; case QProcess::NotRunning: // Cannot find executable.