--- a/src/eric7/Project/Project.py Mon Jul 11 16:09:04 2022 +0200 +++ b/src/eric7/Project/Project.py Mon Jul 11 16:42:50 2022 +0200 @@ -52,6 +52,8 @@ from Tasks.TasksFile import TasksFile +from CodeFormatting.BlackFormattingAction import BlackFormattingAction + class Project(QObject): """ @@ -2346,6 +2348,7 @@ self.menuMakeAct.setEnabled( self.pdata["MAKEPARAMS"]["MakeEnabled"]) self.menuOtherToolsAct.setEnabled(True) + self.menuFormattingAct.setEnabled(True) self.projectAboutToBeCreated.emit() @@ -3039,6 +3042,7 @@ self.menuMakeAct.setEnabled( self.pdata["MAKEPARAMS"]["MakeEnabled"]) self.menuOtherToolsAct.setEnabled(True) + self.menuFormattingAct.setEnabled(True) # open a project debugger properties file being quiet # about errors @@ -3296,6 +3300,7 @@ self.makeGrp.setEnabled(False) self.menuMakeAct.setEnabled(False) self.menuOtherToolsAct.setEnabled(False) + self.menuFormattingAct.setEnabled(False) self.__model.projectClosed() self.projectClosedHooks.emit() @@ -3505,10 +3510,14 @@ pwl = "" if self.pdata["SPELLWORDS"]: pwl = os.path.join(self.ppath, self.pdata["SPELLWORDS"]) + if not os.path.isfile(pwl): + pwl = "" pel = "" if self.pdata["SPELLEXCLUDES"]: pel = os.path.join(self.ppath, self.pdata["SPELLEXCLUDES"]) + if not os.path.isfile(pel): + pel = "" return (pwl, pel) @@ -3923,6 +3932,10 @@ """ self.actions = [] + ################################################################### + ## Project actions + ################################################################### + self.actGrp1 = createActionGroup(self) act = EricAction( @@ -3988,7 +4001,11 @@ )) self.saveasAct.triggered.connect(self.saveProjectAs) self.actions.append(self.saveasAct) - + + ################################################################### + ## Project management actions + ################################################################### + self.actGrp2 = createActionGroup(self) self.addFilesAct = EricAction( @@ -4128,7 +4145,11 @@ )) self.lexersAct.triggered.connect(self.__showLexerAssociations) self.actions.append(self.lexersAct) - + + ################################################################### + ## Project debug actions + ################################################################### + self.dbgActGrp = createActionGroup(self) act = EricAction( @@ -4193,8 +4214,12 @@ act.triggered.connect(self.__initDebugProperties) self.actions.append(act) + ################################################################### + ## Project session actions + ################################################################### + self.sessActGrp = createActionGroup(self) - + act = EricAction( self.tr('Load session'), self.tr('Load session'), 0, 0, @@ -4243,6 +4268,10 @@ act.triggered.connect(self.__deleteSession) self.actions.append(act) + ################################################################### + ## Project Tools - check actions + ################################################################### + self.chkGrp = createActionGroup(self) self.codeMetricsAct = EricAction( @@ -4285,6 +4314,10 @@ )) self.codeProfileAct.triggered.connect(self.__showProfileData) self.actions.append(self.codeProfileAct) + + ################################################################### + ## Project Tools - graphics actions + ################################################################### self.graphicsGrp = createActionGroup(self) @@ -4314,9 +4347,13 @@ )) self.loadDiagramAct.triggered.connect(self.__loadDiagram) self.actions.append(self.loadDiagramAct) - + + ################################################################### + ## Project Tools - plugin packaging actions + ################################################################### + self.pluginGrp = createActionGroup(self) - + self.pluginPkgListAct = EricAction( self.tr('Create Package List'), UI.PixmapCache.getIcon("pluginArchiveList"), @@ -4368,6 +4405,10 @@ self.pluginSArchiveAct.triggered.connect( self.__pluginCreateSnapshotArchives) self.actions.append(self.pluginSArchiveAct) + + ################################################################### + ## Project Tools - make actions + ################################################################### self.makeGrp = createActionGroup(self) @@ -4400,10 +4441,16 @@ lambda: self.__executeMake(questionOnly=True)) self.actions.append(self.makeTestAct) + ################################################################### + ## Project Tools - other tools actions + ################################################################### + + self.othersGrp = createActionGroup(self) + self.createSBOMAct = EricAction( self.tr('Create SBOM File'), self.tr('Create &SBOM File'), 0, 0, - self, 'project_create_sbom') + self.othersGrp, 'project_create_sbom') self.createSBOMAct.setStatusTip( self.tr("Create a SBOM file of the project dependencies.")) self.createSBOMAct.setWhatsThis(self.tr( @@ -4414,7 +4461,96 @@ )) self.createSBOMAct.triggered.connect(self.__createSBOMFile) self.actions.append(self.createSBOMAct) - + + ################################################################### + ## Project Tools - code formatting actions + ################################################################### + + self.blackFormattingGrp = createActionGroup(self) + + self.blackAboutAct = EricAction( + self.tr("About Black"), + self.tr("&Black"), + 0, 0, + self.blackFormattingGrp, "project_black_about" + ) + self.blackAboutAct.setStatusTip( + self.tr("Show some information about 'Black'.") + ) + self.blackAboutAct.setWhatsThis(self.tr( + "<b>Black</b>" + "<p>This shows some information about the installed 'Black' tool.</p>" + )) + self.blackAboutAct.triggered.connect(self.__aboutBlack) + self.actions.append(self.blackAboutAct) + font = self.blackAboutAct.font() + font.setBold(True) + self.blackAboutAct.setFont(font) + + self.blackFormatAct = EricAction( + self.tr("Format Code"), + self.tr("&Format Code"), + 0, 0, + self.blackFormattingGrp, "project_black_format_code" + ) + self.blackFormatAct.setStatusTip( + self.tr("Format the project sources with 'Black'.") + ) + self.blackFormatAct.setWhatsThis(self.tr( + "<b>Format Code</b>" + "<p>This shows a dialog to enter parameters for the formatting run and" + " reformats the project sources using 'Black'.</p>" + )) + self.blackFormatAct.triggered.connect( + lambda: self.__performFormatWithBlack(BlackFormattingAction.Format) + ) + self.actions.append(self.blackFormatAct) + + self.blackCheckFormattingAct = EricAction( + self.tr("Check Code Formatting"), + self.tr("&Check Code Formatting"), + 0, 0, + self.blackFormattingGrp, "project_black_check_code" + ) + self.blackCheckFormattingAct.setStatusTip( + self.tr( + "Check, if the project sources need to be reformatted with 'Black'." + ) + ) + self.blackCheckFormattingAct.setWhatsThis(self.tr( + "<b>Check Code Formatting</b>" + "<p>This shows a dialog to enter parameters for the format check run and" + " performs a check, if the project sources need to be reformatted using" + " 'Black'.</p>" + )) + self.blackCheckFormattingAct.triggered.connect( + lambda: self.__performFormatWithBlack(BlackFormattingAction.Check) + ) + self.actions.append(self.blackCheckFormattingAct) + + self.blackDiffFormattingAct = EricAction( + self.tr("Code Formatting Diff"), + self.tr("Code Formatting &Diff"), + 0, 0, + self.blackFormattingGrp, "project_black_diff_code" + ) + self.blackDiffFormattingAct.setStatusTip( + self.tr( + "Generate a unified diff of potential project source reformatting" + " with 'Black'." + ) + ) + self.blackDiffFormattingAct.setWhatsThis(self.tr( + "<b>Diff Code Formatting</b>" + "<p>This shows a dialog to enter parameters for the format diff run and" + " generates a unified diff of potential project source reformatting using" + " 'Black'.</p>" + )) + self.blackDiffFormattingAct.triggered.connect( + lambda: self.__performFormatWithBlack(BlackFormattingAction.Diff) + ) + self.actions.append(self.blackDiffFormattingAct) + self.closeAct.setEnabled(False) self.saveAct.setEnabled(False) self.saveasAct.setEnabled(False) @@ -4446,6 +4582,8 @@ self.vcsMenu.setEnabled(self.vcsSoftwareAvailable()) self.checksMenu = QMenu(self.tr('Chec&k'), toolsMenu) self.checksMenu.setTearOffEnabled(True) + self.formattingMenu = QMenu(self.tr("Code &Formatting"), toolsMenu) + self.formattingMenu.setTearOffEnabled(True) self.menuShow = QMenu(self.tr('Sho&w'), toolsMenu) self.graphicsMenu = QMenu(self.tr('&Diagrams'), toolsMenu) self.packagersMenu = QMenu(self.tr('Pac&kagers'), toolsMenu) @@ -4467,6 +4605,7 @@ "Packagers": self.packagersMenu, "Make": self.makeMenu, "OtherTools": self.othersMenu, + "Formatting": self.formattingMenu, } # connect the aboutToShow signals @@ -4482,6 +4621,7 @@ self.debuggerMenu.aboutToShow.connect(self.__showContextMenuDebugger) self.makeMenu.aboutToShow.connect(self.__showContextMenuMake) self.othersMenu.aboutToShow.connect(self.__showContextMenuOthers) + self.formattingMenu.aboutToShow.connect(self.__showContextMenuFormat) menu.aboutToShow.connect(self.__showMenu) # build the show menu @@ -4516,7 +4656,13 @@ # build the 'Other Tools' menu self.othersMenu.setTearOffEnabled(True) - self.othersMenu.addAction(self.createSBOMAct) + self.othersMenu.addActions(self.othersGrp.actions()) + self.othersMenu.addSeparator() + + # build the 'Code Formatting' menu + self.formattingMenu.setTearOffEnabled(True) + self.formattingMenu.addActions(self.blackFormattingGrp.actions()) + self.formattingMenu.addSeparator() # build the project main menu menu.setTearOffEnabled(True) @@ -4545,6 +4691,8 @@ toolsMenu.addSeparator() self.menuCheckAct = toolsMenu.addMenu(self.checksMenu) toolsMenu.addSeparator() + self.menuFormattingAct = toolsMenu.addMenu(self.formattingMenu) + toolsMenu.addSeparator() self.menuMakeAct = toolsMenu.addMenu(self.makeMenu) toolsMenu.addSeparator() self.menuDiagramAct = toolsMenu.addMenu(self.graphicsMenu) @@ -4566,6 +4714,7 @@ self.menuPackagersAct.setEnabled(False) self.menuMakeAct.setEnabled(False) self.menuOtherToolsAct.setEnabled(False) + self.menuFormattingAct.setEnabled(False) self.__menu = menu self.__toolsMenu = toolsMenu @@ -5956,7 +6105,7 @@ ######################################################################### ## Below are methods implementing the 'SBOM' support ######################################################################### - + def __showContextMenuOthers(self): """ Private slot called before the 'Other Tools' menu is shown. @@ -5971,6 +6120,63 @@ import CycloneDXInterface CycloneDXInterface.createCycloneDXFile("<project>") + + ######################################################################### + ## Below are methods implementing the 'Code Formatting' support + ######################################################################### + + def __showContextMenuFormat(self): + """ + Private slot called before the 'Code Formatting' menu is shown. + """ + self.showMenu.emit("Formatting", self.othersMenu) + + @pyqtSlot() + def __aboutBlack(self): + """ + Private slot to show some information about the installed 'Black' tool. + """ + import black + + EricMessageBox.information( + None, + self.tr("About Black"), + self.tr("""<p><b>Black Version {0}</b></p>""" + """<p><i>Black</i> is the uncompromising Python code""" + """ formatter.</p>""").format(black.__version__) + ) + + def __performFormatWithBlack(self, action): + """ + Private method to format the project sources using the 'Black' tool. + + Following actions are supported. + <ul> + <li>BlackFormattingAction.Format - the code reformatting is performed</li> + <li>BlackFormattingAction.Check - a check is performed, if code formatting + is necessary</li> + <li>BlackFormattingAction.Diff - a unified diff of potential code formatting + changes is generated</li> + </ul> + + @param action formatting operation to be performed + @type BlackFormattingAction + """ + from CodeFormatting.BlackConfigurationDialog import BlackConfigurationDialog + from CodeFormatting.BlackFormattingDialog import BlackFormattingDialog + + if ericApp().getObject("ViewManager").checkAllDirty(): + dlg = BlackConfigurationDialog(withProject=True) + if dlg.exec() == QDialog.DialogCode.Accepted: + config = dlg.getConfiguration() + + formattingDialog = BlackFormattingDialog( + config, + self.getProjectFiles("SOURCES", normalized=True), + project=self, + action=action + ) + formattingDialog.exec() # # eflag: noqa = M601