7226:babe80d84a3e | 7286:7eb04391adf7 |
---|---|
4 # | 4 # |
5 | 5 |
6 """ | 6 """ |
7 Module implementing the editor component of the eric6 IDE. | 7 Module implementing the editor component of the eric6 IDE. |
8 """ | 8 """ |
9 from __future__ import unicode_literals | 9 |
10 try: | |
11 str = unicode | |
12 chr = unichr | |
13 except NameError: | |
14 pass | |
15 | 10 |
16 import os | 11 import os |
17 import re | 12 import re |
18 import difflib | 13 import difflib |
19 | 14 |
20 from PyQt5.QtCore import QDir, QTimer, QModelIndex, QFileInfo, pyqtSignal, \ | 15 from PyQt5.QtCore import ( |
21 pyqtSlot, QCryptographicHash, QEvent, QDateTime, QRegExp, Qt, QPoint | 16 QDir, QTimer, QModelIndex, QFileInfo, pyqtSignal, pyqtSlot, |
17 QCryptographicHash, QEvent, QDateTime, QRegExp, Qt, QPoint | |
18 ) | |
22 from PyQt5.QtGui import QCursor, QPalette, QFont, QPixmap, QPainter | 19 from PyQt5.QtGui import QCursor, QPalette, QFont, QPixmap, QPainter |
23 from PyQt5.QtWidgets import QLineEdit, QActionGroup, QDialog, QInputDialog, \ | 20 from PyQt5.QtWidgets import ( |
24 QApplication, QMenu | 21 QLineEdit, QActionGroup, QDialog, QInputDialog, QApplication, QMenu |
22 ) | |
25 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog | 23 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog |
26 from PyQt5.Qsci import QsciScintilla, QsciMacro, QsciStyledText | 24 from PyQt5.Qsci import QsciScintilla, QsciMacro, QsciStyledText |
27 | 25 |
28 from E5Gui.E5Application import e5App | 26 from E5Gui.E5Application import e5App |
29 from E5Gui import E5FileDialog, E5MessageBox | 27 from E5Gui import E5FileDialog, E5MessageBox |
33 from .EditorMarkerMap import EditorMarkerMap | 31 from .EditorMarkerMap import EditorMarkerMap |
34 | 32 |
35 import Preferences | 33 import Preferences |
36 import Utilities | 34 import Utilities |
37 from Utilities import MouseUtilities | 35 from Utilities import MouseUtilities |
38 from Globals import qVersionTuple | |
39 | 36 |
40 import UI.PixmapCache | 37 import UI.PixmapCache |
41 | 38 |
42 from ThirdParty.EditorConfig import editorconfig | 39 from ThirdParty.EditorConfig import editorconfig |
43 | 40 |
313 self.currentline = self.markerDefine( | 310 self.currentline = self.markerDefine( |
314 UI.PixmapCache.getPixmap("currentLineMarker.png")) | 311 UI.PixmapCache.getPixmap("currentLineMarker.png")) |
315 self.errorline = self.markerDefine( | 312 self.errorline = self.markerDefine( |
316 UI.PixmapCache.getPixmap("errorLineMarker.png")) | 313 UI.PixmapCache.getPixmap("errorLineMarker.png")) |
317 | 314 |
318 self.breakpointMask = (1 << self.breakpoint) | \ | 315 self.breakpointMask = ( |
319 (1 << self.cbreakpoint) | \ | 316 (1 << self.breakpoint) | |
320 (1 << self.tbreakpoint) | \ | 317 (1 << self.cbreakpoint) | |
321 (1 << self.tcbreakpoint) | \ | 318 (1 << self.tbreakpoint) | |
322 (1 << self.dbreakpoint) | 319 (1 << self.tcbreakpoint) | |
323 | 320 (1 << self.dbreakpoint) |
324 self.changeMarkersMask = (1 << self.__changeMarkerSaved) | \ | 321 ) |
325 (1 << self.__changeMarkerUnsaved) | 322 |
323 self.changeMarkersMask = ( | |
324 (1 << self.__changeMarkerSaved) | | |
325 (1 << self.__changeMarkerUnsaved) | |
326 ) | |
326 | 327 |
327 self.__markerMap = EditorMarkerMap(self) | 328 self.__markerMap = EditorMarkerMap(self) |
328 | 329 |
329 # configure the margins | 330 # configure the margins |
330 self.__setMarginsDisplay() | 331 self.__setMarginsDisplay() |
350 self.syntaxCheckService = None | 351 self.syntaxCheckService = None |
351 | 352 |
352 self.isResourcesFile = False | 353 self.isResourcesFile = False |
353 if editor is None: | 354 if editor is None: |
354 if self.fileName: | 355 if self.fileName: |
355 if (QFileInfo(self.fileName).size() // 1024) > \ | 356 if ( |
356 Preferences.getEditor("WarnFilesize"): | 357 (QFileInfo(self.fileName).size() // 1024) > |
358 Preferences.getEditor("WarnFilesize") | |
359 ): | |
357 res = E5MessageBox.yesNo( | 360 res = E5MessageBox.yesNo( |
358 self, | 361 self, |
359 self.tr("Open File"), | 362 self.tr("Open File"), |
360 self.tr("""<p>The size of the file <b>{0}</b>""" | 363 self.tr("""<p>The size of the file <b>{0}</b>""" |
361 """ is <b>{1} KB</b>.""" | 364 """ is <b>{1} KB</b>.""" |
369 self.__bindLexer(self.fileName) | 372 self.__bindLexer(self.fileName) |
370 self.__bindCompleter(self.fileName) | 373 self.__bindCompleter(self.fileName) |
371 self.checkSyntax() | 374 self.checkSyntax() |
372 self.isResourcesFile = self.fileName.endswith(".qrc") | 375 self.isResourcesFile = self.fileName.endswith(".qrc") |
373 | 376 |
377 self.__convertTabs() | |
378 | |
374 self.recolor() | 379 self.recolor() |
375 else: | 380 else: |
376 # clone the given editor | 381 # clone the given editor |
377 self.setDocument(editor.document()) | 382 self.setDocument(editor.document()) |
378 self.breaks = editor.breaks | 383 self.breaks = editor.breaks |
508 self.textChanged.connect(self.__textChanged) | 513 self.textChanged.connect(self.__textChanged) |
509 | 514 |
510 # initialize the online change trace timer | 515 # initialize the online change trace timer |
511 self.__initOnlineChangeTrace() | 516 self.__initOnlineChangeTrace() |
512 | 517 |
513 if self.fileName and \ | 518 if ( |
514 self.project.isOpen() and \ | 519 self.fileName and |
515 self.project.isProjectSource(self.fileName): | 520 self.project.isOpen() and |
521 self.project.isProjectSource(self.fileName) | |
522 ): | |
516 self.project.projectPropertiesChanged.connect( | 523 self.project.projectPropertiesChanged.connect( |
517 self.__projectPropertiesChanged) | 524 self.__projectPropertiesChanged) |
518 | 525 |
519 self.grabGesture(Qt.PinchGesture) | 526 self.grabGesture(Qt.PinchGesture) |
520 | 527 |
1015 self.supportedLanguages = {} | 1022 self.supportedLanguages = {} |
1016 supportedLanguages = Lexers.getSupportedLanguages() | 1023 supportedLanguages = Lexers.getSupportedLanguages() |
1017 languages = sorted(list(supportedLanguages.keys())) | 1024 languages = sorted(list(supportedLanguages.keys())) |
1018 for language in languages: | 1025 for language in languages: |
1019 if language != "Guessed": | 1026 if language != "Guessed": |
1020 self.supportedLanguages[language] = \ | 1027 self.supportedLanguages[language] = ( |
1021 supportedLanguages[language][:2] | 1028 supportedLanguages[language][:2] |
1029 ) | |
1022 act = menu.addAction( | 1030 act = menu.addAction( |
1023 UI.PixmapCache.getIcon(supportedLanguages[language][2]), | 1031 UI.PixmapCache.getIcon(supportedLanguages[language][2]), |
1024 self.supportedLanguages[language][0]) | 1032 self.supportedLanguages[language][0]) |
1025 act.setCheckable(True) | 1033 act.setCheckable(True) |
1026 act.setData(language) | 1034 act.setData(language) |
1172 self.marginMenuActs["EnableBreakpoint"] = self.bpMarginMenu.addAction( | 1180 self.marginMenuActs["EnableBreakpoint"] = self.bpMarginMenu.addAction( |
1173 self.tr('Enable breakpoint'), | 1181 self.tr('Enable breakpoint'), |
1174 self.__menuToggleBreakpointEnabled) | 1182 self.__menuToggleBreakpointEnabled) |
1175 self.marginMenuActs["NextBreakpoint"] = self.bpMarginMenu.addAction( | 1183 self.marginMenuActs["NextBreakpoint"] = self.bpMarginMenu.addAction( |
1176 self.tr('Next breakpoint'), self.menuNextBreakpoint) | 1184 self.tr('Next breakpoint'), self.menuNextBreakpoint) |
1177 self.marginMenuActs["PreviousBreakpoint"] = \ | 1185 self.marginMenuActs["PreviousBreakpoint"] = ( |
1178 self.bpMarginMenu.addAction( | 1186 self.bpMarginMenu.addAction( |
1179 self.tr('Previous breakpoint'), | 1187 self.tr('Previous breakpoint'), |
1180 self.menuPreviousBreakpoint) | 1188 self.menuPreviousBreakpoint) |
1189 ) | |
1181 self.marginMenuActs["ClearBreakpoint"] = self.bpMarginMenu.addAction( | 1190 self.marginMenuActs["ClearBreakpoint"] = self.bpMarginMenu.addAction( |
1182 self.tr('Clear all breakpoints'), self.__menuClearBreakpoints) | 1191 self.tr('Clear all breakpoints'), self.__menuClearBreakpoints) |
1183 | 1192 |
1184 self.bpMarginMenu.aboutToShow.connect( | 1193 self.bpMarginMenu.aboutToShow.connect( |
1185 lambda: self.__showContextMenuMargin(self.bpMarginMenu)) | 1194 lambda: self.__showContextMenuMargin(self.bpMarginMenu)) |
1186 | 1195 |
1187 # fold margin | 1196 # fold margin |
1188 self.foldMarginMenu = QMenu() | 1197 self.foldMarginMenu = QMenu() |
1189 | 1198 |
1190 self.marginMenuActs["ToggleAllFolds"] = \ | 1199 self.marginMenuActs["ToggleAllFolds"] = ( |
1191 self.foldMarginMenu.addAction( | 1200 self.foldMarginMenu.addAction( |
1192 self.tr("Toggle all folds"), | 1201 self.tr("Toggle all folds"), |
1193 self.foldAll) | 1202 self.foldAll) |
1194 self.marginMenuActs["ToggleAllFoldsAndChildren"] = \ | 1203 ) |
1204 self.marginMenuActs["ToggleAllFoldsAndChildren"] = ( | |
1195 self.foldMarginMenu.addAction( | 1205 self.foldMarginMenu.addAction( |
1196 self.tr("Toggle all folds (including children)"), | 1206 self.tr("Toggle all folds (including children)"), |
1197 lambda: self.foldAll(True)) | 1207 lambda: self.foldAll(True)) |
1198 self.marginMenuActs["ToggleCurrentFold"] = \ | 1208 ) |
1209 self.marginMenuActs["ToggleCurrentFold"] = ( | |
1199 self.foldMarginMenu.addAction( | 1210 self.foldMarginMenu.addAction( |
1200 self.tr("Toggle current fold"), | 1211 self.tr("Toggle current fold"), |
1201 self.toggleCurrentFold) | 1212 self.toggleCurrentFold) |
1213 ) | |
1202 self.foldMarginMenu.addSeparator() | 1214 self.foldMarginMenu.addSeparator() |
1203 self.marginMenuActs["ExpandChildren"] = \ | 1215 self.marginMenuActs["ExpandChildren"] = ( |
1204 self.foldMarginMenu.addAction( | 1216 self.foldMarginMenu.addAction( |
1205 self.tr("Expand (including children)"), | 1217 self.tr("Expand (including children)"), |
1206 self.__contextMenuExpandFoldWithChildren) | 1218 self.__contextMenuExpandFoldWithChildren) |
1207 self.marginMenuActs["CollapseChildren"] = \ | 1219 ) |
1220 self.marginMenuActs["CollapseChildren"] = ( | |
1208 self.foldMarginMenu.addAction( | 1221 self.foldMarginMenu.addAction( |
1209 self.tr("Collapse (including children)"), | 1222 self.tr("Collapse (including children)"), |
1210 self.__contextMenuCollapseFoldWithChildren) | 1223 self.__contextMenuCollapseFoldWithChildren) |
1224 ) | |
1211 self.foldMarginMenu.addSeparator() | 1225 self.foldMarginMenu.addSeparator() |
1212 self.marginMenuActs["ClearAllFolds"] = \ | 1226 self.marginMenuActs["ClearAllFolds"] = ( |
1213 self.foldMarginMenu.addAction( | 1227 self.foldMarginMenu.addAction( |
1214 self.tr("Clear all folds"), | 1228 self.tr("Clear all folds"), |
1215 self.clearFolds) | 1229 self.clearFolds) |
1230 ) | |
1216 | 1231 |
1217 self.foldMarginMenu.aboutToShow.connect( | 1232 self.foldMarginMenu.aboutToShow.connect( |
1218 lambda: self.__showContextMenuMargin(self.foldMarginMenu)) | 1233 lambda: self.__showContextMenuMargin(self.foldMarginMenu)) |
1219 | 1234 |
1220 # indicator margin | 1235 # indicator margin |
1221 self.indicMarginMenu = QMenu() | 1236 self.indicMarginMenu = QMenu() |
1222 | 1237 |
1223 self.marginMenuActs["GotoSyntaxError"] = \ | 1238 self.marginMenuActs["GotoSyntaxError"] = ( |
1224 self.indicMarginMenu.addAction( | 1239 self.indicMarginMenu.addAction( |
1225 self.tr('Goto syntax error'), self.gotoSyntaxError) | 1240 self.tr('Goto syntax error'), self.gotoSyntaxError) |
1226 self.marginMenuActs["ShowSyntaxError"] = \ | 1241 ) |
1242 self.marginMenuActs["ShowSyntaxError"] = ( | |
1227 self.indicMarginMenu.addAction( | 1243 self.indicMarginMenu.addAction( |
1228 self.tr('Show syntax error message'), | 1244 self.tr('Show syntax error message'), |
1229 self.__showSyntaxError) | 1245 self.__showSyntaxError) |
1230 self.marginMenuActs["ClearSyntaxError"] = \ | 1246 ) |
1247 self.marginMenuActs["ClearSyntaxError"] = ( | |
1231 self.indicMarginMenu.addAction( | 1248 self.indicMarginMenu.addAction( |
1232 self.tr('Clear syntax error'), self.clearSyntaxError) | 1249 self.tr('Clear syntax error'), self.clearSyntaxError) |
1250 ) | |
1233 self.indicMarginMenu.addSeparator() | 1251 self.indicMarginMenu.addSeparator() |
1234 self.marginMenuActs["NextWarningMarker"] = \ | 1252 self.marginMenuActs["NextWarningMarker"] = ( |
1235 self.indicMarginMenu.addAction( | 1253 self.indicMarginMenu.addAction( |
1236 self.tr("Next warning"), self.nextWarning) | 1254 self.tr("Next warning"), self.nextWarning) |
1237 self.marginMenuActs["PreviousWarningMarker"] = \ | 1255 ) |
1256 self.marginMenuActs["PreviousWarningMarker"] = ( | |
1238 self.indicMarginMenu.addAction( | 1257 self.indicMarginMenu.addAction( |
1239 self.tr("Previous warning"), self.previousWarning) | 1258 self.tr("Previous warning"), self.previousWarning) |
1240 self.marginMenuActs["ShowWarning"] = \ | 1259 ) |
1260 self.marginMenuActs["ShowWarning"] = ( | |
1241 self.indicMarginMenu.addAction( | 1261 self.indicMarginMenu.addAction( |
1242 self.tr('Show warning message'), self.__showWarning) | 1262 self.tr('Show warning message'), self.__showWarning) |
1243 self.marginMenuActs["ClearWarnings"] = \ | 1263 ) |
1264 self.marginMenuActs["ClearWarnings"] = ( | |
1244 self.indicMarginMenu.addAction( | 1265 self.indicMarginMenu.addAction( |
1245 self.tr('Clear warnings'), self.clearWarnings) | 1266 self.tr('Clear warnings'), self.clearWarnings) |
1267 ) | |
1246 self.indicMarginMenu.addSeparator() | 1268 self.indicMarginMenu.addSeparator() |
1247 self.marginMenuActs["NextCoverageMarker"] = \ | 1269 self.marginMenuActs["NextCoverageMarker"] = ( |
1248 self.indicMarginMenu.addAction( | 1270 self.indicMarginMenu.addAction( |
1249 self.tr('Next uncovered line'), self.nextUncovered) | 1271 self.tr('Next uncovered line'), self.nextUncovered) |
1250 self.marginMenuActs["PreviousCoverageMarker"] = \ | 1272 ) |
1273 self.marginMenuActs["PreviousCoverageMarker"] = ( | |
1251 self.indicMarginMenu.addAction( | 1274 self.indicMarginMenu.addAction( |
1252 self.tr('Previous uncovered line'), self.previousUncovered) | 1275 self.tr('Previous uncovered line'), self.previousUncovered) |
1276 ) | |
1253 self.indicMarginMenu.addSeparator() | 1277 self.indicMarginMenu.addSeparator() |
1254 self.marginMenuActs["NextTaskMarker"] = \ | 1278 self.marginMenuActs["NextTaskMarker"] = ( |
1255 self.indicMarginMenu.addAction( | 1279 self.indicMarginMenu.addAction( |
1256 self.tr('Next task'), self.nextTask) | 1280 self.tr('Next task'), self.nextTask) |
1257 self.marginMenuActs["PreviousTaskMarker"] = \ | 1281 ) |
1282 self.marginMenuActs["PreviousTaskMarker"] = ( | |
1258 self.indicMarginMenu.addAction( | 1283 self.indicMarginMenu.addAction( |
1259 self.tr('Previous task'), self.previousTask) | 1284 self.tr('Previous task'), self.previousTask) |
1285 ) | |
1260 self.indicMarginMenu.addSeparator() | 1286 self.indicMarginMenu.addSeparator() |
1261 self.marginMenuActs["NextChangeMarker"] = \ | 1287 self.marginMenuActs["NextChangeMarker"] = ( |
1262 self.indicMarginMenu.addAction( | 1288 self.indicMarginMenu.addAction( |
1263 self.tr('Next change'), self.nextChange) | 1289 self.tr('Next change'), self.nextChange) |
1264 self.marginMenuActs["PreviousChangeMarker"] = \ | 1290 ) |
1291 self.marginMenuActs["PreviousChangeMarker"] = ( | |
1265 self.indicMarginMenu.addAction( | 1292 self.indicMarginMenu.addAction( |
1266 self.tr('Previous change'), self.previousChange) | 1293 self.tr('Previous change'), self.previousChange) |
1267 self.marginMenuActs["ClearChangeMarkers"] = \ | 1294 ) |
1295 self.marginMenuActs["ClearChangeMarkers"] = ( | |
1268 self.indicMarginMenu.addAction( | 1296 self.indicMarginMenu.addAction( |
1269 self.tr('Clear changes'), self.__reinitOnlineChangeTrace) | 1297 self.tr('Clear changes'), self.__reinitOnlineChangeTrace) |
1298 ) | |
1270 | 1299 |
1271 self.indicMarginMenu.aboutToShow.connect( | 1300 self.indicMarginMenu.aboutToShow.connect( |
1272 lambda: self.__showContextMenuMargin(self.indicMarginMenu)) | 1301 lambda: self.__showContextMenuMargin(self.indicMarginMenu)) |
1273 | 1302 |
1274 def __exportMenuTriggered(self, act): | 1303 def __exportMenuTriggered(self, act): |
1390 """ | 1419 """ |
1391 Private method used to reset the language selection. | 1420 Private method used to reset the language selection. |
1392 | 1421 |
1393 @keyparam propagate flag indicating to propagate the change (boolean) | 1422 @keyparam propagate flag indicating to propagate the change (boolean) |
1394 """ | 1423 """ |
1395 if self.lexer_ is not None and \ | 1424 if ( |
1396 (self.lexer_.lexer() == "container" or self.lexer_.lexer() is None): | 1425 self.lexer_ is not None and |
1426 (self.lexer_.lexer() == "container" or | |
1427 self.lexer_.lexer() is None) | |
1428 ): | |
1397 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) | 1429 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) |
1398 | 1430 |
1399 self.apiLanguage = "" | 1431 self.apiLanguage = "" |
1400 self.lexer_ = None | 1432 self.lexer_ = None |
1401 self.__lexerReset = True | 1433 self.__lexerReset = True |
1491 def __checkEncoding(self): | 1523 def __checkEncoding(self): |
1492 """ | 1524 """ |
1493 Private method to check the selected encoding of the encodings submenu. | 1525 Private method to check the selected encoding of the encodings submenu. |
1494 """ | 1526 """ |
1495 try: | 1527 try: |
1496 self.supportedEncodings[self.__normalizedEncoding()]\ | 1528 (self.supportedEncodings[self.__normalizedEncoding()] |
1497 .setChecked(True) | 1529 .setChecked(True)) |
1498 except (AttributeError, KeyError): | 1530 except (AttributeError, KeyError): |
1499 pass | 1531 pass |
1500 | 1532 |
1501 def __encodingChanged(self, encoding, propagate=True): | 1533 def __encodingChanged(self, encoding, propagate=True): |
1502 """ | 1534 """ |
1520 @param encoding encoding to be normalized (string) | 1552 @param encoding encoding to be normalized (string) |
1521 @return normalized encoding (string) | 1553 @return normalized encoding (string) |
1522 """ | 1554 """ |
1523 if not encoding: | 1555 if not encoding: |
1524 encoding = self.encoding | 1556 encoding = self.encoding |
1525 return encoding.replace("-default", "")\ | 1557 return ( |
1526 .replace("-guessed", "")\ | 1558 encoding |
1527 .replace("-selected", "") | 1559 .replace("-default", "") |
1560 .replace("-guessed", "") | |
1561 .replace("-selected", "") | |
1562 ) | |
1528 | 1563 |
1529 def __showContextMenuEol(self): | 1564 def __showContextMenuEol(self): |
1530 """ | 1565 """ |
1531 Private slot handling the aboutToShow signal of the eol context menu. | 1566 Private slot handling the aboutToShow signal of the eol context menu. |
1532 """ | 1567 """ |
1569 | 1604 |
1570 @param filename filename used to determine the associated lexer | 1605 @param filename filename used to determine the associated lexer |
1571 language (string) | 1606 language (string) |
1572 @keyparam pyname name of the pygments lexer to use (string) | 1607 @keyparam pyname name of the pygments lexer to use (string) |
1573 """ | 1608 """ |
1574 if self.lexer_ is not None and \ | 1609 if ( |
1575 (self.lexer_.lexer() == "container" or self.lexer_.lexer() is None): | 1610 self.lexer_ is not None and |
1611 (self.lexer_.lexer() == "container" or | |
1612 self.lexer_.lexer() is None) | |
1613 ): | |
1576 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) | 1614 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) |
1577 | 1615 |
1578 language = "" | 1616 language = "" |
1579 if not self.filetype: | 1617 if not self.filetype: |
1580 if filename: | 1618 if filename: |
1581 basename = os.path.basename(filename) | 1619 basename = os.path.basename(filename) |
1582 if self.project.isOpen() and \ | 1620 if ( |
1583 self.project.isProjectFile(filename): | 1621 self.project.isOpen() and |
1622 self.project.isProjectFile(filename) | |
1623 ): | |
1584 language = self.project.getEditorLexerAssoc(basename) | 1624 language = self.project.getEditorLexerAssoc(basename) |
1585 if not language: | 1625 if not language: |
1586 language = Preferences.getEditorLexerAssoc(basename) | 1626 language = Preferences.getEditorLexerAssoc(basename) |
1587 if not language: | 1627 if not language: |
1588 bindName = self.__bindName(self.text(0)) | 1628 bindName = self.__bindName(self.text(0)) |
1686 lexer names (boolean) | 1726 lexer names (boolean) |
1687 @keyparam forPygments flag indicating to normalize some lexer | 1727 @keyparam forPygments flag indicating to normalize some lexer |
1688 names for Pygments (boolean) | 1728 names for Pygments (boolean) |
1689 @return language of the editor (string) | 1729 @return language of the editor (string) |
1690 """ | 1730 """ |
1691 if self.apiLanguage == "Guessed" or \ | 1731 if ( |
1692 self.apiLanguage.startswith("Pygments|"): | 1732 self.apiLanguage == "Guessed" or |
1733 self.apiLanguage.startswith("Pygments|") | |
1734 ): | |
1693 lang = self.lexer_.name() | 1735 lang = self.lexer_.name() |
1694 if normalized: | 1736 if normalized: |
1695 # adjust some Pygments lexer names | 1737 # adjust some Pygments lexer names |
1696 if lang == "Python": | 1738 if lang == "Python": |
1697 lang = "Python2" | 1739 lang = "Python2" |
1935 if self.filetype == "Ruby": | 1977 if self.filetype == "Ruby": |
1936 return True | 1978 return True |
1937 | 1979 |
1938 if self.filetype == "": | 1980 if self.filetype == "": |
1939 line0 = self.text(0) | 1981 line0 = self.text(0) |
1940 if line0.startswith("#!") and \ | 1982 if ( |
1941 "ruby" in line0: | 1983 line0.startswith("#!") and |
1984 "ruby" in line0 | |
1985 ): | |
1942 self.filetype = "Ruby" | 1986 self.filetype = "Ruby" |
1943 return True | 1987 return True |
1944 | 1988 |
1945 if bool(self.fileName) and \ | 1989 if ( |
1946 os.path.splitext(self.fileName)[1] in \ | 1990 bool(self.fileName) and |
1947 self.dbs.getExtensions('Ruby'): | 1991 os.path.splitext(self.fileName)[1] in |
1992 self.dbs.getExtensions('Ruby') | |
1993 ): | |
1948 self.filetype = "Ruby" | 1994 self.filetype = "Ruby" |
1949 return True | 1995 return True |
1950 | 1996 |
1951 return False | 1997 return False |
1952 | 1998 |
1958 """ | 2004 """ |
1959 if self.filetype == "JavaScript": | 2005 if self.filetype == "JavaScript": |
1960 return True | 2006 return True |
1961 | 2007 |
1962 if self.filetype == "": | 2008 if self.filetype == "": |
1963 if self.fileName and \ | 2009 if ( |
1964 os.path.splitext(self.fileName)[1] == ".js": | 2010 self.fileName and |
2011 os.path.splitext(self.fileName)[1] == ".js" | |
2012 ): | |
1965 self.filetype = "JavaScript" | 2013 self.filetype = "JavaScript" |
1966 return True | 2014 return True |
1967 | 2015 |
1968 return False | 2016 return False |
1969 | 2017 |
2036 @param foldPrev previous fold level (integer) | 2084 @param foldPrev previous fold level (integer) |
2037 @param token ??? | 2085 @param token ??? |
2038 @param annotationLinesAdded number of added/deleted annotation lines | 2086 @param annotationLinesAdded number of added/deleted annotation lines |
2039 (integer) | 2087 (integer) |
2040 """ | 2088 """ |
2041 if mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) and \ | 2089 if ( |
2042 linesAdded != 0: | 2090 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) and |
2091 linesAdded != 0 | |
2092 ): | |
2043 if self.breaks: | 2093 if self.breaks: |
2044 bps = [] # list of breakpoints | 2094 bps = [] # list of breakpoints |
2045 for handle, (ln, cond, temp, enabled, ignorecount) in \ | 2095 for handle, (ln, cond, temp, enabled, ignorecount) in ( |
2046 self.breaks.items(): | 2096 self.breaks.items() |
2097 ): | |
2047 line = self.markerLine(handle) + 1 | 2098 line = self.markerLine(handle) + 1 |
2048 if ln != line: | 2099 if ln != line: |
2049 bps.append((ln, line)) | 2100 bps.append((ln, line)) |
2050 self.breaks[handle] = (line, cond, temp, enabled, | 2101 self.breaks[handle] = (line, cond, temp, enabled, |
2051 ignorecount) | 2102 ignorecount) |
2113 @param start start row (integer) | 2164 @param start start row (integer) |
2114 @param end end row (integer) | 2165 @param end end row (integer) |
2115 """ | 2166 """ |
2116 for row in range(start, end + 1): | 2167 for row in range(start, end + 1): |
2117 index = self.breakpointModel.index(row, 0, parentIndex) | 2168 index = self.breakpointModel.index(row, 0, parentIndex) |
2118 fn, line, cond, temp, enabled, ignorecount = \ | 2169 fn, line, cond, temp, enabled, ignorecount = ( |
2119 self.breakpointModel.getBreakPointByIndex(index)[:6] | 2170 self.breakpointModel.getBreakPointByIndex(index)[:6] |
2171 ) | |
2120 if fn == self.fileName: | 2172 if fn == self.fileName: |
2121 self.newBreakpointWithProperties( | 2173 self.newBreakpointWithProperties( |
2122 line, (cond, temp, enabled, ignorecount)) | 2174 line, (cond, temp, enabled, ignorecount)) |
2123 | 2175 |
2124 def clearBreakpoint(self, line): | 2176 def clearBreakpoint(self, line): |
2175 for handle in self.breaks: | 2227 for handle in self.breaks: |
2176 if self.markerLine(handle) == line - 1: | 2228 if self.markerLine(handle) == line - 1: |
2177 # delete breakpoint or toggle it to the next state | 2229 # delete breakpoint or toggle it to the next state |
2178 index = self.breakpointModel.getBreakPointIndex( | 2230 index = self.breakpointModel.getBreakPointIndex( |
2179 self.fileName, line) | 2231 self.fileName, line) |
2180 if Preferences.getDebugger("ThreeStateBreakPoints") and \ | 2232 if ( |
2181 not self.breakpointModel.isBreakPointTemporaryByIndex( | 2233 Preferences.getDebugger("ThreeStateBreakPoints") and |
2182 index): | 2234 not self.breakpointModel.isBreakPointTemporaryByIndex( |
2235 index) | |
2236 ): | |
2183 self.breakpointModel.deleteBreakPointByIndex(index) | 2237 self.breakpointModel.deleteBreakPointByIndex(index) |
2184 self.__addBreakPoint(line, True) | 2238 self.__addBreakPoint(line, True) |
2185 else: | 2239 else: |
2186 self.breakpointModel.deleteBreakPointByIndex(index) | 2240 self.breakpointModel.deleteBreakPointByIndex(index) |
2187 self.breakpointToggled.emit(self) | 2241 self.breakpointToggled.emit(self) |
2951 QApplication.restoreOverrideCursor() | 3005 QApplication.restoreOverrideCursor() |
2952 raise | 3006 raise |
2953 | 3007 |
2954 modified = False | 3008 modified = False |
2955 | 3009 |
2956 if (not self.__getEditorConfig("TabForIndentation")) and \ | 3010 self.setText(txt) |
2957 Preferences.getEditor("ConvertTabsOnLoad") and \ | 3011 |
2958 not (self.lexer_ and | 3012 # get eric specific flags |
2959 self.lexer_.alwaysKeepTabs()): | 3013 self.__processFlags() |
3014 | |
3015 # perform automatic EOL conversion | |
3016 if ( | |
3017 self.__getEditorConfig("EOLMode", nodefault=True) or | |
3018 Preferences.getEditor("AutomaticEOLConversion") | |
3019 ): | |
3020 self.convertEols(self.eolMode()) | |
3021 else: | |
3022 fileEol = self.detectEolString(txt) | |
3023 self.setEolModeByEolString(fileEol) | |
3024 | |
3025 self.extractTasks() | |
3026 | |
3027 QApplication.restoreOverrideCursor() | |
3028 | |
3029 self.setModified(modified) | |
3030 self.lastModified = QFileInfo(self.fileName).lastModified() | |
3031 | |
3032 def __convertTabs(self): | |
3033 """ | |
3034 Private slot to convert tabulators to spaces. | |
3035 """ | |
3036 if ( | |
3037 (not self.__getEditorConfig("TabForIndentation")) and | |
3038 Preferences.getEditor("ConvertTabsOnLoad") and | |
3039 not (self.lexer_ and | |
3040 self.lexer_.alwaysKeepTabs()) | |
3041 ): | |
3042 txt = self.text() | |
2960 txtExpanded = txt.expandtabs(self.__getEditorConfig("TabWidth")) | 3043 txtExpanded = txt.expandtabs(self.__getEditorConfig("TabWidth")) |
2961 if txtExpanded != txt: | 3044 if txtExpanded != txt: |
2962 modified = True | 3045 self.beginUndoAction |
2963 txt = txtExpanded | 3046 self.setText(txt) |
2964 | 3047 self.endUndoAction() |
2965 self.setText(txt) | 3048 |
2966 | 3049 self.setModified(True) |
2967 # get eric specific flags | 3050 |
2968 self.__processFlags() | |
2969 | |
2970 # perform automatic EOL conversion | |
2971 if self.__getEditorConfig("EOLMode", nodefault=True) or \ | |
2972 Preferences.getEditor("AutomaticEOLConversion"): | |
2973 self.convertEols(self.eolMode()) | |
2974 else: | |
2975 fileEol = self.detectEolString(txt) | |
2976 self.setEolModeByEolString(fileEol) | |
2977 | |
2978 self.extractTasks() | |
2979 | |
2980 QApplication.restoreOverrideCursor() | |
2981 | |
2982 self.setModified(modified) | |
2983 self.lastModified = QFileInfo(self.fileName).lastModified() | |
2984 | |
2985 def __removeTrailingWhitespace(self): | 3051 def __removeTrailingWhitespace(self): |
2986 """ | 3052 """ |
2987 Private method to remove trailing whitespace. | 3053 Private method to remove trailing whitespace. |
2988 """ | 3054 """ |
2989 searchRE = r"[ \t]+$" # whitespace at the end of a line | 3055 searchRE = r"[ \t]+$" # whitespace at the end of a line |
3071 @param path directory to save the file in (string) | 3137 @param path directory to save the file in (string) |
3072 @return file name (string) | 3138 @return file name (string) |
3073 """ | 3139 """ |
3074 # save to project, if a project is loaded | 3140 # save to project, if a project is loaded |
3075 if self.project.isOpen(): | 3141 if self.project.isOpen(): |
3076 if self.fileName and \ | 3142 if ( |
3077 self.project.startswithProjectPath(self.fileName): | 3143 self.fileName and |
3144 self.project.startswithProjectPath(self.fileName) | |
3145 ): | |
3078 path = os.path.dirname(self.fileName) | 3146 path = os.path.dirname(self.fileName) |
3079 else: | 3147 else: |
3080 path = self.project.getProjectPath() | 3148 path = self.project.getProjectPath() |
3081 | 3149 |
3082 if not path and self.fileName: | 3150 if not path and self.fileName: |
3083 path = os.path.dirname(self.fileName) | 3151 path = os.path.dirname(self.fileName) |
3084 if not path: | 3152 if not path: |
3085 path = Preferences.getMultiProject("Workspace") or \ | 3153 path = ( |
3154 Preferences.getMultiProject("Workspace") or | |
3086 Utilities.getHomeDir() | 3155 Utilities.getHomeDir() |
3156 ) | |
3087 | 3157 |
3088 from . import Lexers | 3158 from . import Lexers |
3089 if self.fileName: | 3159 if self.fileName: |
3090 filterPattern = "(*{0})".format( | 3160 filterPattern = "(*{0})".format( |
3091 os.path.splitext(self.fileName)[1]) | 3161 os.path.splitext(self.fileName)[1]) |
3139 return False | 3209 return False |
3140 | 3210 |
3141 res = self.writeFile(fn) | 3211 res = self.writeFile(fn) |
3142 if res: | 3212 if res: |
3143 # save to project, if a project is loaded | 3213 # save to project, if a project is loaded |
3144 if self.project.isOpen() and \ | 3214 if ( |
3145 self.project.startswithProjectPath(fn): | 3215 self.project.isOpen() and |
3216 self.project.startswithProjectPath(fn) | |
3217 ): | |
3146 self.project.appendFile(fn) | 3218 self.project.appendFile(fn) |
3147 | 3219 |
3148 return res | 3220 return res |
3149 | 3221 |
3150 def saveFile(self, saveas=False, path=None): | 3222 def saveFile(self, saveas=False, path=None): |
3167 return False | 3239 return False |
3168 | 3240 |
3169 newName = fn | 3241 newName = fn |
3170 | 3242 |
3171 # save to project, if a project is loaded | 3243 # save to project, if a project is loaded |
3172 if self.project.isOpen() and \ | 3244 if ( |
3173 self.project.startswithProjectPath(fn): | 3245 self.project.isOpen() and |
3246 self.project.startswithProjectPath(fn) | |
3247 ): | |
3174 editorConfigEol = self.__getEditorConfig( | 3248 editorConfigEol = self.__getEditorConfig( |
3175 "EOLMode", nodefault=True, | 3249 "EOLMode", nodefault=True, |
3176 config=self.__loadEditorConfigObject(fn)) | 3250 config=self.__loadEditorConfigObject(fn)) |
3177 if editorConfigEol is not None: | 3251 if editorConfigEol is not None: |
3178 self.setEolMode(editorConfigEol) | 3252 self.setEolMode(editorConfigEol) |
3200 self.isResourcesFile = self.fileName.endswith(".qrc") | 3274 self.isResourcesFile = self.fileName.endswith(".qrc") |
3201 self.__initContextMenu() | 3275 self.__initContextMenu() |
3202 self.editorRenamed.emit(self.fileName) | 3276 self.editorRenamed.emit(self.fileName) |
3203 | 3277 |
3204 # save to project, if a project is loaded | 3278 # save to project, if a project is loaded |
3205 if self.project.isOpen() and \ | 3279 if ( |
3206 self.project.startswithProjectPath(fn): | 3280 self.project.isOpen() and |
3281 self.project.startswithProjectPath(fn) | |
3282 ): | |
3207 self.project.appendFile(fn) | 3283 self.project.appendFile(fn) |
3208 self.addedToProject() | 3284 self.addedToProject() |
3209 | 3285 |
3210 self.setLanguage(self.fileName) | 3286 self.setLanguage(self.fileName) |
3211 | 3287 |
3626 commentStr = self.lexer_.commentStr() | 3702 commentStr = self.lexer_.commentStr() |
3627 line, index = self.getCursorPosition() | 3703 line, index = self.getCursorPosition() |
3628 | 3704 |
3629 # check if line starts with our comment string (i.e. was commented | 3705 # check if line starts with our comment string (i.e. was commented |
3630 # by our comment...() slots | 3706 # by our comment...() slots |
3631 if self.hasSelectedText() and \ | 3707 if ( |
3632 self.__isCommentedLine(self.text(self.getSelection()[0]), | 3708 self.hasSelectedText() and |
3633 commentStr): | 3709 self.__isCommentedLine(self.text(self.getSelection()[0]), |
3710 commentStr) | |
3711 ): | |
3634 self.uncommentLineOrSelection() | 3712 self.uncommentLineOrSelection() |
3635 elif not self.__isCommentedLine(self.text(line), commentStr): | 3713 elif not self.__isCommentedLine(self.text(line), commentStr): |
3636 # it doesn't, so comment the line or selection | 3714 # it doesn't, so comment the line or selection |
3637 self.commentLineOrSelection() | 3715 self.commentLineOrSelection() |
3638 else: | 3716 else: |
3639 # determine the start of the comment block | 3717 # determine the start of the comment block |
3640 begline = line | 3718 begline = line |
3641 while begline > 0 and \ | 3719 while ( |
3642 self.__isCommentedLine(self.text(begline - 1), commentStr): | 3720 begline > 0 and |
3721 self.__isCommentedLine(self.text(begline - 1), commentStr) | |
3722 ): | |
3643 begline -= 1 | 3723 begline -= 1 |
3644 # determine the end of the comment block | 3724 # determine the end of the comment block |
3645 endline = line | 3725 endline = line |
3646 lines = self.lines() | 3726 lines = self.lines() |
3647 while endline < lines and \ | 3727 while ( |
3648 self.__isCommentedLine(self.text(endline + 1), commentStr): | 3728 endline < lines and |
3729 self.__isCommentedLine(self.text(endline + 1), commentStr) | |
3730 ): | |
3649 endline += 1 | 3731 endline += 1 |
3650 | 3732 |
3651 self.setSelection(begline, 0, endline, self.lineLength(endline)) | 3733 self.setSelection(begline, 0, endline, self.lineLength(endline)) |
3652 self.uncommentLineOrSelection() | 3734 self.uncommentLineOrSelection() |
3653 | 3735 |
4272 marginBmMask = (1 << self.bookmark) | 4354 marginBmMask = (1 << self.bookmark) |
4273 self.setMarginWidth(self.__bmMargin, 16) | 4355 self.setMarginWidth(self.__bmMargin, 16) |
4274 self.setMarginSensitivity(self.__bmMargin, True) | 4356 self.setMarginSensitivity(self.__bmMargin, True) |
4275 self.setMarginMarkerMask(self.__bmMargin, marginBmMask) | 4357 self.setMarginMarkerMask(self.__bmMargin, marginBmMask) |
4276 | 4358 |
4277 marginBpMask = (1 << self.breakpoint) | \ | 4359 marginBpMask = ( |
4278 (1 << self.cbreakpoint) | \ | 4360 (1 << self.breakpoint) | |
4279 (1 << self.tbreakpoint) | \ | 4361 (1 << self.cbreakpoint) | |
4280 (1 << self.tcbreakpoint) | \ | 4362 (1 << self.tbreakpoint) | |
4281 (1 << self.dbreakpoint) | 4363 (1 << self.tcbreakpoint) | |
4364 (1 << self.dbreakpoint) | |
4365 ) | |
4282 self.setMarginWidth(self.__bpMargin, 16) | 4366 self.setMarginWidth(self.__bpMargin, 16) |
4283 self.setMarginSensitivity(self.__bpMargin, True) | 4367 self.setMarginSensitivity(self.__bpMargin, True) |
4284 self.setMarginMarkerMask(self.__bpMargin, marginBpMask) | 4368 self.setMarginMarkerMask(self.__bpMargin, marginBpMask) |
4285 | 4369 |
4286 marginIndicMask = (1 << self.syntaxerror) | \ | 4370 marginIndicMask = ( |
4287 (1 << self.notcovered) | \ | 4371 (1 << self.syntaxerror) | |
4288 (1 << self.taskmarker) | \ | 4372 (1 << self.notcovered) | |
4289 (1 << self.warning) | \ | 4373 (1 << self.taskmarker) | |
4290 (1 << self.__changeMarkerUnsaved) | \ | 4374 (1 << self.warning) | |
4291 (1 << self.__changeMarkerSaved) | \ | 4375 (1 << self.__changeMarkerUnsaved) | |
4292 (1 << self.currentline) | \ | 4376 (1 << self.__changeMarkerSaved) | |
4293 (1 << self.errorline) | 4377 (1 << self.currentline) | |
4378 (1 << self.errorline) | |
4379 ) | |
4294 self.setMarginWidth(self.__indicMargin, 16) | 4380 self.setMarginWidth(self.__indicMargin, 16) |
4295 self.setMarginSensitivity(self.__indicMargin, True) | 4381 self.setMarginSensitivity(self.__indicMargin, True) |
4296 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask) | 4382 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask) |
4297 | 4383 |
4298 # set linenumber margin settings | 4384 # set linenumber margin settings |
4430 | 4516 |
4431 self.searchIndicator = QsciScintilla.INDIC_CONTAINER | 4517 self.searchIndicator = QsciScintilla.INDIC_CONTAINER |
4432 self.indicatorDefine( | 4518 self.indicatorDefine( |
4433 self.searchIndicator, QsciScintilla.INDIC_BOX, | 4519 self.searchIndicator, QsciScintilla.INDIC_BOX, |
4434 Preferences.getEditorColour("SearchMarkers")) | 4520 Preferences.getEditorColour("SearchMarkers")) |
4435 if not Preferences.getEditor("SearchMarkersEnabled") and \ | 4521 if ( |
4436 not Preferences.getEditor("QuickSearchMarkersEnabled") and \ | 4522 not Preferences.getEditor("SearchMarkersEnabled") and |
4437 not Preferences.getEditor("MarkOccurrencesEnabled"): | 4523 not Preferences.getEditor("QuickSearchMarkersEnabled") and |
4524 not Preferences.getEditor("MarkOccurrencesEnabled") | |
4525 ): | |
4438 self.clearAllIndicators(self.searchIndicator) | 4526 self.clearAllIndicators(self.searchIndicator) |
4439 | 4527 |
4440 self.spellingIndicator = QsciScintilla.INDIC_CONTAINER + 1 | 4528 self.spellingIndicator = QsciScintilla.INDIC_CONTAINER + 1 |
4441 self.indicatorDefine( | 4529 self.indicatorDefine( |
4442 self.spellingIndicator, QsciScintilla.INDIC_SQUIGGLE, | 4530 self.spellingIndicator, QsciScintilla.INDIC_SQUIGGLE, |
4470 | 4558 |
4471 def __setEolMode(self): | 4559 def __setEolMode(self): |
4472 """ | 4560 """ |
4473 Private method to configure the eol mode of the editor. | 4561 Private method to configure the eol mode of the editor. |
4474 """ | 4562 """ |
4475 if self.fileName and \ | 4563 if ( |
4476 self.project.isOpen() and \ | 4564 self.fileName and |
4477 self.project.isProjectFile(self.fileName): | 4565 self.project.isOpen() and |
4566 self.project.isProjectFile(self.fileName) | |
4567 ): | |
4478 eolMode = self.__getEditorConfig("EOLMode", nodefault=True) | 4568 eolMode = self.__getEditorConfig("EOLMode", nodefault=True) |
4479 if eolMode is None: | 4569 if eolMode is None: |
4480 eolStr = self.project.getEolString() | 4570 eolStr = self.project.getEolString() |
4481 self.setEolModeByEolString(eolStr) | 4571 self.setEolModeByEolString(eolStr) |
4482 else: | 4572 else: |
4531 pass | 4621 pass |
4532 | 4622 |
4533 if Preferences.getEditor("CallTipsEnabled"): | 4623 if Preferences.getEditor("CallTipsEnabled"): |
4534 if calltipsStyle == QsciScintilla.CallTipsNoContext: | 4624 if calltipsStyle == QsciScintilla.CallTipsNoContext: |
4535 self.setCallTipsStyle(QsciScintilla.CallTipsNoContext) | 4625 self.setCallTipsStyle(QsciScintilla.CallTipsNoContext) |
4536 elif calltipsStyle == \ | 4626 elif ( |
4537 QsciScintilla.CallTipsNoAutoCompletionContext: | 4627 calltipsStyle == QsciScintilla.CallTipsNoAutoCompletionContext |
4628 ): | |
4538 self.setCallTipsStyle( | 4629 self.setCallTipsStyle( |
4539 QsciScintilla.CallTipsNoAutoCompletionContext) | 4630 QsciScintilla.CallTipsNoAutoCompletionContext) |
4540 else: | 4631 else: |
4541 self.setCallTipsStyle(QsciScintilla.CallTipsContext) | 4632 self.setCallTipsStyle(QsciScintilla.CallTipsContext) |
4542 else: | 4633 else: |
4584 | 4675 |
4585 @param enable flag indicating the desired autocompletion status | 4676 @param enable flag indicating the desired autocompletion status |
4586 (boolean) | 4677 (boolean) |
4587 """ | 4678 """ |
4588 if enable: | 4679 if enable: |
4589 autoCompletionSource = \ | 4680 autoCompletionSource = Preferences.getEditor( |
4590 Preferences.getEditor("AutoCompletionSource") | 4681 "AutoCompletionSource") |
4591 if autoCompletionSource == QsciScintilla.AcsDocument: | 4682 if autoCompletionSource == QsciScintilla.AcsDocument: |
4592 self.setAutoCompletionSource(QsciScintilla.AcsDocument) | 4683 self.setAutoCompletionSource(QsciScintilla.AcsDocument) |
4593 elif autoCompletionSource == QsciScintilla.AcsAPIs: | 4684 elif autoCompletionSource == QsciScintilla.AcsAPIs: |
4594 self.setAutoCompletionSource(QsciScintilla.AcsAPIs) | 4685 self.setAutoCompletionSource(QsciScintilla.AcsAPIs) |
4595 else: | 4686 else: |
4614 | 4705 |
4615 @param charNumber value of the character entered (integer) | 4706 @param charNumber value of the character entered (integer) |
4616 """ | 4707 """ |
4617 char = chr(charNumber) | 4708 char = chr(charNumber) |
4618 # update code documentation viewer | 4709 # update code documentation viewer |
4619 if char == "(" and \ | 4710 if ( |
4620 Preferences.getDocuViewer("ShowInfoOnOpenParenthesis"): | 4711 char == "(" and |
4712 Preferences.getDocuViewer("ShowInfoOnOpenParenthesis") | |
4713 ): | |
4621 self.vm.showEditorInfo(self) | 4714 self.vm.showEditorInfo(self) |
4622 | 4715 |
4623 if self.isListActive(): | 4716 if self.isListActive(): |
4624 if self.__isStartChar(char): | 4717 if self.__isStartChar(char): |
4625 self.cancelList() | 4718 self.cancelList() |
4628 elif char == '(': | 4721 elif char == '(': |
4629 self.cancelList() | 4722 self.cancelList() |
4630 else: | 4723 else: |
4631 self.__acTimer.stop() | 4724 self.__acTimer.stop() |
4632 | 4725 |
4633 if self.callTipsStyle() != QsciScintilla.CallTipsNone and \ | 4726 if ( |
4634 self.lexer_ is not None and chr(charNumber) in '()': | 4727 self.callTipsStyle() != QsciScintilla.CallTipsNone and |
4728 self.lexer_ is not None and chr(charNumber) in '()' | |
4729 ): | |
4635 self.callTip() | 4730 self.callTip() |
4636 | 4731 |
4637 if not self.isCallTipActive(): | 4732 if not self.isCallTipActive(): |
4638 char = chr(charNumber) | 4733 char = chr(charNumber) |
4639 if self.__isStartChar(char): | 4734 if self.__isStartChar(char): |
4690 and function(editor, bool, str) returning nothing in case async | 4785 and function(editor, bool, str) returning nothing in case async |
4691 is True | 4786 is True |
4692 @param asynchroneous flag indicating an asynchroneous function | 4787 @param asynchroneous flag indicating an asynchroneous function |
4693 @type bool | 4788 @type bool |
4694 """ | 4789 """ |
4695 if key in self.__completionListHookFunctions or \ | 4790 if ( |
4696 key in self.__completionListAsyncHookFunctions: | 4791 key in self.__completionListHookFunctions or |
4792 key in self.__completionListAsyncHookFunctions | |
4793 ): | |
4697 # it was already registered | 4794 # it was already registered |
4698 E5MessageBox.warning( | 4795 E5MessageBox.warning( |
4699 self, | 4796 self, |
4700 self.tr("Auto-Completion Provider"), | 4797 self.tr("Auto-Completion Provider"), |
4701 self.tr("""The completion list provider '{0}' was already""" | 4798 self.tr("""The completion list provider '{0}' was already""" |
4746 return | 4843 return |
4747 | 4844 |
4748 if self.isListActive(): | 4845 if self.isListActive(): |
4749 self.cancelList() | 4846 self.cancelList() |
4750 | 4847 |
4751 if self.__completionListHookFunctions or \ | 4848 if ( |
4752 self.__completionListAsyncHookFunctions: | 4849 self.__completionListHookFunctions or |
4850 self.__completionListAsyncHookFunctions | |
4851 ): | |
4753 # Avoid delayed auto-completion after cursor repositioning | 4852 # Avoid delayed auto-completion after cursor repositioning |
4754 self.__acText = self.__getAcText() | 4853 self.__acText = self.__getAcText() |
4755 if auto and Preferences.getEditor("AutoCompletionTimeout"): | 4854 if auto and Preferences.getEditor("AutoCompletionTimeout"): |
4756 self.__acTimer.stop() | 4855 self.__acTimer.stop() |
4757 self.__acContext = context | 4856 self.__acContext = context |
4850 len(self.__completionListHookFunctions) | 4949 len(self.__completionListHookFunctions) |
4851 ): | 4950 ): |
4852 self.__acWatchdog.stop() | 4951 self.__acWatchdog.stop() |
4853 | 4952 |
4854 # Autocomplete with QScintilla if no results present | 4953 # Autocomplete with QScintilla if no results present |
4855 if Preferences.getEditor("AutoCompletionScintillaOnFail") and \ | 4954 if ( |
4856 not self.__acCompletions: | 4955 Preferences.getEditor("AutoCompletionScintillaOnFail") and |
4956 not self.__acCompletions | |
4957 ): | |
4857 self.autoCompleteQScintilla() | 4958 self.autoCompleteQScintilla() |
4858 return | 4959 return |
4859 | 4960 |
4860 # ... or completions are not empty | 4961 # ... or completions are not empty |
4861 if not bool(completions): | 4962 if not bool(completions): |
5173 @param evt the context menu event (QContextMenuEvent) | 5274 @param evt the context menu event (QContextMenuEvent) |
5174 """ | 5275 """ |
5175 evt.accept() | 5276 evt.accept() |
5176 if self.__marginNumber(evt.x()) == -1: | 5277 if self.__marginNumber(evt.x()) == -1: |
5177 self.spellingMenuPos = self.positionFromPoint(evt.pos()) | 5278 self.spellingMenuPos = self.positionFromPoint(evt.pos()) |
5178 if self.spellingMenuPos >= 0 and \ | 5279 if ( |
5179 self.spell is not None and \ | 5280 self.spellingMenuPos >= 0 and |
5180 self.hasIndicator(self.spellingIndicator, self.spellingMenuPos): | 5281 self.spell is not None and |
5282 self.hasIndicator(self.spellingIndicator, | |
5283 self.spellingMenuPos) | |
5284 ): | |
5181 self.spellingMenu.popup(evt.globalPos()) | 5285 self.spellingMenu.popup(evt.globalPos()) |
5182 else: | 5286 else: |
5183 self.menu.popup(evt.globalPos()) | 5287 self.menu.popup(evt.globalPos()) |
5184 else: | 5288 else: |
5185 self.line = self.lineAt(evt.pos()) | 5289 self.line = self.lineAt(evt.pos()) |
5212 if not self.isResourcesFile: | 5316 if not self.isResourcesFile: |
5213 if self.fileName and self.isPyFile(): | 5317 if self.fileName and self.isPyFile(): |
5214 self.menuActs["Show"].setEnabled(True) | 5318 self.menuActs["Show"].setEnabled(True) |
5215 else: | 5319 else: |
5216 self.menuActs["Show"].setEnabled(False) | 5320 self.menuActs["Show"].setEnabled(False) |
5217 if self.fileName and \ | 5321 if ( |
5218 (self.isPyFile() or self.isRubyFile()): | 5322 self.fileName and |
5323 (self.isPyFile() or self.isRubyFile()) | |
5324 ): | |
5219 self.menuActs["Diagrams"].setEnabled(True) | 5325 self.menuActs["Diagrams"].setEnabled(True) |
5220 else: | 5326 else: |
5221 self.menuActs["Diagrams"].setEnabled(False) | 5327 self.menuActs["Diagrams"].setEnabled(False) |
5222 if not self.miniMenu: | 5328 if not self.miniMenu: |
5223 if self.lexer_ is not None: | 5329 if self.lexer_ is not None: |
5293 """ | 5399 """ |
5294 prEnable = False | 5400 prEnable = False |
5295 coEnable = False | 5401 coEnable = False |
5296 | 5402 |
5297 # first check if the file belongs to a project | 5403 # first check if the file belongs to a project |
5298 if self.project.isOpen() and \ | 5404 if ( |
5299 self.project.isProjectSource(self.fileName): | 5405 self.project.isOpen() and |
5406 self.project.isProjectSource(self.fileName) | |
5407 ): | |
5300 fn = self.project.getMainScript(True) | 5408 fn = self.project.getMainScript(True) |
5301 if fn is not None: | 5409 if fn is not None: |
5302 tfn = Utilities.getTestFileName(fn) | 5410 tfn = Utilities.getTestFileName(fn) |
5303 basename = os.path.splitext(fn)[0] | 5411 basename = os.path.splitext(fn)[0] |
5304 tbasename = os.path.splitext(tfn)[0] | 5412 tbasename = os.path.splitext(tfn)[0] |
5305 prEnable = prEnable or \ | 5413 prEnable = ( |
5306 os.path.isfile("{0}.profile".format(basename)) or \ | 5414 prEnable or |
5415 os.path.isfile("{0}.profile".format(basename)) or | |
5307 os.path.isfile("{0}.profile".format(tbasename)) | 5416 os.path.isfile("{0}.profile".format(tbasename)) |
5417 ) | |
5308 coEnable = ( | 5418 coEnable = ( |
5309 coEnable or | 5419 (coEnable or |
5310 os.path.isfile("{0}.coverage".format(basename)) or | 5420 os.path.isfile("{0}.coverage".format(basename)) or |
5311 os.path.isfile("{0}.coverage".format(tbasename))) and \ | 5421 os.path.isfile("{0}.coverage".format(tbasename))) and |
5312 (self.project.isPy3Project() or | 5422 (self.project.isPy3Project() or |
5313 self.project.isPy2Project()) | 5423 self.project.isPy2Project()) |
5424 ) | |
5314 | 5425 |
5315 # now check ourselves | 5426 # now check ourselves |
5316 fn = self.getFileName() | 5427 fn = self.getFileName() |
5317 if fn is not None: | 5428 if fn is not None: |
5318 tfn = Utilities.getTestFileName(fn) | 5429 tfn = Utilities.getTestFileName(fn) |
5319 basename = os.path.splitext(fn)[0] | 5430 basename = os.path.splitext(fn)[0] |
5320 tbasename = os.path.splitext(tfn)[0] | 5431 tbasename = os.path.splitext(tfn)[0] |
5321 prEnable = prEnable or \ | 5432 prEnable = ( |
5322 os.path.isfile("{0}.profile".format(basename)) or \ | 5433 prEnable or |
5434 os.path.isfile("{0}.profile".format(basename)) or | |
5323 os.path.isfile("{0}.profile".format(tbasename)) | 5435 os.path.isfile("{0}.profile".format(tbasename)) |
5436 ) | |
5324 coEnable = ( | 5437 coEnable = ( |
5325 coEnable or | 5438 (coEnable or |
5326 os.path.isfile("{0}.coverage".format(basename)) or | 5439 os.path.isfile("{0}.coverage".format(basename)) or |
5327 os.path.isfile("{0}.coverage".format(tbasename))) and \ | 5440 os.path.isfile("{0}.coverage".format(tbasename))) and |
5328 self.isPyFile() | 5441 self.isPyFile() |
5442 ) | |
5329 | 5443 |
5330 # now check for syntax errors | 5444 # now check for syntax errors |
5331 if self.hasSyntaxErrors(): | 5445 if self.hasSyntaxErrors(): |
5332 coEnable = False | 5446 coEnable = False |
5333 | 5447 |
5343 def __showContextMenuGraphics(self): | 5457 def __showContextMenuGraphics(self): |
5344 """ | 5458 """ |
5345 Private slot handling the aboutToShow signal of the diagrams context | 5459 Private slot handling the aboutToShow signal of the diagrams context |
5346 menu. | 5460 menu. |
5347 """ | 5461 """ |
5348 if self.project.isOpen() and \ | 5462 if ( |
5349 self.project.isProjectSource(self.fileName): | 5463 self.project.isOpen() and |
5464 self.project.isProjectSource(self.fileName) | |
5465 ): | |
5350 self.applicationDiagramMenuAct.setEnabled(True) | 5466 self.applicationDiagramMenuAct.setEnabled(True) |
5351 else: | 5467 else: |
5352 self.applicationDiagramMenuAct.setEnabled(False) | 5468 self.applicationDiagramMenuAct.setEnabled(False) |
5353 | 5469 |
5354 self.showMenu.emit("Graphics", self.graphicsMenu, self) | 5470 self.showMenu.emit("Graphics", self.graphicsMenu, self) |
5407 hasWarnings = bool(self.warnings) | 5523 hasWarnings = bool(self.warnings) |
5408 hasNotCoveredMarkers = bool(self.notcoveredMarkers) | 5524 hasNotCoveredMarkers = bool(self.notcoveredMarkers) |
5409 | 5525 |
5410 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors) | 5526 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors) |
5411 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors) | 5527 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors) |
5412 if hasSyntaxErrors and \ | 5528 if ( |
5413 self.markersAtLine(self.line) & (1 << self.syntaxerror): | 5529 hasSyntaxErrors and |
5530 self.markersAtLine(self.line) & (1 << self.syntaxerror) | |
5531 ): | |
5414 self.marginMenuActs["ShowSyntaxError"].setEnabled(True) | 5532 self.marginMenuActs["ShowSyntaxError"].setEnabled(True) |
5415 else: | 5533 else: |
5416 self.marginMenuActs["ShowSyntaxError"].setEnabled(False) | 5534 self.marginMenuActs["ShowSyntaxError"].setEnabled(False) |
5417 | 5535 |
5418 self.marginMenuActs["NextWarningMarker"].setEnabled(hasWarnings) | 5536 self.marginMenuActs["NextWarningMarker"].setEnabled(hasWarnings) |
5419 self.marginMenuActs["PreviousWarningMarker"].setEnabled( | 5537 self.marginMenuActs["PreviousWarningMarker"].setEnabled( |
5420 hasWarnings) | 5538 hasWarnings) |
5421 self.marginMenuActs["ClearWarnings"].setEnabled(hasWarnings) | 5539 self.marginMenuActs["ClearWarnings"].setEnabled(hasWarnings) |
5422 if hasWarnings and \ | 5540 if ( |
5423 self.markersAtLine(self.line) & (1 << self.warning): | 5541 hasWarnings and |
5542 self.markersAtLine(self.line) & (1 << self.warning) | |
5543 ): | |
5424 self.marginMenuActs["ShowWarning"].setEnabled(True) | 5544 self.marginMenuActs["ShowWarning"].setEnabled(True) |
5425 else: | 5545 else: |
5426 self.marginMenuActs["ShowWarning"].setEnabled(False) | 5546 self.marginMenuActs["ShowWarning"].setEnabled(False) |
5427 | 5547 |
5428 self.marginMenuActs["NextCoverageMarker"].setEnabled( | 5548 self.marginMenuActs["NextCoverageMarker"].setEnabled( |
5465 | 5585 |
5466 @param act reference to the action that was triggered (QAction) | 5586 @param act reference to the action that was triggered (QAction) |
5467 """ | 5587 """ |
5468 encoding = act.data() | 5588 encoding = act.data() |
5469 self.readFile(self.fileName, encoding=encoding) | 5589 self.readFile(self.fileName, encoding=encoding) |
5590 self.__convertTabs() | |
5470 self.__checkEncoding() | 5591 self.__checkEncoding() |
5471 | 5592 |
5472 def __contextSave(self): | 5593 def __contextSave(self): |
5473 """ | 5594 """ |
5474 Private slot handling the save context menu entry. | 5595 Private slot handling the save context menu entry. |
5542 line0Text = self.text(curLine) | 5663 line0Text = self.text(curLine) |
5543 line1Text = self.text(curLine + 1) | 5664 line1Text = self.text(curLine + 1) |
5544 if line1Text in ["", "\r", "\n", "\r\n"]: | 5665 if line1Text in ["", "\r", "\n", "\r\n"]: |
5545 return | 5666 return |
5546 | 5667 |
5547 if line0Text.rstrip("\r\n\\ \t").endswith(("'", '"')) and \ | 5668 if ( |
5548 line1Text.lstrip().startswith(("'", '"')): | 5669 line0Text.rstrip("\r\n\\ \t").endswith(("'", '"')) and |
5670 line1Text.lstrip().startswith(("'", '"')) | |
5671 ): | |
5549 # merging multi line strings | 5672 # merging multi line strings |
5550 startChars = "\r\n\\ \t'\"" | 5673 startChars = "\r\n\\ \t'\"" |
5551 endChars = " \t'\"" | 5674 endChars = " \t'\"" |
5552 else: | 5675 else: |
5553 startChars = "\r\n\\ \t" | 5676 startChars = "\r\n\\ \t" |
5598 """ | 5721 """ |
5599 Public slot to check the autosave flags. | 5722 Public slot to check the autosave flags. |
5600 | 5723 |
5601 @return flag indicating this editor should be saved (boolean) | 5724 @return flag indicating this editor should be saved (boolean) |
5602 """ | 5725 """ |
5603 return bool(self.fileName) and \ | 5726 return ( |
5604 not self.autosaveManuallyDisabled and \ | 5727 bool(self.fileName) and |
5728 not self.autosaveManuallyDisabled and | |
5605 not self.isReadOnly() | 5729 not self.isReadOnly() |
5730 ) | |
5606 | 5731 |
5607 def checkSyntax(self): | 5732 def checkSyntax(self): |
5608 """ | 5733 """ |
5609 Public method to perform an automatic syntax check of the file. | 5734 Public method to perform an automatic syntax check of the file. |
5610 """ | 5735 """ |
5611 fileType = self.filetype | 5736 fileType = self.filetype |
5612 if fileType == "MicroPython": | 5737 if fileType == "MicroPython": |
5613 # adjustment for MicroPython | 5738 # adjustment for MicroPython |
5614 fileType = "Python3" | 5739 fileType = "Python3" |
5615 | 5740 |
5616 if self.syntaxCheckService is None or \ | 5741 if ( |
5617 fileType not in self.syntaxCheckService.getLanguages(): | 5742 self.syntaxCheckService is None or |
5743 fileType not in self.syntaxCheckService.getLanguages() | |
5744 ): | |
5618 return | 5745 return |
5619 | 5746 |
5620 if Preferences.getEditor("AutoCheckSyntax"): | 5747 if Preferences.getEditor("AutoCheckSyntax"): |
5621 if Preferences.getEditor("OnlineSyntaxCheck"): | 5748 if Preferences.getEditor("OnlineSyntaxCheck"): |
5622 self.__onlineSyntaxCheckTimer.stop() | 5749 self.__onlineSyntaxCheckTimer.stop() |
5713 """ | 5840 """ |
5714 files = [] | 5841 files = [] |
5715 | 5842 |
5716 # first check if the file belongs to a project and there is | 5843 # first check if the file belongs to a project and there is |
5717 # a project coverage file | 5844 # a project coverage file |
5718 if self.project.isOpen() and \ | 5845 if ( |
5719 self.project.isProjectSource(self.fileName): | 5846 self.project.isOpen() and |
5847 self.project.isProjectSource(self.fileName) | |
5848 ): | |
5720 fn = self.project.getMainScript(True) | 5849 fn = self.project.getMainScript(True) |
5721 if fn is not None: | 5850 if fn is not None: |
5722 tfn = Utilities.getTestFileName(fn) | 5851 tfn = Utilities.getTestFileName(fn) |
5723 basename = os.path.splitext(fn)[0] | 5852 basename = os.path.splitext(fn)[0] |
5724 tbasename = os.path.splitext(tfn)[0] | 5853 tbasename = os.path.splitext(tfn)[0] |
5891 """ | 6020 """ |
5892 files = [] | 6021 files = [] |
5893 | 6022 |
5894 # first check if the file belongs to a project and there is | 6023 # first check if the file belongs to a project and there is |
5895 # a project profile file | 6024 # a project profile file |
5896 if self.project.isOpen() and \ | 6025 if ( |
5897 self.project.isProjectSource(self.fileName): | 6026 self.project.isOpen() and |
6027 self.project.isProjectSource(self.fileName) | |
6028 ): | |
5898 fn = self.project.getMainScript(True) | 6029 fn = self.project.getMainScript(True) |
5899 if fn is not None: | 6030 if fn is not None: |
5900 tfn = Utilities.getTestFileName(fn) | 6031 tfn = Utilities.getTestFileName(fn) |
5901 basename = os.path.splitext(fn)[0] | 6032 basename = os.path.splitext(fn)[0] |
5902 tbasename = os.path.splitext(tfn)[0] | 6033 tbasename = os.path.splitext(tfn)[0] |
5985 handle = self.markerAdd(line - 1, self.syntaxerror) | 6116 handle = self.markerAdd(line - 1, self.syntaxerror) |
5986 self.syntaxerrors[handle] = [(msg, index)] | 6117 self.syntaxerrors[handle] = [(msg, index)] |
5987 self.syntaxerrorToggled.emit(self) | 6118 self.syntaxerrorToggled.emit(self) |
5988 else: | 6119 else: |
5989 for handle in list(self.syntaxerrors.keys()): | 6120 for handle in list(self.syntaxerrors.keys()): |
5990 if self.markerLine(handle) == line - 1 and \ | 6121 if ( |
5991 (msg, index) not in self.syntaxerrors[handle]: | 6122 self.markerLine(handle) == line - 1 and |
6123 (msg, index) not in self.syntaxerrors[handle] | |
6124 ): | |
5992 self.syntaxerrors[handle].append((msg, index)) | 6125 self.syntaxerrors[handle].append((msg, index)) |
5993 if show: | 6126 if show: |
5994 self.setCursorPosition(line - 1, index) | 6127 self.setCursorPosition(line - 1, index) |
5995 self.ensureLineVisible(line - 1) | 6128 self.ensureLineVisible(line - 1) |
5996 else: | 6129 else: |
6140 handle = self.markerAdd(line - 1, self.warning) | 6273 handle = self.markerAdd(line - 1, self.warning) |
6141 self.warnings[handle] = [warn] | 6274 self.warnings[handle] = [warn] |
6142 self.syntaxerrorToggled.emit(self) | 6275 self.syntaxerrorToggled.emit(self) |
6143 else: | 6276 else: |
6144 for handle in list(self.warnings.keys()): | 6277 for handle in list(self.warnings.keys()): |
6145 if self.markerLine(handle) == line - 1 and \ | 6278 if ( |
6146 warn not in self.warnings[handle]: | 6279 self.markerLine(handle) == line - 1 and |
6280 warn not in self.warnings[handle] | |
6281 ): | |
6147 self.warnings[handle].append(warn) | 6282 self.warnings[handle].append(warn) |
6148 else: | 6283 else: |
6149 for handle in list(self.warnings.keys()): | 6284 for handle in list(self.warnings.keys()): |
6150 if self.markerLine(handle) == line - 1: | 6285 if self.markerLine(handle) == line - 1: |
6151 del self.warnings[handle] | 6286 del self.warnings[handle] |
6308 def __setAnnotationStyles(self): | 6443 def __setAnnotationStyles(self): |
6309 """ | 6444 """ |
6310 Private slot to define the style used by inline annotations. | 6445 Private slot to define the style used by inline annotations. |
6311 """ | 6446 """ |
6312 if hasattr(QsciScintilla, "annotate"): | 6447 if hasattr(QsciScintilla, "annotate"): |
6313 self.annotationWarningStyle = \ | 6448 self.annotationWarningStyle = ( |
6314 QsciScintilla.STYLE_LASTPREDEFINED + 1 | 6449 QsciScintilla.STYLE_LASTPREDEFINED + 1 |
6450 ) | |
6315 self.SendScintilla( | 6451 self.SendScintilla( |
6316 QsciScintilla.SCI_STYLESETFORE, | 6452 QsciScintilla.SCI_STYLESETFORE, |
6317 self.annotationWarningStyle, | 6453 self.annotationWarningStyle, |
6318 Preferences.getEditorColour("AnnotationsWarningForeground")) | 6454 Preferences.getEditorColour("AnnotationsWarningForeground")) |
6319 self.SendScintilla( | 6455 self.SendScintilla( |
6399 """ | 6535 """ |
6400 Private method to refresh the annotations. | 6536 Private method to refresh the annotations. |
6401 """ | 6537 """ |
6402 if hasattr(QsciScintilla, "annotate"): | 6538 if hasattr(QsciScintilla, "annotate"): |
6403 self.clearAnnotations() | 6539 self.clearAnnotations() |
6404 for handle in list(self.warnings.keys()) + \ | 6540 for handle in ( |
6405 list(self.syntaxerrors.keys()): | 6541 list(self.warnings.keys()) + |
6542 list(self.syntaxerrors.keys()) | |
6543 ): | |
6406 line = self.markerLine(handle) | 6544 line = self.markerLine(handle) |
6407 self.__setAnnotation(line) | 6545 self.__setAnnotation(line) |
6408 | 6546 |
6409 ################################################################# | 6547 ################################################################# |
6410 ## Fold handling methods | 6548 ## Fold handling methods |
6731 try: | 6869 try: |
6732 self.setCaretWidth(self.caretWidth) | 6870 self.setCaretWidth(self.caretWidth) |
6733 except AttributeError: | 6871 except AttributeError: |
6734 pass | 6872 pass |
6735 self.__updateReadOnly(False) | 6873 self.__updateReadOnly(False) |
6736 if self.vm.editorsCheckFocusInEnabled() and \ | 6874 if ( |
6737 not self.inReopenPrompt and self.fileName and \ | 6875 self.vm.editorsCheckFocusInEnabled() and |
6738 QFileInfo(self.fileName).lastModified().toString() != \ | 6876 not self.inReopenPrompt and self.fileName and |
6739 self.lastModified.toString(): | 6877 QFileInfo(self.fileName).lastModified().toString() != |
6878 self.lastModified.toString() | |
6879 ): | |
6740 self.inReopenPrompt = True | 6880 self.inReopenPrompt = True |
6741 if Preferences.getEditor("AutoReopen") and not self.isModified(): | 6881 if Preferences.getEditor("AutoReopen") and not self.isModified(): |
6742 self.refresh() | 6882 self.refresh() |
6743 else: | 6883 else: |
6744 msg = self.tr( | 6884 msg = self.tr( |
6745 """<p>The file <b>{0}</b> has been changed while it""" | 6885 """<p>The file <b>{0}</b> has been changed while it""" |
6746 """ was opened in eric6. Reread it?</p>""")\ | 6886 """ was opened in eric6. Reread it?</p>""" |
6747 .format(self.fileName) | 6887 ).format(self.fileName) |
6748 yesDefault = True | 6888 yesDefault = True |
6749 if self.isModified(): | 6889 if self.isModified(): |
6750 msg += self.tr( | 6890 msg += self.tr( |
6751 """<br><b>Warning:</b> You will lose""" | 6891 """<br><b>Warning:</b> You will lose""" |
6752 """ your changes upon reopening it.""") | 6892 """ your changes upon reopening it.""") |
6788 other modes. This is to make the editor windows work nicer | 6928 other modes. This is to make the editor windows work nicer |
6789 with the QWorkspace. | 6929 with the QWorkspace. |
6790 | 6930 |
6791 @param evt the event, that was generated (QEvent) | 6931 @param evt the event, that was generated (QEvent) |
6792 """ | 6932 """ |
6793 if evt.type() == QEvent.WindowStateChange and \ | 6933 if ( |
6794 bool(self.fileName): | 6934 evt.type() == QEvent.WindowStateChange and |
6935 bool(self.fileName) | |
6936 ): | |
6795 if self.windowState() == Qt.WindowStates(Qt.WindowMinimized): | 6937 if self.windowState() == Qt.WindowStates(Qt.WindowMinimized): |
6796 cap = os.path.basename(self.fileName) | 6938 cap = os.path.basename(self.fileName) |
6797 else: | 6939 else: |
6798 cap = self.fileName | 6940 cap = self.fileName |
6799 if self.isReadOnly(): | 6941 if self.isReadOnly(): |
6815 """ | 6957 """ |
6816 Protected method to handle wheel events. | 6958 Protected method to handle wheel events. |
6817 | 6959 |
6818 @param evt reference to the wheel event (QWheelEvent) | 6960 @param evt reference to the wheel event (QWheelEvent) |
6819 """ | 6961 """ |
6820 if qVersionTuple() >= (5, 0, 0): | 6962 delta = evt.angleDelta().y() |
6821 delta = evt.angleDelta().y() | |
6822 else: | |
6823 delta = evt.delta() | |
6824 if evt.modifiers() & Qt.ControlModifier: | 6963 if evt.modifiers() & Qt.ControlModifier: |
6825 if delta < 0: | 6964 if delta < 0: |
6826 self.zoomOut() | 6965 self.zoomOut() |
6827 elif delta > 0: | 6966 elif delta > 0: |
6828 self.zoomIn() | 6967 self.zoomIn() |
6906 signal if there was an attribute change. | 7045 signal if there was an attribute change. |
6907 """ | 7046 """ |
6908 if self.fileName == "": | 7047 if self.fileName == "": |
6909 return | 7048 return |
6910 | 7049 |
6911 readOnly = not QFileInfo(self.fileName).isWritable() or \ | 7050 readOnly = ( |
7051 not QFileInfo(self.fileName).isWritable() or | |
6912 self.isReadOnly() | 7052 self.isReadOnly() |
7053 ) | |
6913 if not bForce and (readOnly == self.isReadOnly()): | 7054 if not bForce and (readOnly == self.isReadOnly()): |
6914 return | 7055 return |
6915 | 7056 |
6916 cap = self.fileName | 7057 cap = self.fileName |
6917 if readOnly: | 7058 if readOnly: |
6952 self.readFile(self.fileName) | 7093 self.readFile(self.fileName) |
6953 except IOError: | 7094 except IOError: |
6954 # do not prompt for this change again... | 7095 # do not prompt for this change again... |
6955 self.lastModified = QDateTime.currentDateTime() | 7096 self.lastModified = QDateTime.currentDateTime() |
6956 self.setModified(False) | 7097 self.setModified(False) |
7098 self.__convertTabs() | |
6957 | 7099 |
6958 # re-initialize the online change tracer | 7100 # re-initialize the online change tracer |
6959 self.__reinitOnlineChangeTrace() | 7101 self.__reinitOnlineChangeTrace() |
6960 | 7102 |
6961 # reset cursor position | 7103 # reset cursor position |
7211 """ | 7353 """ |
7212 from Graphics.UMLDialog import UMLDialog | 7354 from Graphics.UMLDialog import UMLDialog |
7213 if not self.checkDirty(): | 7355 if not self.checkDirty(): |
7214 return | 7356 return |
7215 | 7357 |
7216 package = os.path.isdir(self.fileName) and \ | 7358 package = ( |
7359 os.path.isdir(self.fileName) and | |
7217 self.fileName or os.path.dirname(self.fileName) | 7360 self.fileName or os.path.dirname(self.fileName) |
7361 ) | |
7218 res = E5MessageBox.yesNo( | 7362 res = E5MessageBox.yesNo( |
7219 self, | 7363 self, |
7220 self.tr("Package Diagram"), | 7364 self.tr("Package Diagram"), |
7221 self.tr("""Include class attributes?"""), | 7365 self.tr("""Include class attributes?"""), |
7222 yesDefault=True) | 7366 yesDefault=True) |
7231 """ | 7375 """ |
7232 from Graphics.UMLDialog import UMLDialog | 7376 from Graphics.UMLDialog import UMLDialog |
7233 if not self.checkDirty(): | 7377 if not self.checkDirty(): |
7234 return | 7378 return |
7235 | 7379 |
7236 package = os.path.isdir(self.fileName) and self.fileName \ | 7380 package = ( |
7237 or os.path.dirname(self.fileName) | 7381 os.path.isdir(self.fileName) and |
7382 self.fileName or os.path.dirname(self.fileName) | |
7383 ) | |
7238 res = E5MessageBox.yesNo( | 7384 res = E5MessageBox.yesNo( |
7239 self, | 7385 self, |
7240 self.tr("Imports Diagram"), | 7386 self.tr("Imports Diagram"), |
7241 self.tr("""Include imports from external modules?""")) | 7387 self.tr("""Include imports from external modules?""")) |
7242 self.importsDiagram = UMLDialog( | 7388 self.importsDiagram = UMLDialog( |
7378 | 7524 |
7379 def projectOpened(self): | 7525 def projectOpened(self): |
7380 """ | 7526 """ |
7381 Public slot to handle the opening of a project. | 7527 Public slot to handle the opening of a project. |
7382 """ | 7528 """ |
7383 if self.fileName and \ | 7529 if ( |
7384 self.project.isProjectSource(self.fileName): | 7530 self.fileName and |
7531 self.project.isProjectSource(self.fileName) | |
7532 ): | |
7385 self.project.projectPropertiesChanged.connect( | 7533 self.project.projectPropertiesChanged.connect( |
7386 self.__projectPropertiesChanged) | 7534 self.__projectPropertiesChanged) |
7387 self.setSpellingForProject() | 7535 self.setSpellingForProject() |
7388 | 7536 |
7389 def projectClosed(self): | 7537 def projectClosed(self): |
7435 def setSpellingForProject(self): | 7583 def setSpellingForProject(self): |
7436 """ | 7584 """ |
7437 Public method to set the spell checking options for files belonging | 7585 Public method to set the spell checking options for files belonging |
7438 to the current project. | 7586 to the current project. |
7439 """ | 7587 """ |
7440 if self.fileName and \ | 7588 if ( |
7441 self.project.isOpen() and \ | 7589 self.fileName and |
7442 self.project.isProjectSource(self.fileName): | 7590 self.project.isOpen() and |
7591 self.project.isProjectSource(self.fileName) | |
7592 ): | |
7443 pwl, pel = self.project.getProjectDictionaries() | 7593 pwl, pel = self.project.getProjectDictionaries() |
7444 self.__setSpellingLanguage(self.project.getProjectSpellLanguage(), | 7594 self.__setSpellingLanguage(self.project.getProjectSpellLanguage(), |
7445 pwl=pwl, pel=pel) | 7595 pwl=pwl, pel=pel) |
7446 | 7596 |
7447 def setAutoSpellChecking(self): | 7597 def setAutoSpellChecking(self): |
7471 @return flag indicating pos is in a spell check region (boolean) | 7621 @return flag indicating pos is in a spell check region (boolean) |
7472 """ | 7622 """ |
7473 if self.__spellCheckStringsOnly: | 7623 if self.__spellCheckStringsOnly: |
7474 style = self.styleAt(pos) | 7624 style = self.styleAt(pos) |
7475 if self.lexer_ is not None: | 7625 if self.lexer_ is not None: |
7476 return self.lexer_.isCommentStyle(style) or \ | 7626 return ( |
7627 self.lexer_.isCommentStyle(style) or | |
7477 self.lexer_.isStringStyle(style) | 7628 self.lexer_.isStringStyle(style) |
7629 ) | |
7478 return True | 7630 return True |
7479 | 7631 |
7480 @pyqtSlot(int) | 7632 @pyqtSlot(int) |
7481 def __spellCharAdded(self, charNumber): | 7633 def __spellCharAdded(self, charNumber): |
7482 """ | 7634 """ |
7617 @return tuple indicating, if the editor is sharable, the sharing | 7769 @return tuple indicating, if the editor is sharable, the sharing |
7618 status, if it is inside a locally initiated shared edit session | 7770 status, if it is inside a locally initiated shared edit session |
7619 and if it is inside a remotely initiated shared edit session | 7771 and if it is inside a remotely initiated shared edit session |
7620 (boolean, boolean, boolean, boolean) | 7772 (boolean, boolean, boolean, boolean) |
7621 """ | 7773 """ |
7622 return bool(self.fileName) and \ | 7774 return ( |
7623 self.project.isOpen() and \ | 7775 (bool(self.fileName) and |
7624 self.project.isProjectFile(self.fileName), \ | 7776 self.project.isOpen() and |
7625 self.__isShared, self.__inSharedEdit, self.__inRemoteSharedEdit | 7777 self.project.isProjectFile(self.fileName)), |
7778 self.__isShared, | |
7779 self.__inSharedEdit, | |
7780 self.__inRemoteSharedEdit | |
7781 ) | |
7626 | 7782 |
7627 def shareConnected(self, connected): | 7783 def shareConnected(self, connected): |
7628 """ | 7784 """ |
7629 Public slot to handle a change of the connected state. | 7785 Public slot to handle a change of the connected state. |
7630 | 7786 |
7713 Public slot to handle received editor commands. | 7869 Public slot to handle received editor commands. |
7714 | 7870 |
7715 @param command command string (string) | 7871 @param command command string (string) |
7716 """ | 7872 """ |
7717 if self.__isShared: | 7873 if self.__isShared: |
7718 if self.__isSyncing and \ | 7874 if ( |
7719 not command.startswith(Editor.SyncToken + Editor.Separator): | 7875 self.__isSyncing and |
7876 not command.startswith(Editor.SyncToken + Editor.Separator) | |
7877 ): | |
7720 self.__receivedWhileSyncing.append(command) | 7878 self.__receivedWhileSyncing.append(command) |
7721 else: | 7879 else: |
7722 self.__dispatchCommand(command) | 7880 self.__dispatchCommand(command) |
7723 | 7881 |
7724 def __dispatchCommand(self, command): | 7882 def __dispatchCommand(self, command): |
7935 | 8093 |
7936 from .SortOptionsDialog import SortOptionsDialog | 8094 from .SortOptionsDialog import SortOptionsDialog |
7937 dlg = SortOptionsDialog() | 8095 dlg = SortOptionsDialog() |
7938 if dlg.exec_() == QDialog.Accepted: | 8096 if dlg.exec_() == QDialog.Accepted: |
7939 ascending, alnum, caseSensitive = dlg.getData() | 8097 ascending, alnum, caseSensitive = dlg.getData() |
7940 origStartLine, origStartIndex, origEndLine, origEndIndex = \ | 8098 origStartLine, origStartIndex, origEndLine, origEndIndex = ( |
7941 self.getRectangularSelection() | 8099 self.getRectangularSelection() |
8100 ) | |
7942 # convert to upper-left to lower-right | 8101 # convert to upper-left to lower-right |
7943 startLine = min(origStartLine, origEndLine) | 8102 startLine = min(origStartLine, origEndLine) |
7944 startIndex = min(origStartIndex, origEndIndex) | 8103 startIndex = min(origStartIndex, origEndIndex) |
7945 endLine = max(origStartLine, origEndLine) | 8104 endLine = max(origStartLine, origEndLine) |
7946 endIndex = max(origStartIndex, origEndIndex) | 8105 endIndex = max(origStartIndex, origEndIndex) |
8017 key = (int(modifiers), int(button)) | 8176 key = (int(modifiers), int(button)) |
8018 | 8177 |
8019 self.vm.eventFilter(self, evt) | 8178 self.vm.eventFilter(self, evt) |
8020 super(Editor, self).mouseReleaseEvent(evt) | 8179 super(Editor, self).mouseReleaseEvent(evt) |
8021 | 8180 |
8022 if button != Qt.NoButton and \ | 8181 if ( |
8023 Preferences.getEditor("MouseClickHandlersEnabled") and \ | 8182 button != Qt.NoButton and |
8024 key in self.__mouseClickHandlers: | 8183 Preferences.getEditor("MouseClickHandlersEnabled") and |
8184 key in self.__mouseClickHandlers | |
8185 ): | |
8025 evt.accept() | 8186 evt.accept() |
8026 self.__mouseClickHandlers[key][1](self) | 8187 self.__mouseClickHandlers[key][1](self) |
8027 | 8188 |
8028 def setMouseClickHandler(self, name, modifiers, button, function): | 8189 def setMouseClickHandler(self, name, modifiers, button, function): |
8029 """ | 8190 """ |
8198 | 8359 |
8199 if not config: | 8360 if not config: |
8200 if nodefault: | 8361 if nodefault: |
8201 return None | 8362 return None |
8202 else: | 8363 else: |
8203 return Preferences.getEditor(option) | 8364 value = self.__getOverrideValue(option) |
8365 if value is None: | |
8366 # no override | |
8367 value = Preferences.getEditor(option) | |
8368 return value | |
8204 | 8369 |
8205 try: | 8370 try: |
8206 if option == "EOLMode": | 8371 if option == "EOLMode": |
8207 value = config["end_of_line"] | 8372 value = config["end_of_line"] |
8208 if value == "lf": | 8373 if value == "lf": |
8232 except KeyError: | 8397 except KeyError: |
8233 value = None | 8398 value = None |
8234 | 8399 |
8235 if value is None and not nodefault: | 8400 if value is None and not nodefault: |
8236 # use Preferences in case of error | 8401 # use Preferences in case of error |
8237 value = Preferences.getEditor(option) | 8402 value = self.__getOverrideValue(option) |
8403 if value is None: | |
8404 # no override | |
8405 value = Preferences.getEditor(option) | |
8238 | 8406 |
8239 return value | 8407 return value |
8240 | 8408 |
8241 def getEditorConfig(self, option): | 8409 def getEditorConfig(self, option): |
8242 """ | 8410 """ |
8247 @return value of requested setting | 8415 @return value of requested setting |
8248 @rtype any | 8416 @rtype any |
8249 """ | 8417 """ |
8250 return self.__getEditorConfig(option) | 8418 return self.__getEditorConfig(option) |
8251 | 8419 |
8420 def __getOverrideValue(self, option): | |
8421 """ | |
8422 Private method to get an override value for the current file type. | |
8423 | |
8424 @param option Preferences option key | |
8425 @type str | |
8426 @return override value; None in case nothing is defined | |
8427 @rtype any | |
8428 """ | |
8429 if option in ("TabWidth", "IndentWidth"): | |
8430 overrides = Preferences.getEditor("TabIndentOverride") | |
8431 if self.filetype in overrides: | |
8432 if option == "TabWidth": | |
8433 return overrides[self.filetype][0] | |
8434 elif option == "IndentWidth": | |
8435 return overrides[self.filetype][1] | |
8436 | |
8437 return None | |
8438 | |
8252 def mouseDoubleClickEvent(self, evt): | 8439 def mouseDoubleClickEvent(self, evt): |
8253 """ | 8440 """ |
8254 Protected method to handle mouse double click events. | 8441 Protected method to handle mouse double click events. |
8255 | 8442 |
8256 @param evt reference to the mouse event | 8443 @param evt reference to the mouse event |