--- a/eric6/MicroPython/MicroPythonWidget.py Thu Aug 15 17:19:28 2019 +0200 +++ b/eric6/MicroPython/MicroPythonWidget.py Fri Aug 16 17:17:32 2019 +0200 @@ -11,6 +11,7 @@ import re import time +import os from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint, QEvent from PyQt5.QtGui import QColor, QKeySequence, QTextCursor, QBrush @@ -22,6 +23,7 @@ from E5Gui.E5ZoomWidget import E5ZoomWidget from E5Gui import E5MessageBox, E5FileDialog from E5Gui.E5Application import e5App +from E5Gui.E5ProcessDialog import E5ProcessDialog from .Ui_MicroPythonWidget import Ui_MicroPythonWidget @@ -41,6 +43,7 @@ import Globals import UI.PixmapCache import Preferences +import Utilities # ANSI Colors (see https://en.wikipedia.org/wiki/ANSI_escape_code) AnsiColorSchemes = { @@ -1087,7 +1090,6 @@ else: hasTime = False - # TODO: add menu entry to cross-compile a .py file (using mpy-cross) act = self.__superMenu.addAction( self.tr("Show Version"), self.__showDeviceVersion) act.setEnabled(self.__connected) @@ -1105,6 +1107,14 @@ self.__superMenu.addAction( self.tr("Show Local Time"), self.__showLocalTime) self.__superMenu.addSeparator() + if not Globals.isWindowsPlatform(): + self.__superMenu.addAction( + self.tr("Compile Python File"), self.__compileFile2Mpy) + act = self.__superMenu.addAction( + self.tr("Compile Current Editor"), self.__compileEditor2Mpy) + aw = e5App().getObject("ViewManager").activeWindow() + act.setEnabled(bool(aw)) + self.__superMenu.addSeparator() if self.__device: self.__device.addDeviceMenuEntries(self.__superMenu) @@ -1261,3 +1271,89 @@ self.tr("<p>There was an error communicating with the connected" " device.</p><p>Method: {0}</p><p>Message: {1}</p>") .format(method, error)) + + def __crossCompile(self, pythonFile="", title=""): + """ + Private method to cross compile a Python file to a .mpy file. + + @param pythonFile name of the Python file to be compiled + @type str + @param title title for the various dialogs + @type str + """ + program = Preferences.getMicroPython("MpyCrossCompiler") + if not program: + program = "mpy-cross" + if not Utilities.isinpath(program): + E5MessageBox.critical( + self, + title, + self.tr("""The MicroPython cross compiler""" + """ <b>mpy-cross</b> cannot be found. Ensure it""" + """ is in the search path or configure it on""" + """ the MicroPython configuration page.""")) + return + + if not pythonFile: + defaultDirectory = "" + aw = e5App().getObject("ViewManager").activeWindow() + if aw: + fn = aw.getFileName() + if fn: + defaultDirectory = os.path.dirname(fn) + if not defaultDirectory: + defaultDirectory = Preferences.getMultiProject("Workspace") + pythonFile = E5FileDialog.getOpenFileName( + self, + title, + defaultDirectory, + self.tr("Python Files (*.py);;All Files (*)")) + if not pythonFile: + # user cancelled + return + + if not os.path.exists(pythonFile): + E5MessageBox.critical( + self, + title, + self.tr("""The Python file <b>{0}</b> does not exist.""" + """ Aborting...""").format(pythonFile)) + return + + compileArgs = [ + pythonFile, + ] + dlg = E5ProcessDialog(self.tr("'mpy-cross' Output"), title) + res = dlg.startProcess(program, compileArgs) + if res: + dlg.exec_() + + @pyqtSlot() + def __compileFile2Mpy(self): + """ + Private slot to cross compile a Python file (*.py) to a .mpy file. + """ + self.__crossCompile(title=self.tr("Compile Python File")) + + @pyqtSlot() + def __compileEditor2Mpy(self): + """ + Private slot to cross compile the current editor to a .mpy file. + """ + aw = e5App().getObject("ViewManager").activeWindow() + if not aw.checkDirty(): + # editor still has unsaved changes, abort... + return + if not aw.isPyFile(): + # no Python file + E5MessageBox.critical( + self, + self.tr("Compile Current Editor"), + self.tr("""The current editor does not contain a Python""" + """ file. Aborting...""")) + return + + self.__crossCompile( + pythonFile=aw.getFileName(), + title=self.tr("Compile Current Editor") + )