src/eric7/QScintilla/Editor.py

branch
eric7-maintenance
changeset 10460
3b34efa2857c
parent 10349
df7edc29cbfb
parent 10449
cc468bd2abdf
child 10534
783d835d7fe4
equal deleted inserted replaced
10366:411df92e881f 10460:3b34efa2857c
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (c) 2002 - 2023 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2002 - 2024 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 5
6 """ 6 """
7 Module implementing the editor component of the eric IDE. 7 Module implementing the editor component of the eric IDE.
8 """ 8 """
49 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor 49 from eric7.EricGui.EricOverrideCursor import EricOverrideCursor
50 from eric7.EricUtilities.EricCache import EricCache 50 from eric7.EricUtilities.EricCache import EricCache
51 from eric7.EricWidgets import EricFileDialog, EricMessageBox 51 from eric7.EricWidgets import EricFileDialog, EricMessageBox
52 from eric7.EricWidgets.EricApplication import ericApp 52 from eric7.EricWidgets.EricApplication import ericApp
53 from eric7.Globals import recentNameBreakpointConditions 53 from eric7.Globals import recentNameBreakpointConditions
54 from eric7.SystemUtilities import OSUtilities, PythonUtilities 54 from eric7.SystemUtilities import FileSystemUtilities, OSUtilities, PythonUtilities
55 from eric7.UI import PythonDisViewer 55 from eric7.UI import PythonDisViewer
56 from eric7.Utilities import MouseUtilities 56 from eric7.Utilities import MouseUtilities
57 57
58 from . import Exporters, Lexers, TypingCompleters 58 from . import Exporters, Lexers, TypingCompleters
59 from .EditorMarkerMap import EditorMarkerMap 59 from .EditorMarkerMap import EditorMarkerMap
144 lastEditPositionAvailable = pyqtSignal() 144 lastEditPositionAvailable = pyqtSignal()
145 refreshed = pyqtSignal() 145 refreshed = pyqtSignal()
146 settingsRead = pyqtSignal() 146 settingsRead = pyqtSignal()
147 mouseDoubleClick = pyqtSignal(QPoint, Qt.MouseButton) 147 mouseDoubleClick = pyqtSignal(QPoint, Qt.MouseButton)
148 148
149 # TODO: convert to an enum.Enum
149 WarningCode = 1 150 WarningCode = 1
150 WarningPython = 2 151 WarningPython = 2
151 WarningStyle = 3 152 WarningStyle = 3
152 WarningInfo = 4 153 WarningInfo = 4
153 WarningError = 5 154 WarningError = 5
154 155
156 # TODO: convert to an enum.IntEnum (also in Assistant plugin)
155 # Autocompletion icon definitions 157 # Autocompletion icon definitions
156 ClassID = 1 158 ClassID = 1
157 ClassProtectedID = 2 159 ClassProtectedID = 2
158 ClassPrivateID = 3 160 ClassPrivateID = 3
159 MethodID = 4 161 MethodID = 4
416 if editor is None: 418 if editor is None:
417 if self.fileName: 419 if self.fileName:
418 if not Utilities.MimeTypes.isTextFile(self.fileName): 420 if not Utilities.MimeTypes.isTextFile(self.fileName):
419 raise OSError() 421 raise OSError()
420 422
421 if self.isLocalFile() and pathlib.Path(self.fileName).exists(): 423 if (
424 FileSystemUtilities.isPlainFileName(self.fileName)
425 and pathlib.Path(self.fileName).exists()
426 ):
422 fileSizeKB = pathlib.Path(self.fileName).stat().st_size // 1024 427 fileSizeKB = pathlib.Path(self.fileName).stat().st_size // 1024
423 if fileSizeKB > Preferences.getEditor("RejectFilesize"): 428 if fileSizeKB > Preferences.getEditor("RejectFilesize"):
424 EricMessageBox.warning( 429 EricMessageBox.warning(
425 None, 430 None,
426 self.tr("Open File"), 431 self.tr("Open File"),
630 @param name name of the current file 635 @param name name of the current file
631 @type str 636 @type str
632 """ 637 """
633 renamed = self.fileName != name 638 renamed = self.fileName != name
634 639
640 oldFileName = self.fileName
635 self.fileName = name 641 self.fileName = name
636 642
637 if renamed: 643 if renamed:
638 self.vm.setEditorName(self, self.fileName) 644 self.vm.setEditorName(self, self.fileName)
645 self.vm.removeWatchedFilePath(oldFileName)
646 self.vm.addWatchedFilePath(self.fileName)
639 647
640 if self.fileName: 648 if self.fileName:
641 self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower() 649 self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower()
642 else: 650 else:
643 self.__fileNameExtension = "" 651 self.__fileNameExtension = ""
644
645 def isLocalFile(self):
646 """
647 Public method to check, if the editor contains a local file.
648
649 @return flag indicating a local file
650 @rtype bool
651 """
652 return not self.fileName.startswith(("device:", "remote:"))
653
654 def isDeviceFile(self):
655 """
656 Public method to check, if the editor contains a MCU device file.
657
658 @return flag indicating a MCU device file
659 @rtype bool
660 """
661 return self.fileName.startswith("device:")
662
663 def isRemoteFile(self):
664 """
665 Public method to check, if the editor contains a remote file.
666
667 @return flag indicating a remote file
668 @rtype bool
669 """
670 return self.fileName.startswith("remote:")
671 652
672 def __registerImages(self): 653 def __registerImages(self):
673 """ 654 """
674 Private method to register images for autocompletion lists. 655 Private method to register images for autocompletion lists.
675 """ 656 """
765 def __bindName(self, line0): 746 def __bindName(self, line0):
766 """ 747 """
767 Private method to generate a dummy filename for binding a lexer. 748 Private method to generate a dummy filename for binding a lexer.
768 749
769 @param line0 first line of text to use in the generation process 750 @param line0 first line of text to use in the generation process
770 (string) 751 @type str
771 @return dummy file name to be used for binding a lexer (string) 752 @return dummy file name to be used for binding a lexer
753 @rtype str
772 """ 754 """
773 bindName = "" 755 bindName = ""
774 line0 = line0.lower() 756 line0 = line0.lower()
775 757
776 # check first line if it does not start with #! 758 # check first line if it does not start with #!
840 822
841 def getMenu(self, menuName): 823 def getMenu(self, menuName):
842 """ 824 """
843 Public method to get a reference to the main context menu or a submenu. 825 Public method to get a reference to the main context menu or a submenu.
844 826
845 @param menuName name of the menu (string) 827 @param menuName name of the menu
846 @return reference to the requested menu (QMenu) or None 828 @type str
829 @return reference to the requested menu or None
830 @rtype QMenu
847 """ 831 """
848 try: 832 try:
849 return self.__menus[menuName] 833 return self.__menus[menuName]
850 except KeyError: 834 except KeyError:
851 return None 835 return None
852 836
853 def hasMiniMenu(self): 837 def hasMiniMenu(self):
854 """ 838 """
855 Public method to check the miniMenu flag. 839 Public method to check the miniMenu flag.
856 840
857 @return flag indicating a minimized context menu (boolean) 841 @return flag indicating a minimized context menu
842 @rtype bool
858 """ 843 """
859 return self.miniMenu 844 return self.miniMenu
860 845
861 def __initContextMenu(self): 846 def __initContextMenu(self):
862 """ 847 """
1212 self.languagesActGrp.addAction(self.noLanguageAct) 1197 self.languagesActGrp.addAction(self.noLanguageAct)
1213 menu.addSeparator() 1198 menu.addSeparator()
1214 1199
1215 self.supportedLanguages = {} 1200 self.supportedLanguages = {}
1216 supportedLanguages = Lexers.getSupportedLanguages() 1201 supportedLanguages = Lexers.getSupportedLanguages()
1217 languages = sorted(supportedLanguages.keys()) 1202 for language in sorted(supportedLanguages):
1218 for language in languages:
1219 if language != "Guessed": 1203 if language != "Guessed":
1220 self.supportedLanguages[language] = supportedLanguages[language][:2] 1204 self.supportedLanguages[language] = supportedLanguages[language][:2]
1221 act = menu.addAction( 1205 act = menu.addAction(
1222 EricPixmapCache.getIcon(supportedLanguages[language][2]), 1206 EricPixmapCache.getIcon(supportedLanguages[language][2]),
1223 self.supportedLanguages[language][0], 1207 self.supportedLanguages[language][0],
1523 1507
1524 def exportFile(self, exporterFormat): 1508 def exportFile(self, exporterFormat):
1525 """ 1509 """
1526 Public method to export the file. 1510 Public method to export the file.
1527 1511
1528 @param exporterFormat format the file should be exported into (string) 1512 @param exporterFormat format the file should be exported into
1513 @type str
1529 """ 1514 """
1530 if exporterFormat: 1515 if exporterFormat:
1531 exporter = Exporters.getExporter(exporterFormat, self) 1516 exporter = Exporters.getExporter(exporterFormat, self)
1532 if exporter: 1517 if exporter:
1533 exporter.exportSource() 1518 exporter.exportSource()
1563 1548
1564 def __selectPygmentsLexer(self): 1549 def __selectPygmentsLexer(self):
1565 """ 1550 """
1566 Private method to select a specific pygments lexer. 1551 Private method to select a specific pygments lexer.
1567 1552
1568 @return name of the selected pygments lexer (string) 1553 @return name of the selected pygments lexer
1554 @rtype str
1569 """ 1555 """
1570 from pygments.lexers import get_all_lexers # __IGNORE_WARNING_I102__ 1556 from pygments.lexers import get_all_lexers # __IGNORE_WARNING_I102__
1571 1557
1572 lexerList = sorted(lex[0] for lex in get_all_lexers()) 1558 lexerList = sorted(lex[0] for lex in get_all_lexers())
1573 try: 1559 try:
1591 1577
1592 def __languageMenuTriggered(self, act): 1578 def __languageMenuTriggered(self, act):
1593 """ 1579 """
1594 Private method to handle the selection of a lexer language. 1580 Private method to handle the selection of a lexer language.
1595 1581
1596 @param act reference to the action that was triggered (QAction) 1582 @param act reference to the action that was triggered
1583 @type QAction
1597 """ 1584 """
1598 if act == self.noLanguageAct: 1585 if act == self.noLanguageAct:
1599 self.__resetLanguage() 1586 self.__resetLanguage()
1600 elif act == self.pygmentsAct: 1587 elif act == self.pygmentsAct:
1601 self.setLanguage("dummy.pygments") 1588 self.setLanguage("dummy.pygments")
1614 1601
1615 def __languageChanged(self, language, propagate=True): 1602 def __languageChanged(self, language, propagate=True):
1616 """ 1603 """
1617 Private method handling a change of a connected editor's language. 1604 Private method handling a change of a connected editor's language.
1618 1605
1619 @param language language to be set (string) 1606 @param language language to be set
1620 @param propagate flag indicating to propagate the change (boolean) 1607 @type str
1608 @param propagate flag indicating to propagate the change
1609 @type bool
1621 """ 1610 """
1622 if language == "": 1611 if language == "":
1623 self.__resetLanguage(propagate=propagate) 1612 self.__resetLanguage(propagate=propagate)
1624 elif language == "Guessed": 1613 elif language == "Guessed":
1625 self.setLanguage("dummy.pygments", propagate=propagate) 1614 self.setLanguage("dummy.pygments", propagate=propagate)
1635 1624
1636 def __resetLanguage(self, propagate=True): 1625 def __resetLanguage(self, propagate=True):
1637 """ 1626 """
1638 Private method used to reset the language selection. 1627 Private method used to reset the language selection.
1639 1628
1640 @param propagate flag indicating to propagate the change (boolean) 1629 @param propagate flag indicating to propagate the change
1630 @type bool
1641 """ 1631 """
1642 if self.lexer_ is not None and ( 1632 if self.lexer_ is not None and (
1643 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None 1633 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None
1644 ): 1634 ):
1645 with contextlib.suppress(TypeError): 1635 with contextlib.suppress(TypeError):
1669 def setLanguage(self, filename, initTextDisplay=True, propagate=True, pyname=""): 1659 def setLanguage(self, filename, initTextDisplay=True, propagate=True, pyname=""):
1670 """ 1660 """
1671 Public method to set a lexer language. 1661 Public method to set a lexer language.
1672 1662
1673 @param filename filename used to determine the associated lexer 1663 @param filename filename used to determine the associated lexer
1674 language (string) 1664 language
1665 @type str
1675 @param initTextDisplay flag indicating an initialization of the text 1666 @param initTextDisplay flag indicating an initialization of the text
1676 display is required as well (boolean) 1667 display is required as well
1677 @param propagate flag indicating to propagate the change (boolean) 1668 @type bool
1678 @param pyname name of the pygments lexer to use (string) 1669 @param propagate flag indicating to propagate the change
1670 @type bool
1671 @param pyname name of the pygments lexer to use
1672 @type str
1679 """ 1673 """
1680 # clear all warning and syntax error markers 1674 # clear all warning and syntax error markers
1681 self.clearSyntaxError() 1675 self.clearSyntaxError()
1682 self.clearWarnings() 1676 self.clearWarnings()
1683 1677
1736 1730
1737 def __encodingsMenuTriggered(self, act): 1731 def __encodingsMenuTriggered(self, act):
1738 """ 1732 """
1739 Private method to handle the selection of an encoding. 1733 Private method to handle the selection of an encoding.
1740 1734
1741 @param act reference to the action that was triggered (QAction) 1735 @param act reference to the action that was triggered
1736 @type QAction
1742 """ 1737 """
1743 encoding = act.data() 1738 encoding = act.data()
1744 self.setModified(True) 1739 self.setModified(True)
1745 self.__encodingChanged("{0}-selected".format(encoding)) 1740 self.__encodingChanged("{0}-selected".format(encoding))
1746 1741
1771 1766
1772 def __normalizedEncoding(self, encoding=""): 1767 def __normalizedEncoding(self, encoding=""):
1773 """ 1768 """
1774 Private method to calculate the normalized encoding string. 1769 Private method to calculate the normalized encoding string.
1775 1770
1776 @param encoding encoding to be normalized (string) 1771 @param encoding encoding to be normalized
1777 @return normalized encoding (string) 1772 @type str
1773 @return normalized encoding
1774 @rtype str
1778 """ 1775 """
1779 if not encoding: 1776 if not encoding:
1780 encoding = self.encoding 1777 encoding = self.encoding
1781 return ( 1778 return (
1782 encoding.replace("-default", "") 1779 encoding.replace("-default", "")
1793 1790
1794 def __eolMenuTriggered(self, act): 1791 def __eolMenuTriggered(self, act):
1795 """ 1792 """
1796 Private method to handle the selection of an eol type. 1793 Private method to handle the selection of an eol type.
1797 1794
1798 @param act reference to the action that was triggered (QAction) 1795 @param act reference to the action that was triggered
1796 @type QAction
1799 """ 1797 """
1800 eol = act.data() 1798 eol = act.data()
1801 self.setEolModeByEolString(eol) 1799 self.setEolModeByEolString(eol)
1802 self.convertEols(self.eolMode()) 1800 self.convertEols(self.eolMode())
1803 1801
1818 if not self.inEolChanged: 1816 if not self.inEolChanged:
1819 self.inEolChanged = True 1817 self.inEolChanged = True
1820 eol = self.getLineSeparator() 1818 eol = self.getLineSeparator()
1821 self.eolChanged.emit(eol) 1819 self.eolChanged.emit(eol)
1822 self.inEolChanged = False 1820 self.inEolChanged = False
1821
1822 def convertEols(self, eolMode):
1823 """
1824 Public method to convert the end-of-line marker.
1825
1826 This variant of the method emits a signal to update the IDE after
1827 the original method was called.
1828
1829 @param eolMode end-of-line mode
1830 @type QsciScintilla.EolMode
1831 """
1832 super().convertEols(eolMode)
1833 self.__eolChanged()
1823 1834
1824 @pyqtSlot() 1835 @pyqtSlot()
1825 def __showContextMenuSpellCheck(self): 1836 def __showContextMenuSpellCheck(self):
1826 """ 1837 """
1827 Private slot handling the aboutToShow signal of the spell check 1838 Private slot handling the aboutToShow signal of the spell check
2017 2028
2018 def getLexer(self): 2029 def getLexer(self):
2019 """ 2030 """
2020 Public method to retrieve a reference to the lexer object. 2031 Public method to retrieve a reference to the lexer object.
2021 2032
2022 @return the lexer object (Lexer) 2033 @return the lexer object
2034 @rtype Lexer
2023 """ 2035 """
2024 return self.lexer_ 2036 return self.lexer_
2025 2037
2026 def getLanguage(self, normalized=True, forPygments=False): 2038 def getLanguage(self, normalized=True, forPygments=False):
2027 """ 2039 """
2028 Public method to retrieve the language of the editor. 2040 Public method to retrieve the language of the editor.
2029 2041
2030 @param normalized flag indicating to normalize some Pygments 2042 @param normalized flag indicating to normalize some Pygments
2031 lexer names (boolean) 2043 lexer names
2044 @type bool
2032 @param forPygments flag indicating to normalize some lexer 2045 @param forPygments flag indicating to normalize some lexer
2033 names for Pygments (boolean) 2046 names for Pygments
2034 @return language of the editor (string) 2047 @type bool
2048 @return language of the editor
2049 @rtype str
2035 """ 2050 """
2036 if self.apiLanguage == "Guessed" or self.apiLanguage.startswith("Pygments|"): 2051 if self.apiLanguage == "Guessed" or self.apiLanguage.startswith("Pygments|"):
2037 lang = self.lexer_.name() 2052 lang = self.lexer_.name()
2038 if normalized and lang in ("Python 2.x", "Python"): 2053 if normalized and lang in ("Python 2.x", "Python"):
2039 # adjust some Pygments lexer names 2054 # adjust some Pygments lexer names
2080 2095
2081 def getCompleter(self): 2096 def getCompleter(self):
2082 """ 2097 """
2083 Public method to retrieve a reference to the completer object. 2098 Public method to retrieve a reference to the completer object.
2084 2099
2085 @return the completer object (CompleterBase) 2100 @return the completer object
2101 @rtype CompleterBase
2086 """ 2102 """
2087 return self.completer 2103 return self.completer
2088 2104
2089 @pyqtSlot(bool) 2105 @pyqtSlot(bool)
2090 def __modificationChanged(self, m): 2106 def __modificationChanged(self, m):
2160 2176
2161 def setNoName(self, noName): 2177 def setNoName(self, noName):
2162 """ 2178 """
2163 Public method to set the display string for an unnamed editor. 2179 Public method to set the display string for an unnamed editor.
2164 2180
2165 @param noName display string for this unnamed editor (string) 2181 @param noName display string for this unnamed editor
2182 @type str
2166 """ 2183 """
2167 self.noName = noName 2184 self.noName = noName
2168 2185
2169 def getNoName(self): 2186 def getNoName(self):
2170 """ 2187 """
2171 Public method to get the display string for an unnamed editor. 2188 Public method to get the display string for an unnamed editor.
2172 2189
2173 @return display string for this unnamed editor (string) 2190 @return display string for this unnamed editor
2191 @rtype str
2174 """ 2192 """
2175 return self.noName 2193 return self.noName
2176 2194
2177 def getFileName(self): 2195 def getFileName(self):
2178 """ 2196 """
2179 Public method to return the name of the file being displayed. 2197 Public method to return the name of the file being displayed.
2180 2198
2181 @return filename of the displayed file (string) 2199 @return filename of the displayed file
2200 @rtype str
2182 """ 2201 """
2183 return self.fileName 2202 return self.fileName
2184 2203
2185 def getFileType(self): 2204 def getFileType(self):
2186 """ 2205 """
2187 Public method to return the type of the file being displayed. 2206 Public method to return the type of the file being displayed.
2188 2207
2189 @return type of the displayed file (string) 2208 @return type of the displayed file
2209 @rtype str
2190 """ 2210 """
2191 return self.filetype 2211 return self.filetype
2192 2212
2193 def getFileTypeByFlag(self): 2213 def getFileTypeByFlag(self):
2194 """ 2214 """
2195 Public method to return the type of the file, if it was set by an 2215 Public method to return the type of the file, if it was set by an
2196 eflag: marker. 2216 eflag: marker.
2197 2217
2198 @return type of the displayed file, if set by an eflag: marker or an 2218 @return type of the displayed file, if set by an eflag: marker or an
2199 empty string (string) 2219 empty string
2220 @rtype str
2200 """ 2221 """
2201 if self.filetypeByFlag: 2222 if self.filetypeByFlag:
2202 return self.filetype 2223 return self.filetype
2203 else: 2224 else:
2204 return "" 2225 return ""
2205 2226
2206 def determineFileType(self): 2227 def determineFileType(self):
2207 """ 2228 """
2208 Public method to determine the file type using various tests. 2229 Public method to determine the file type using various tests.
2209 2230
2210 @return type of the displayed file or an empty string (string) 2231 @return type of the displayed file or an empty string
2232 @rtype str
2211 """ 2233 """
2212 ftype = self.filetype 2234 ftype = self.filetype
2213 if not ftype: 2235 if not ftype:
2214 pyVer = self.__getPyVersion() 2236 pyVer = self.__getPyVersion()
2215 if pyVer: 2237 if pyVer:
2223 2245
2224 def getEncoding(self): 2246 def getEncoding(self):
2225 """ 2247 """
2226 Public method to return the current encoding. 2248 Public method to return the current encoding.
2227 2249
2228 @return current encoding (string) 2250 @return current encoding
2251 @rtype str
2229 """ 2252 """
2230 return self.encoding 2253 return self.encoding
2231 2254
2232 def __getPyVersion(self): 2255 def __getPyVersion(self):
2233 """ 2256 """
2234 Private method to return the Python main version or 0 if it's 2257 Private method to return the Python main version or 0 if it's
2235 not a Python file at all. 2258 not a Python file at all.
2236 2259
2237 @return Python version or 0 if it's not a Python file (int) 2260 @return Python version or 0 if it's not a Python file
2261 @rtype int
2238 """ 2262 """
2239 return PythonUtilities.determinePythonVersion(self.fileName, self.text(0), self) 2263 return PythonUtilities.determinePythonVersion(self.fileName, self.text(0), self)
2240 2264
2241 def isPyFile(self): 2265 def isPyFile(self):
2242 """ 2266 """
2243 Public method to return a flag indicating a Python (2 or 3) file. 2267 Public method to return a flag indicating a Python (2 or 3) file.
2244 2268
2245 @return flag indicating a Python3 file (boolean) 2269 @return flag indicating a Python3 file
2270 @rtype bool
2246 """ 2271 """
2247 return self.__getPyVersion() == 3 2272 return self.__getPyVersion() == 3
2248 2273
2249 def isPy3File(self): 2274 def isPy3File(self):
2250 """ 2275 """
2251 Public method to return a flag indicating a Python3 file. 2276 Public method to return a flag indicating a Python3 file.
2252 2277
2253 @return flag indicating a Python3 file (boolean) 2278 @return flag indicating a Python3 file
2279 @rtype bool
2254 """ 2280 """
2255 return self.__getPyVersion() == 3 2281 return self.__getPyVersion() == 3
2256 2282
2257 def isMicroPythonFile(self): 2283 def isMicroPythonFile(self):
2258 """ 2284 """
2280 2306
2281 def isRubyFile(self): 2307 def isRubyFile(self):
2282 """ 2308 """
2283 Public method to return a flag indicating a Ruby file. 2309 Public method to return a flag indicating a Ruby file.
2284 2310
2285 @return flag indicating a Ruby file (boolean) 2311 @return flag indicating a Ruby file
2312 @rtype bool
2286 """ 2313 """
2287 if self.filetype == "Ruby": 2314 if self.filetype == "Ruby":
2288 return True 2315 return True
2289 2316
2290 if self.filetype == "": 2317 if self.filetype == "":
2303 2330
2304 def isJavascriptFile(self): 2331 def isJavascriptFile(self):
2305 """ 2332 """
2306 Public method to return a flag indicating a Javascript file. 2333 Public method to return a flag indicating a Javascript file.
2307 2334
2308 @return flag indicating a Javascript file (boolean) 2335 @return flag indicating a Javascript file
2336 @rtype bool
2309 """ 2337 """
2310 if self.filetype == "JavaScript": 2338 if self.filetype == "JavaScript":
2311 return True 2339 return True
2312 2340
2313 if ( 2341 if (
2344 2372
2345 def highlight(self, line=None, error=False, syntaxError=False): # noqa: U100 2373 def highlight(self, line=None, error=False, syntaxError=False): # noqa: U100
2346 """ 2374 """
2347 Public method to highlight [or de-highlight] a particular line. 2375 Public method to highlight [or de-highlight] a particular line.
2348 2376
2349 @param line line number to highlight (integer) 2377 @param line line number to highlight
2378 @type int
2350 @param error flag indicating whether the error highlight should be 2379 @param error flag indicating whether the error highlight should be
2351 used (boolean) 2380 used
2352 @param syntaxError flag indicating a syntax error (boolean) 2381 @type bool
2382 @param syntaxError flag indicating a syntax error
2383 @type bool
2353 """ 2384 """
2354 if line is None: 2385 if line is None:
2355 self.lastHighlight = None 2386 self.lastHighlight = None
2356 if self.lastErrorMarker is not None: 2387 if self.lastErrorMarker is not None:
2357 self.markerDeleteHandle(self.lastErrorMarker) 2388 self.markerDeleteHandle(self.lastErrorMarker)
2374 2405
2375 def getHighlightPosition(self): 2406 def getHighlightPosition(self):
2376 """ 2407 """
2377 Public method to return the position of the highlight bar. 2408 Public method to return the position of the highlight bar.
2378 2409
2379 @return line number of the highlight bar (integer) 2410 @return line number of the highlight bar
2411 @rtype int
2380 """ 2412 """
2381 if self.lastHighlight is not None: 2413 if self.lastHighlight is not None:
2382 return self.markerLine(self.lastHighlight) 2414 return self.markerLine(self.lastHighlight)
2383 else: 2415 else:
2384 return 1 2416 return 1
2401 annotationLinesAdded, # noqa: U100 2433 annotationLinesAdded, # noqa: U100
2402 ): 2434 ):
2403 """ 2435 """
2404 Private method to handle changes of the number of lines. 2436 Private method to handle changes of the number of lines.
2405 2437
2406 @param pos start position of change (integer) 2438 @param pos start position of change
2407 @param mtype flags identifying the change (integer) 2439 @type int
2408 @param text text that is given to the Undo system (string) 2440 @param mtype flags identifying the change
2409 @param length length of the change (integer) 2441 @type int
2410 @param linesAdded number of added/deleted lines (integer) 2442 @param text text that is given to the Undo system
2411 @param line line number of a fold level or marker change (integer) 2443 @type str
2412 @param foldNow new fold level (integer) 2444 @param length length of the change
2413 @param foldPrev previous fold level (integer) 2445 @type int
2446 @param linesAdded number of added/deleted lines
2447 @type int
2448 @param line line number of a fold level or marker change
2449 @type int
2450 @param foldNow new fold level
2451 @type int
2452 @param foldPrev previous fold level
2453 @type int
2414 @param token ??? 2454 @param token ???
2455 @type int
2415 @param annotationLinesAdded number of added/deleted annotation lines 2456 @param annotationLinesAdded number of added/deleted annotation lines
2416 (integer) 2457 @type int
2417 """ 2458 """
2418 if mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT): 2459 if mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT):
2419 # 1. set/reset the autosave timer 2460 # 1. set/reset the autosave timer
2420 if self.__autosaveInterval > 0: 2461 if self.__autosaveInterval > 0:
2421 self.__autosaveTimer.start(self.__autosaveInterval * 1000) 2462 self.__autosaveTimer.start(self.__autosaveInterval * 1000)
2526 Public method to clear a breakpoint. 2567 Public method to clear a breakpoint.
2527 2568
2528 Note: This doesn't clear the breakpoint in the debugger, 2569 Note: This doesn't clear the breakpoint in the debugger,
2529 it just deletes it from the editor internal list of breakpoints. 2570 it just deletes it from the editor internal list of breakpoints.
2530 2571
2531 @param line line number of the breakpoint (integer) 2572 @param line line number of the breakpoint
2573 @type int
2532 """ 2574 """
2533 if self.inLinesChanged: 2575 if self.inLinesChanged:
2534 return 2576 return
2535 2577
2536 for handle in self.breaks: 2578 for handle in self.breaks:
2542 2584
2543 def newBreakpointWithProperties(self, line, properties): 2585 def newBreakpointWithProperties(self, line, properties):
2544 """ 2586 """
2545 Public method to set a new breakpoint and its properties. 2587 Public method to set a new breakpoint and its properties.
2546 2588
2547 @param line line number of the breakpoint (integer) 2589 @param line line number of the breakpoint
2548 @param properties properties for the breakpoint (tuple) 2590 @type int
2591 @param properties properties for the breakpoint
2549 (condition, temporary flag, enabled flag, ignore count) 2592 (condition, temporary flag, enabled flag, ignore count)
2593 @type tuple of (str, bool, bool, int)
2550 """ 2594 """
2551 if not properties[2]: 2595 if not properties[2]:
2552 marker = self.dbreakpoint 2596 marker = self.dbreakpoint
2553 elif properties[0]: 2597 elif properties[0]:
2554 marker = properties[1] and self.tcbreakpoint or self.cbreakpoint 2598 marker = properties[1] and self.tcbreakpoint or self.cbreakpoint
2563 2607
2564 def __toggleBreakpoint(self, line, temporary=False): 2608 def __toggleBreakpoint(self, line, temporary=False):
2565 """ 2609 """
2566 Private method to toggle a breakpoint. 2610 Private method to toggle a breakpoint.
2567 2611
2568 @param line line number of the breakpoint (integer) 2612 @param line line number of the breakpoint
2569 @param temporary flag indicating a temporary breakpoint (boolean) 2613 @type int
2614 @param temporary flag indicating a temporary breakpoint
2615 @type bool
2570 """ 2616 """
2571 for handle in self.breaks: 2617 for handle in self.breaks:
2572 if self.markerLine(handle) == line - 1: 2618 if self.markerLine(handle) == line - 1:
2573 # delete breakpoint or toggle it to the next state 2619 # delete breakpoint or toggle it to the next state
2574 index = self.breakpointModel.getBreakPointIndex(self.fileName, line) 2620 index = self.breakpointModel.getBreakPointIndex(self.fileName, line)
2586 2632
2587 def __addBreakPoint(self, line, temporary): 2633 def __addBreakPoint(self, line, temporary):
2588 """ 2634 """
2589 Private method to add a new breakpoint. 2635 Private method to add a new breakpoint.
2590 2636
2591 @param line line number of the breakpoint (integer) 2637 @param line line number of the breakpoint
2592 @param temporary flag indicating a temporary breakpoint (boolean) 2638 @type int
2639 @param temporary flag indicating a temporary breakpoint
2640 @type bool
2593 """ 2641 """
2594 if self.fileName and self.isPyFile(): 2642 if self.fileName and self.isPyFile():
2595 linestarts = PythonDisViewer.linestarts(self.text()) 2643 linestarts = PythonDisViewer.linestarts(self.text())
2596 if line not in linestarts: 2644 if line not in linestarts:
2597 if Preferences.getDebugger("IntelligentBreakpoints"): 2645 if Preferences.getDebugger("IntelligentBreakpoints"):
2618 2666
2619 def __toggleBreakpointEnabled(self, line): 2667 def __toggleBreakpointEnabled(self, line):
2620 """ 2668 """
2621 Private method to toggle a breakpoints enabled status. 2669 Private method to toggle a breakpoints enabled status.
2622 2670
2623 @param line line number of the breakpoint (integer) 2671 @param line line number of the breakpoint
2672 @type int
2624 """ 2673 """
2625 for handle in self.breaks: 2674 for handle in self.breaks:
2626 if self.markerLine(handle) == line - 1: 2675 if self.markerLine(handle) == line - 1:
2627 index = self.breakpointModel.getBreakPointIndex(self.fileName, line) 2676 index = self.breakpointModel.getBreakPointIndex(self.fileName, line)
2628 self.breakpointModel.setBreakPointEnabledByIndex( 2677 self.breakpointModel.setBreakPointEnabledByIndex(
2633 def curLineHasBreakpoint(self): 2682 def curLineHasBreakpoint(self):
2634 """ 2683 """
2635 Public method to check for the presence of a breakpoint at the current 2684 Public method to check for the presence of a breakpoint at the current
2636 line. 2685 line.
2637 2686
2638 @return flag indicating the presence of a breakpoint (boolean) 2687 @return flag indicating the presence of a breakpoint
2688 @rtype bool
2639 """ 2689 """
2640 line, _ = self.getCursorPosition() 2690 line, _ = self.getCursorPosition()
2641 return self.markersAtLine(line) & self.breakpointMask != 0 2691 return self.markersAtLine(line) & self.breakpointMask != 0
2642 2692
2643 def getBreakpointLines(self): 2693 def getBreakpointLines(self):
2644 """ 2694 """
2645 Public method to get the lines containing a breakpoint. 2695 Public method to get the lines containing a breakpoint.
2646 2696
2647 @return list of lines containing a breakpoint (list of integer) 2697 @return list of lines containing a breakpoint
2698 @rtype list of int
2648 """ 2699 """
2649 lines = [] 2700 lines = []
2650 line = -1 2701 line = -1
2651 while True: 2702 while True:
2652 line = self.markerFindNext(line + 1, self.breakpointMask) 2703 line = self.markerFindNext(line + 1, self.breakpointMask)
2658 2709
2659 def hasBreakpoints(self): 2710 def hasBreakpoints(self):
2660 """ 2711 """
2661 Public method to check for the presence of breakpoints. 2712 Public method to check for the presence of breakpoints.
2662 2713
2663 @return flag indicating the presence of breakpoints (boolean) 2714 @return flag indicating the presence of breakpoints
2715 @rtype bool
2664 """ 2716 """
2665 return len(self.breaks) > 0 2717 return len(self.breaks) > 0
2666 2718
2667 @pyqtSlot() 2719 @pyqtSlot()
2668 def __menuToggleTemporaryBreakpoint(self): 2720 def __menuToggleTemporaryBreakpoint(self):
2820 2872
2821 def toggleBookmark(self, line): 2873 def toggleBookmark(self, line):
2822 """ 2874 """
2823 Public method to toggle a bookmark. 2875 Public method to toggle a bookmark.
2824 2876
2825 @param line line number of the bookmark (integer) 2877 @param line line number of the bookmark
2878 @type int
2826 """ 2879 """
2827 for handle in self.bookmarks: 2880 for handle in self.bookmarks:
2828 if self.markerLine(handle) == line - 1: 2881 if self.markerLine(handle) == line - 1:
2829 self.bookmarks.remove(handle) 2882 self.bookmarks.remove(handle)
2830 self.markerDeleteHandle(handle) 2883 self.markerDeleteHandle(handle)
2839 def getBookmarks(self): 2892 def getBookmarks(self):
2840 """ 2893 """
2841 Public method to retrieve the bookmarks. 2894 Public method to retrieve the bookmarks.
2842 2895
2843 @return sorted list of all lines containing a bookmark 2896 @return sorted list of all lines containing a bookmark
2844 (list of integer) 2897 @rtype list of int
2845 """ 2898 """
2846 bmlist = [] 2899 bmlist = []
2847 for handle in self.bookmarks: 2900 for handle in self.bookmarks:
2848 bmlist.append(self.markerLine(handle) + 1) 2901 bmlist.append(self.markerLine(handle) + 1)
2849 2902
2852 2905
2853 def getBookmarkLines(self): 2906 def getBookmarkLines(self):
2854 """ 2907 """
2855 Public method to get the lines containing a bookmark. 2908 Public method to get the lines containing a bookmark.
2856 2909
2857 @return list of lines containing a bookmark (list of integer) 2910 @return list of lines containing a bookmark
2911 @rtype list of int
2858 """ 2912 """
2859 lines = [] 2913 lines = []
2860 line = -1 2914 line = -1
2861 while True: 2915 while True:
2862 line = self.markerFindNext(line + 1, 1 << self.bookmark) 2916 line = self.markerFindNext(line + 1, 1 << self.bookmark)
2868 2922
2869 def hasBookmarks(self): 2923 def hasBookmarks(self):
2870 """ 2924 """
2871 Public method to check for the presence of bookmarks. 2925 Public method to check for the presence of bookmarks.
2872 2926
2873 @return flag indicating the presence of bookmarks (boolean) 2927 @return flag indicating the presence of bookmarks
2928 @rtype bool
2874 """ 2929 """
2875 return len(self.bookmarks) > 0 2930 return len(self.bookmarks) > 0
2876 2931
2877 @pyqtSlot() 2932 @pyqtSlot()
2878 def menuToggleBookmark(self): 2933 def menuToggleBookmark(self):
2996 def __printPreview(self, printer): 3051 def __printPreview(self, printer):
2997 """ 3052 """
2998 Private slot to generate a print preview. 3053 Private slot to generate a print preview.
2999 3054
3000 @param printer reference to the printer object 3055 @param printer reference to the printer object
3001 (QScintilla.Printer.Printer) 3056 @type QScintilla.Printer.Printer
3002 """ 3057 """
3003 printer.printRange(self) 3058 printer.printRange(self)
3004 3059
3005 ########################################################################### 3060 ###########################################################################
3006 ## Task handling methods below 3061 ## Task handling methods below
3008 3063
3009 def getTaskLines(self): 3064 def getTaskLines(self):
3010 """ 3065 """
3011 Public method to get the lines containing a task. 3066 Public method to get the lines containing a task.
3012 3067
3013 @return list of lines containing a task (list of integer) 3068 @return list of lines containing a task
3069 @rtype list of int
3014 """ 3070 """
3015 lines = [] 3071 lines = []
3016 line = -1 3072 line = -1
3017 while True: 3073 while True:
3018 line = self.markerFindNext(line + 1, 1 << self.taskmarker) 3074 line = self.markerFindNext(line + 1, 1 << self.taskmarker)
3024 3080
3025 def hasTaskMarkers(self): 3081 def hasTaskMarkers(self):
3026 """ 3082 """
3027 Public method to determine, if this editor contains any task markers. 3083 Public method to determine, if this editor contains any task markers.
3028 3084
3029 @return flag indicating the presence of task markers (boolean) 3085 @return flag indicating the presence of task markers
3086 @rtype bool
3030 """ 3087 """
3031 return self.__hasTaskMarkers 3088 return self.__hasTaskMarkers
3032 3089
3033 @pyqtSlot() 3090 @pyqtSlot()
3034 def nextTask(self): 3091 def nextTask(self):
3115 3172
3116 def __createChangeMarkerPixmap(self, key, size=16): 3173 def __createChangeMarkerPixmap(self, key, size=16):
3117 """ 3174 """
3118 Private method to create a pixmap for the change markers. 3175 Private method to create a pixmap for the change markers.
3119 3176
3120 @param key key of the color to use (string) 3177 @param key key of the color to use
3121 @param size size of the pixmap (integer) 3178 @type str
3122 @return create pixmap (QPixmap) 3179 @param size size of the pixmap
3180 @type int
3181 @return create pixmap
3182 @rtype QPixmap
3123 """ 3183 """
3124 pixmap = QPixmap(size, size) 3184 pixmap = QPixmap(size, size)
3125 pixmap.fill(Qt.GlobalColor.transparent) 3185 pixmap.fill(Qt.GlobalColor.transparent)
3126 painter = QPainter(pixmap) 3186 painter = QPainter(pixmap)
3127 painter.fillRect(size - 4, 0, 4, size, Preferences.getEditorColour(key)) 3187 painter.fillRect(size - 4, 0, 4, size, Preferences.getEditorColour(key))
3238 3298
3239 def getChangeLines(self): 3299 def getChangeLines(self):
3240 """ 3300 """
3241 Public method to get the lines containing a change. 3301 Public method to get the lines containing a change.
3242 3302
3243 @return list of lines containing a change (list of integer) 3303 @return list of lines containing a change
3304 @rtype list of int
3244 """ 3305 """
3245 lines = [] 3306 lines = []
3246 line = -1 3307 line = -1
3247 while True: 3308 while True:
3248 line = self.markerFindNext(line + 1, self.changeMarkersMask) 3309 line = self.markerFindNext(line + 1, self.changeMarkersMask)
3254 3315
3255 def hasChangeMarkers(self): 3316 def hasChangeMarkers(self):
3256 """ 3317 """
3257 Public method to determine, if this editor contains any change markers. 3318 Public method to determine, if this editor contains any change markers.
3258 3319
3259 @return flag indicating the presence of change markers (boolean) 3320 @return flag indicating the presence of change markers
3321 @rtype bool
3260 """ 3322 """
3261 return self.__hasChangeMarkers 3323 return self.__hasChangeMarkers
3262 3324
3263 @pyqtSlot() 3325 @pyqtSlot()
3264 def nextChange(self): 3326 def nextChange(self):
3304 3366
3305 def __processFlags(self): 3367 def __processFlags(self):
3306 """ 3368 """
3307 Private method to extract flags and process them. 3369 Private method to extract flags and process them.
3308 3370
3309 @return list of change flags (list of string) 3371 @return list of change flags
3372 @rtype list of str
3310 """ 3373 """
3311 txt = self.text() 3374 txt = self.text()
3312 flags = Utilities.extractFlags(txt) 3375 flags = Utilities.extractFlags(txt)
3313 3376
3314 changedFlags = [] 3377 changedFlags = []
3336 3399
3337 def checkDirty(self): 3400 def checkDirty(self):
3338 """ 3401 """
3339 Public method to check dirty status and open a message window. 3402 Public method to check dirty status and open a message window.
3340 3403
3341 @return flag indicating successful reset of the dirty flag (boolean) 3404 @return flag indicating successful reset of the dirty flag
3405 @rtype bool
3342 """ 3406 """
3343 if self.isModified(): 3407 if self.isModified():
3344 fn = self.fileName 3408 fn = self.fileName
3345 if fn is None: 3409 if fn is None:
3346 fn = self.noName 3410 fn = self.noName
3347 res = EricMessageBox.okToClearData( 3411 res = EricMessageBox.okToClearData(
3348 self, 3412 self,
3349 self.tr("File Modified"), 3413 self.tr("File Modified"),
3350 self.tr("<p>The file <b>{0}</b> has unsaved changes.</p>").format(fn), 3414 self.tr("<p>The file <b>{0}</b> has unsaved changes.</p>").format(fn),
3351 self.saveFile if not self.isRemoteFile() else None, 3415 self.saveFile
3416 if not FileSystemUtilities.isRemoteFileName(self.fileName)
3417 else None,
3352 ) 3418 )
3353 if res: 3419 if res:
3354 self.vm.setEditorName(self, self.fileName) 3420 self.vm.setEditorName(self, self.fileName)
3355 return res 3421 return res
3356 3422
3374 self.redo() 3440 self.redo()
3375 else: 3441 else:
3376 break 3442 break
3377 # Couldn't find the unmodified state 3443 # Couldn't find the unmodified state
3378 3444
3379 def readFile(self, fn, createIt=False, encoding=""): 3445 def readFile(self, fn, createIt=False, encoding="", noempty=False):
3380 """ 3446 """
3381 Public method to read the text from a file. 3447 Public method to read the text from a file.
3382 3448
3383 @param fn filename to read from (string) 3449 @param fn filename to read from
3450 @type str
3384 @param createIt flag indicating the creation of a new file, if the 3451 @param createIt flag indicating the creation of a new file, if the
3385 given one doesn't exist (boolean) 3452 given one doesn't exist (defaults to False)
3386 @param encoding encoding to be used to read the file (string) 3453 @type bool (optional)
3454 @param encoding encoding to be used to read the file (defaults to "")
3387 (Note: this parameter overrides encoding detection) 3455 (Note: this parameter overrides encoding detection)
3456 @type str (optional)
3457 @param noempty flag indicating to not set an empty text (defaults to False)
3458 @type bool (optional)
3388 """ 3459 """
3389 self.__loadEditorConfig(fileName=fn) 3460 self.__loadEditorConfig(fileName=fn)
3390 3461
3391 try: 3462 try:
3392 with EricOverrideCursor(): 3463 with EricOverrideCursor():
3410 "<p>Reason: {1}</p>" 3481 "<p>Reason: {1}</p>"
3411 ).format(fn, str(why)), 3482 ).format(fn, str(why)),
3412 ) 3483 )
3413 raise 3484 raise
3414 3485
3486 if noempty and not bool(txt):
3487 return
3488
3415 with EricOverrideCursor(): 3489 with EricOverrideCursor():
3416 modified = False
3417
3418 self.setText(txt) 3490 self.setText(txt)
3491 self.setModified(False)
3419 3492
3420 # get eric specific flags 3493 # get eric specific flags
3421 self.__processFlags() 3494 self.__processFlags()
3422 3495
3423 # perform automatic EOL conversion 3496 # perform automatic EOL conversion
3426 ) or Preferences.getEditor("AutomaticEOLConversion"): 3499 ) or Preferences.getEditor("AutomaticEOLConversion"):
3427 self.convertEols(self.eolMode()) 3500 self.convertEols(self.eolMode())
3428 else: 3501 else:
3429 fileEol = self.detectEolString(txt) 3502 fileEol = self.detectEolString(txt)
3430 self.setEolModeByEolString(fileEol) 3503 self.setEolModeByEolString(fileEol)
3504 self.__eolChanged()
3431 3505
3432 self.extractTasks() 3506 self.extractTasks()
3433 3507
3434 self.setModified(modified)
3435 self.lastModified = pathlib.Path(fn).stat().st_mtime 3508 self.lastModified = pathlib.Path(fn).stat().st_mtime
3436 3509
3437 @pyqtSlot() 3510 @pyqtSlot()
3438 def __convertTabs(self): 3511 def __convertTabs(self):
3439 """ 3512 """
3537 3610
3538 def __getSaveFileName(self, path=None): 3611 def __getSaveFileName(self, path=None):
3539 """ 3612 """
3540 Private method to get the name of the file to be saved. 3613 Private method to get the name of the file to be saved.
3541 3614
3542 @param path directory to save the file in (string) 3615 @param path directory to save the file in
3543 @return file name (string) 3616 @type str
3617 @return file name
3618 @rtype str
3544 """ 3619 """
3545 # save to project, if a project is loaded 3620 # save to project, if a project is loaded
3546 if self.project.isOpen(): 3621 if self.project.isOpen():
3547 if self.fileName and self.project.startswithProjectPath(self.fileName): 3622 if self.fileName and self.project.startswithProjectPath(self.fileName):
3548 path = os.path.dirname(self.fileName) 3623 path = os.path.dirname(self.fileName)
3600 3675
3601 def saveFileCopy(self, path=None): 3676 def saveFileCopy(self, path=None):
3602 """ 3677 """
3603 Public method to save a copy of the file. 3678 Public method to save a copy of the file.
3604 3679
3605 @param path directory to save the file in (string) 3680 @param path directory to save the file in
3606 @return flag indicating success (boolean) 3681 @type str
3682 @return flag indicating success
3683 @rtype bool
3607 """ 3684 """
3608 fn = self.__getSaveFileName(path) 3685 fn = self.__getSaveFileName(path)
3609 if not fn: 3686 if not fn:
3610 return False 3687 return False
3611 3688
3618 3695
3619 def saveFile(self, saveas=False, path=None): 3696 def saveFile(self, saveas=False, path=None):
3620 """ 3697 """
3621 Public method to save the text to a file. 3698 Public method to save the text to a file.
3622 3699
3623 @param saveas flag indicating a 'save as' action (boolean) 3700 @param saveas flag indicating a 'save as' action
3624 @param path directory to save the file in (string) 3701 @type bool
3625 @return flag indicating success (boolean) 3702 @param path directory to save the file in
3626 """ 3703 @type str
3627 if not saveas and (not self.isModified() or self.isRemoteFile()): 3704 @return flag indicating success
3705 @rtype bool
3706 """
3707 if not saveas and (
3708 not self.isModified() or FileSystemUtilities.isRemoteFileName(self.fileName)
3709 ):
3628 # do nothing if text wasn't changed or is a remote file 3710 # do nothing if text wasn't changed or is a remote file
3629 return False 3711 return False
3630 3712
3631 if self.isDeviceFile(): 3713 if FileSystemUtilities.isDeviceFileName(self.fileName):
3632 return self.__saveDeviceFile(saveas=saveas) 3714 return self.__saveDeviceFile(saveas=saveas)
3633 3715
3634 newName = None 3716 newName = None
3635 if saveas or self.fileName == "": 3717 if saveas or self.fileName == "":
3636 saveas = True 3718 saveas = True
3736 # Convert the file name to device path separators ('/') and ensure, 3818 # Convert the file name to device path separators ('/') and ensure,
3737 # intermediate directories exist (creating them if necessary) 3819 # intermediate directories exist (creating them if necessary)
3738 fn = fn.replace("\\", "/") 3820 fn = fn.replace("\\", "/")
3739 if "/" in fn: 3821 if "/" in fn:
3740 dn = fn.rsplit("/", 1)[0] 3822 dn = fn.rsplit("/", 1)[0]
3741 filemanager.makedirs(dn.replace("device:", "")) 3823 filemanager.makedirs(FileSystemUtilities.plainFileName(dn))
3742 success = filemanager.writeFile(fn.replace("device:", ""), self.text()) 3824 success = filemanager.writeFile(
3825 FileSystemUtilities.plainFileName(fn), self.text()
3826 )
3743 if success: 3827 if success:
3744 self.setFileName(fn) 3828 self.setFileName(fn)
3745 self.setModified(False) 3829 self.setModified(False)
3746 self.resetOnlineChangeTraceInfo() 3830 self.resetOnlineChangeTraceInfo()
3747 return success 3831 return success
3750 3834
3751 def handleRenamed(self, fn): 3835 def handleRenamed(self, fn):
3752 """ 3836 """
3753 Public method to handle the editorRenamed signal. 3837 Public method to handle the editorRenamed signal.
3754 3838
3755 @param fn filename to be set for the editor (string). 3839 @param fn filename to be set for the editor
3840 @type str
3756 """ 3841 """
3757 self.__clearBreakpoints(fn) 3842 self.__clearBreakpoints(fn)
3758 3843
3759 self.setFileName(fn) 3844 self.setFileName(fn)
3760 self.setWindowTitle(self.fileName) 3845 self.setWindowTitle(self.fileName)
3936 4021
3937 def getWordLeft(self, line, index): 4022 def getWordLeft(self, line, index):
3938 """ 4023 """
3939 Public method to get the word to the left of a position. 4024 Public method to get the word to the left of a position.
3940 4025
3941 @param line number of line to look at (int) 4026 @param line number of line to look at
3942 @param index position to look at (int) 4027 @type int
3943 @return the word to the left of that position (string) 4028 @param index position to look at
4029 @type int
4030 @return the word to the left of that position
4031 @rtype str
3944 """ 4032 """
3945 return self.getWord(line, index, 1) 4033 return self.getWord(line, index, 1)
3946 4034
3947 def getWordRight(self, line, index): 4035 def getWordRight(self, line, index):
3948 """ 4036 """
3949 Public method to get the word to the right of a position. 4037 Public method to get the word to the right of a position.
3950 4038
3951 @param line number of line to look at (int) 4039 @param line number of line to look at
3952 @param index position to look at (int) 4040 @type int
3953 @return the word to the right of that position (string) 4041 @param index position to look at
4042 @type int
4043 @return the word to the right of that position
4044 @rtype str
3954 """ 4045 """
3955 return self.getWord(line, index, 2) 4046 return self.getWord(line, index, 2)
3956 4047
3957 def getCurrentWord(self): 4048 def getCurrentWord(self):
3958 """ 4049 """
3959 Public method to get the word at the current position. 4050 Public method to get the word at the current position.
3960 4051
3961 @return the word at that current position (string) 4052 @return the word at that current position
4053 @rtype str
3962 """ 4054 """
3963 line, index = self.getCursorPosition() 4055 line, index = self.getCursorPosition()
3964 return self.getWord(line, index) 4056 return self.getWord(line, index)
3965 4057
3966 def getCurrentWordBoundaries(self): 4058 def getCurrentWordBoundaries(self):
3967 """ 4059 """
3968 Public method to get the word boundaries at the current position. 4060 Public method to get the word boundaries at the current position.
3969 4061
3970 @return tuple with start and end indexes of the current word 4062 @return tuple with start and end indexes of the current word
3971 (integer, integer) 4063 @rtype tuple of (int, int)
3972 """ 4064 """
3973 line, index = self.getCursorPosition() 4065 line, index = self.getCursorPosition()
3974 return self.getWordBoundaries(line, index) 4066 return self.getWordBoundaries(line, index)
3975 4067
3976 def selectWord(self, line, index): 4068 def selectWord(self, line, index):
3977 """ 4069 """
3978 Public method to select the word at a position. 4070 Public method to select the word at a position.
3979 4071
3980 @param line number of line to look at (int) 4072 @param line number of line to look at
3981 @param index position to look at (int) 4073 @type int
4074 @param index position to look at
4075 @type int
3982 """ 4076 """
3983 start, end = self.getWordBoundaries(line, index) 4077 start, end = self.getWordBoundaries(line, index)
3984 self.setSelection(line, start, line, end) 4078 self.setSelection(line, start, line, end)
3985 4079
3986 def selectCurrentWord(self): 4080 def selectCurrentWord(self):
3993 def __getCharacter(self, pos): 4087 def __getCharacter(self, pos):
3994 """ 4088 """
3995 Private method to get the character to the left of the current position 4089 Private method to get the character to the left of the current position
3996 in the current line. 4090 in the current line.
3997 4091
3998 @param pos position to get character at (integer) 4092 @param pos position to get character at
3999 @return requested character or "", if there are no more (string) and 4093 @type int
4000 the next position (i.e. pos - 1) 4094 @return requested character or "", if there are no more and the next position
4095 (i.e. pos - 1)
4096 @rtype tuple of (str, int)
4001 """ 4097 """
4002 if pos <= 0: 4098 if pos <= 0:
4003 return "", pos 4099 return "", pos
4004 4100
4005 pos = self.positionBefore(pos) 4101 pos = self.positionBefore(pos)
4015 """ 4111 """
4016 Public method to determine the selection or the current word for the 4112 Public method to determine the selection or the current word for the
4017 next search operation. 4113 next search operation.
4018 4114
4019 @param selectionOnly flag indicating that only selected text should be 4115 @param selectionOnly flag indicating that only selected text should be
4020 returned (boolean) 4116 returned
4021 @return selection or current word (string) 4117 @type bool
4118 @return selection or current word
4119 @rtype str
4022 """ 4120 """
4023 if self.hasSelectedText(): 4121 if self.hasSelectedText():
4024 text = self.selectedText() 4122 text = self.selectedText()
4025 if "\r" in text or "\n" in text: 4123 if "\r" in text or "\n" in text:
4026 # the selection contains at least a newline, it is 4124 # the selection contains at least a newline, it is
4037 4135
4038 def setSearchIndicator(self, startPos, indicLength): 4136 def setSearchIndicator(self, startPos, indicLength):
4039 """ 4137 """
4040 Public method to set a search indicator for the given range. 4138 Public method to set a search indicator for the given range.
4041 4139
4042 @param startPos start position of the indicator (integer) 4140 @param startPos start position of the indicator
4043 @param indicLength length of the indicator (integer) 4141 @type int
4142 @param indicLength length of the indicator
4143 @type int
4044 """ 4144 """
4045 self.setIndicatorRange(self.searchIndicator, startPos, indicLength) 4145 self.setIndicatorRange(self.searchIndicator, startPos, indicLength)
4046 line = self.lineIndexFromPosition(startPos)[0] 4146 line = self.lineIndexFromPosition(startPos)[0]
4047 if line not in self.__searchIndicatorLines: 4147 if line not in self.__searchIndicatorLines:
4048 self.__searchIndicatorLines.append(line) 4148 self.__searchIndicatorLines.append(line)
4111 4211
4112 def getSearchIndicatorLines(self): 4212 def getSearchIndicatorLines(self):
4113 """ 4213 """
4114 Public method to get the lines containing a search indicator. 4214 Public method to get the lines containing a search indicator.
4115 4215
4116 @return list of lines containing a search indicator (list of integer) 4216 @return list of lines containing a search indicator
4217 @rtype list of int
4117 """ 4218 """
4118 return self.__searchIndicatorLines[:] 4219 return self.__searchIndicatorLines[:]
4119 4220
4120 def updateMarkerMap(self): 4221 def updateMarkerMap(self):
4121 """ 4222 """
4174 def __isCommentedLine(self, line, commentStr): 4275 def __isCommentedLine(self, line, commentStr):
4175 """ 4276 """
4176 Private method to check, if the given line is a comment line as 4277 Private method to check, if the given line is a comment line as
4177 produced by the configured comment rules. 4278 produced by the configured comment rules.
4178 4279
4179 @param line text of the line to check (string) 4280 @param line text of the line to check
4180 @param commentStr comment string to check against (string) 4281 @type str
4181 @return flag indicating a commented line (boolean) 4282 @param commentStr comment string to check against
4283 @type str
4284 @return flag indicating a commented line
4285 @rtype bool
4182 """ 4286 """
4183 if Preferences.getEditor("CommentColumn0"): 4287 if Preferences.getEditor("CommentColumn0"):
4184 return line.startswith(commentStr) 4288 return line.startswith(commentStr)
4185 else: 4289 else:
4186 return line.strip().startswith(commentStr) 4290 return line.strip().startswith(commentStr)
4187 4291
4188 @pyqtSlot() 4292 @pyqtSlot()
4189 def toggleCommentBlock(self): 4293 def toggleComment(self):
4190 """ 4294 """
4191 Public slot to toggle the comment of a block. 4295 Public slot to toggle a block or stream comment.
4296
4297 If the lexer supports a block comment, that is used for toggling the
4298 comment. Otherwise a stream comment is used if that is supported. If
4299 none of these are supported, the request is ignored silently.
4300 """
4301 if self.lexer_ is not None:
4302 if self.lexer_.canBlockComment():
4303 self.__toggleBlockComment()
4304 elif self.lexer_.canStreamComment():
4305 self.__toggleStreamComment()
4306
4307 @pyqtSlot()
4308 def __toggleBlockComment(self):
4309 """
4310 Private slot to toggle the comment of a block.
4192 4311
4193 If the editor contains selected text and the start line is not commented, it 4312 If the editor contains selected text and the start line is not commented, it
4194 will be commented. Otherwise the selection will be un-commented. In case there 4313 will be commented. Otherwise the selection will be un-commented. In case there
4195 is no selected text and the current line is not commented, it will be commented. 4314 is no selected text and the current line is not commented, it will be commented.
4196 If is commented, the comment block will be removed. 4315 If is commented, the comment block will be removed.
4232 self.setSelection(begline, 0, endline, self.lineLength(endline)) 4351 self.setSelection(begline, 0, endline, self.lineLength(endline))
4233 self.uncommentLineOrSelection() 4352 self.uncommentLineOrSelection()
4234 self.setCursorPosition(line, index - len(commentStr)) 4353 self.setCursorPosition(line, index - len(commentStr))
4235 4354
4236 @pyqtSlot() 4355 @pyqtSlot()
4237 def commentLine(self): 4356 def __commentLine(self):
4238 """ 4357 """
4239 Public slot to comment the current line. 4358 Private slot to comment the current line.
4240 """ 4359 """
4241 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4360 if self.lexer_ is None or not self.lexer_.canBlockComment():
4242 return 4361 return
4243 4362
4244 line, index = self.getCursorPosition() 4363 line, index = self.getCursorPosition()
4250 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) 4369 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
4251 self.insertAt(self.lexer_.commentStr(), line, pos) 4370 self.insertAt(self.lexer_.commentStr(), line, pos)
4252 self.endUndoAction() 4371 self.endUndoAction()
4253 4372
4254 @pyqtSlot() 4373 @pyqtSlot()
4255 def uncommentLine(self): 4374 def __uncommentLine(self):
4256 """ 4375 """
4257 Public slot to uncomment the current line. 4376 Private slot to uncomment the current line.
4258 """ 4377 """
4259 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4378 if self.lexer_ is None or not self.lexer_.canBlockComment():
4260 return 4379 return
4261 4380
4262 commentStr = self.lexer_.commentStr() 4381 commentStr = self.lexer_.commentStr()
4277 self.setSelection(line, pos, line, pos + len(commentStr)) 4396 self.setSelection(line, pos, line, pos + len(commentStr))
4278 self.removeSelectedText() 4397 self.removeSelectedText()
4279 self.endUndoAction() 4398 self.endUndoAction()
4280 4399
4281 @pyqtSlot() 4400 @pyqtSlot()
4282 def commentSelection(self): 4401 def __commentSelection(self):
4283 """ 4402 """
4284 Public slot to comment the current selection. 4403 Private slot to comment the current selection.
4285 """ 4404 """
4286 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4405 if self.lexer_ is None or not self.lexer_.canBlockComment():
4287 return 4406 return
4288 4407
4289 if not self.hasSelectedText(): 4408 if not self.hasSelectedText():
4308 # change the selection accordingly 4427 # change the selection accordingly
4309 self.setSelection(lineFrom, 0, endLine + 1, 0) 4428 self.setSelection(lineFrom, 0, endLine + 1, 0)
4310 self.endUndoAction() 4429 self.endUndoAction()
4311 4430
4312 @pyqtSlot() 4431 @pyqtSlot()
4313 def uncommentSelection(self): 4432 def __uncommentSelection(self):
4314 """ 4433 """
4315 Public slot to uncomment the current selection. 4434 Private slot to uncomment the current selection.
4316 """ 4435 """
4317 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4436 if self.lexer_ is None or not self.lexer_.canBlockComment():
4318 return 4437 return
4319 4438
4320 if not self.hasSelectedText(): 4439 if not self.hasSelectedText():
4360 4479
4361 @pyqtSlot() 4480 @pyqtSlot()
4362 def commentLineOrSelection(self): 4481 def commentLineOrSelection(self):
4363 """ 4482 """
4364 Public slot to comment the current line or current selection. 4483 Public slot to comment the current line or current selection.
4365 """ 4484
4366 if self.hasSelectedText(): 4485 If the lexer supports a block comment, that is used for commenting.
4367 self.commentSelection() 4486 Otherwise a stream comment is used if that is supported. If none of
4368 else: 4487 these are supported, the request is ignored silently.
4369 self.commentLine() 4488 """
4489 if self.lexer_ is not None:
4490 if self.lexer_.canBlockComment():
4491 if self.hasSelectedText():
4492 self.__commentSelection()
4493 else:
4494 self.__commentLine()
4495 elif self.lexer_.canStreamComment():
4496 # delegate to the stream comment method
4497 self.streamCommentLineOrSelection()
4370 4498
4371 @pyqtSlot() 4499 @pyqtSlot()
4372 def uncommentLineOrSelection(self): 4500 def uncommentLineOrSelection(self):
4373 """ 4501 """
4374 Public slot to uncomment the current line or current selection. 4502 Public slot to uncomment the current line or current selection.
4375 """ 4503
4376 if self.hasSelectedText(): 4504 If the lexer supports a block comment, that is used for uncommenting.
4377 self.uncommentSelection() 4505 Otherwise a stream comment is used if that is supported. If none of
4378 else: 4506 these are supported, the request is ignored silently.
4379 self.uncommentLine() 4507 """
4380 4508 if self.lexer_ is not None:
4381 @pyqtSlot() 4509 if self.lexer_.canBlockComment():
4382 def streamCommentLine(self): 4510 if self.hasSelectedText():
4383 """ 4511 self.__uncommentSelection()
4384 Public slot to stream comment the current line. 4512 else:
4513 self.__uncommentLine()
4514 elif self.lexer_.canStreamComment():
4515 # delegate to the stream uncomment method
4516 self.streamUncommentLineOrSelection()
4517
4518 def __isStreamCommentedLine(self, line, streamCommentStr):
4519 """
4520 Private method to check, if the line is commented by a stream comment.
4521
4522 @param line text of the line to check
4523 @type str
4524 @param streamCommentStr dictionary containing the stream comment start and
4525 end strings
4526 @type dict
4527 @return flag indicating a stream commented line
4528 @rtype bool
4529 """
4530 line = line.strip()
4531 return line.startswith(streamCommentStr["start"]) and line.endswith(
4532 streamCommentStr["end"]
4533 )
4534
4535 @pyqtSlot()
4536 def __toggleStreamComment(self):
4537 """
4538 Private slot to toggle the comment of a block.
4539
4540 If the editor contains selected text and the start line is not commented, it
4541 will be commented. Otherwise the selection will be un-commented. In case there
4542 is no selected text and the current line is not commented, it will be commented.
4543 If is commented, the comment block will be removed.
4385 """ 4544 """
4386 if self.lexer_ is None or not self.lexer_.canStreamComment(): 4545 if self.lexer_ is None or not self.lexer_.canStreamComment():
4387 return 4546 return
4388 4547
4389 commentStr = self.lexer_.streamCommentStr() 4548 streamCommentStr = self.lexer_.streamCommentStr()
4390 line, index = self.getCursorPosition() 4549 line, index = self.getCursorPosition()
4391 4550
4392 self.beginUndoAction() 4551 if self.hasSelectedText():
4393 self.insertAt(commentStr["end"], line, self.lineLength(line)) 4552 # Check if the selection starts with a stream comment string.
4394 self.insertAt(commentStr["start"], line, 0) 4553 if self.text(self.getSelection()[0]).startswith(streamCommentStr["start"]):
4395 self.endUndoAction() 4554 self.streamUncommentLineOrSelection()
4396 4555 else:
4397 @pyqtSlot() 4556 self.streamCommentLineOrSelection()
4398 def streamCommentSelection(self): 4557 elif self.__isStreamCommentedLine(self.text(line), streamCommentStr):
4399 """ 4558 # It is a stream commented line.
4400 Public slot to comment the current selection. 4559 self.streamUncommentLineOrSelection()
4560 elif self.text(line).lstrip(" \t").startswith(streamCommentStr["start"]):
4561 # The cursor is at the first line of a stream comment.
4562 pos = len(self.text(line).replace(self.text(line).lstrip(" \t"), ""))
4563 endline = line
4564 lines = self.lines()
4565 while endline < lines and not self.text(endline).rstrip().endswith(
4566 streamCommentStr["end"]
4567 ):
4568 endline += 1
4569
4570 # Uncomment the determined block and reset the cursor position
4571 self.setSelection(line, pos, endline, self.lineLength(endline))
4572 self.uncommentLineOrSelection()
4573 self.setCursorPosition(line, index - len(streamCommentStr["start"]))
4574 elif self.text(line).rstrip().endswith(streamCommentStr["end"]):
4575 # The cursor is at the last line of a stream comment.
4576 begline = line
4577 while begline > 0 and not self.text(begline).lstrip(" \t").startswith(
4578 streamCommentStr["start"]
4579 ):
4580 begline -= 1
4581 pos = len(self.text(begline).replace(self.text(begline).lstrip(" \t"), ""))
4582
4583 # Uncomment the determined block and reset the cursor position
4584 self.setSelection(begline, pos, line, self.lineLength(line))
4585 self.uncommentLineOrSelection()
4586 self.setCursorPosition(
4587 line, min(index, self.lineLength(line) - len(self.getLineSeparator()))
4588 )
4589 else:
4590 # No selected text and the current line does not start with a stream comment
4591 # string, so comment the line.
4592 self.streamCommentLineOrSelection()
4593
4594 @pyqtSlot()
4595 def __streamCommentLine(self):
4596 """
4597 Private slot to stream comment the current line.
4401 """ 4598 """
4402 if self.lexer_ is None or not self.lexer_.canStreamComment(): 4599 if self.lexer_ is None or not self.lexer_.canStreamComment():
4403 return 4600 return
4404 4601
4602 streamCommentStr = self.lexer_.streamCommentStr()
4603 line, index = self.getCursorPosition()
4604
4605 self.beginUndoAction()
4606 self.insertAt(
4607 streamCommentStr["end"],
4608 line,
4609 self.lineLength(line) - len(self.getLineSeparator()),
4610 )
4611 self.insertAt(streamCommentStr["start"], line, 0)
4612 self.endUndoAction()
4613
4614 @pyqtSlot()
4615 def __streamCommentSelection(self):
4616 """
4617 Private slot to comment the current selection.
4618 """
4619 if self.lexer_ is None or not self.lexer_.canStreamComment():
4620 return
4621
4405 if not self.hasSelectedText(): 4622 if not self.hasSelectedText():
4406 return 4623 return
4407 4624
4408 commentStr = self.lexer_.streamCommentStr() 4625 streamCommentStr = self.lexer_.streamCommentStr()
4409 4626
4410 # get the selection boundaries 4627 # get the selection boundaries
4411 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4628 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4412 if indexTo == 0: 4629 if indexTo == 0:
4413 endLine = lineTo - 1 4630 endLine = lineTo - 1
4414 endIndex = self.lineLength(endLine) 4631 endIndex = self.lineLength(endLine) - len(self.getLineSeparator())
4415 else: 4632 else:
4416 endLine = lineTo 4633 endLine = lineTo
4417 endIndex = indexTo 4634 endIndex = indexTo
4418 4635
4419 self.beginUndoAction() 4636 self.beginUndoAction()
4420 self.insertAt(commentStr["end"], endLine, endIndex) 4637 self.insertAt(streamCommentStr["end"], endLine, endIndex)
4421 self.insertAt(commentStr["start"], lineFrom, indexFrom) 4638 self.insertAt(streamCommentStr["start"], lineFrom, indexFrom)
4422 4639
4423 # change the selection accordingly 4640 # change the selection accordingly
4424 if indexTo > 0: 4641 if indexTo > 0:
4425 indexTo += len(commentStr["end"]) 4642 indexTo += len(streamCommentStr["end"])
4426 if lineFrom == endLine: 4643 if lineFrom == endLine:
4427 indexTo += len(commentStr["start"]) 4644 indexTo += len(streamCommentStr["start"])
4428 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) 4645 self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
4429 self.endUndoAction() 4646 self.endUndoAction()
4430 4647
4431 @pyqtSlot() 4648 @pyqtSlot()
4649 def __streamUncommentLine(self):
4650 """
4651 Private slot to stream uncomment the current line.
4652 """
4653 if self.lexer_ is None or not self.lexer_.canStreamComment():
4654 return
4655
4656 streamCommentStr = self.lexer_.streamCommentStr()
4657 line, index = self.getCursorPosition()
4658
4659 # check if line starts and ends with the stream comment strings
4660 if not self.__isStreamCommentedLine(self.text(line), streamCommentStr):
4661 return
4662
4663 self.beginUndoAction()
4664 # 1. remove comment end string
4665 self.setSelection(
4666 line,
4667 self.lineLength(line)
4668 - len(self.getLineSeparator())
4669 - len(streamCommentStr["end"]),
4670 line,
4671 self.lineLength(line) - len(self.getLineSeparator()),
4672 )
4673 self.removeSelectedText()
4674
4675 # 2. remove comment start string
4676 lineText = self.text(line)
4677 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
4678 self.setSelection(line, pos, line, pos + len(streamCommentStr["start"]))
4679 self.removeSelectedText()
4680 self.endUndoAction()
4681
4682 @pyqtSlot()
4683 def __streamUncommentSelection(self):
4684 """
4685 Private slot to stream uncomment the current selection.
4686 """
4687 if self.lexer_ is None or not self.lexer_.canStreamComment():
4688 return
4689
4690 if not self.hasSelectedText():
4691 return
4692
4693 streamCommentStr = self.lexer_.streamCommentStr()
4694
4695 # get the selection boundaries
4696 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4697 if indexTo == 0:
4698 endLine = lineTo - 1
4699 endIndex = self.lineLength(endLine) - len(self.getLineSeparator())
4700 else:
4701 endLine = lineTo
4702 endIndex = indexTo
4703
4704 self.beginUndoAction()
4705 self.setSelection(lineFrom, indexFrom, endLine, endIndex)
4706 selTxt = self.selectedText()
4707 if selTxt.endswith(streamCommentStr["end"]):
4708 self.setSelection(
4709 endLine, endIndex - len(streamCommentStr["end"]), endLine, endIndex
4710 )
4711 self.removeSelectedText()
4712
4713 # modify selection end accordingly
4714 if indexTo > 0:
4715 indexTo -= len(streamCommentStr["end"])
4716 if selTxt.startswith(streamCommentStr["start"]):
4717 self.setSelection(
4718 lineFrom,
4719 indexFrom,
4720 lineFrom,
4721 indexFrom + len(streamCommentStr["start"]),
4722 )
4723 self.removeSelectedText()
4724
4725 # modify selection end accordingly
4726 if lineFrom == lineTo and indexTo > 0:
4727 indexTo -= len(streamCommentStr["start"])
4728 self.endUndoAction()
4729
4730 # now set the new selection
4731 self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
4732
4733 @pyqtSlot()
4432 def streamCommentLineOrSelection(self): 4734 def streamCommentLineOrSelection(self):
4433 """ 4735 """
4434 Public slot to stream comment the current line or current selection. 4736 Public slot to stream comment the current line or current selection.
4435 """ 4737 """
4436 if self.hasSelectedText(): 4738 if self.hasSelectedText():
4437 self.streamCommentSelection() 4739 self.__streamCommentSelection()
4438 else: 4740 else:
4439 self.streamCommentLine() 4741 self.__streamCommentLine()
4440 4742
4441 @pyqtSlot() 4743 @pyqtSlot()
4442 def boxCommentLine(self): 4744 def streamUncommentLineOrSelection(self):
4443 """ 4745 """
4444 Public slot to box comment the current line. 4746 Public slot to stream uncomment the current line or current selection.
4747 """
4748 if self.hasSelectedText():
4749 self.__streamUncommentSelection()
4750 else:
4751 self.__streamUncommentLine()
4752
4753 @pyqtSlot()
4754 def __boxCommentLine(self):
4755 """
4756 Private slot to box comment the current line.
4445 """ 4757 """
4446 if self.lexer_ is None or not self.lexer_.canBoxComment(): 4758 if self.lexer_ is None or not self.lexer_.canBoxComment():
4447 return 4759 return
4448 4760
4449 commentStr = self.lexer_.boxCommentStr() 4761 boxCommentStr = self.lexer_.boxCommentStr()
4450 line, index = self.getCursorPosition() 4762 line, index = self.getCursorPosition()
4451 4763
4452 eol = self.getLineSeparator() 4764 eol = self.getLineSeparator()
4453 self.beginUndoAction() 4765 self.beginUndoAction()
4454 self.insertAt(eol, line, self.lineLength(line)) 4766 self.insertAt(eol, line, self.lineLength(line))
4455 self.insertAt(commentStr["end"], line + 1, 0) 4767 self.insertAt(boxCommentStr["end"], line + 1, 0)
4456 self.insertAt(commentStr["middle"], line, 0) 4768 self.insertAt(boxCommentStr["middle"], line, 0)
4457 self.insertAt(eol, line, 0) 4769 self.insertAt(eol, line, 0)
4458 self.insertAt(commentStr["start"], line, 0) 4770 self.insertAt(boxCommentStr["start"], line, 0)
4459 self.endUndoAction() 4771 self.endUndoAction()
4460 4772
4461 @pyqtSlot() 4773 @pyqtSlot()
4462 def boxCommentSelection(self): 4774 def __boxCommentSelection(self):
4463 """ 4775 """
4464 Public slot to box comment the current selection. 4776 Private slot to box comment the current selection.
4465 """ 4777 """
4466 if self.lexer_ is None or not self.lexer_.canBoxComment(): 4778 if self.lexer_ is None or not self.lexer_.canBoxComment():
4467 return 4779 return
4468 4780
4469 if not self.hasSelectedText(): 4781 if not self.hasSelectedText():
4470 return 4782 return
4471 4783
4472 commentStr = self.lexer_.boxCommentStr() 4784 boxCommentStr = self.lexer_.boxCommentStr()
4473 4785
4474 # get the selection boundaries 4786 # get the selection boundaries
4475 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4787 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4476 endLine = lineTo if indexTo else lineTo - 1 4788 endLine = lineTo if indexTo else lineTo - 1
4477 4789
4478 self.beginUndoAction() 4790 self.beginUndoAction()
4479 # iterate over the lines 4791 # iterate over the lines
4480 for line in range(lineFrom, endLine + 1): 4792 for line in range(lineFrom, endLine + 1):
4481 self.insertAt(commentStr["middle"], line, 0) 4793 self.insertAt(boxCommentStr["middle"], line, 0)
4482 4794
4483 # now do the comments before and after the selection 4795 # now do the comments before and after the selection
4484 eol = self.getLineSeparator() 4796 eol = self.getLineSeparator()
4485 self.insertAt(eol, endLine, self.lineLength(endLine)) 4797 self.insertAt(eol, endLine, self.lineLength(endLine))
4486 self.insertAt(commentStr["end"], endLine + 1, 0) 4798 self.insertAt(boxCommentStr["end"], endLine + 1, 0)
4487 self.insertAt(eol, lineFrom, 0) 4799 self.insertAt(eol, lineFrom, 0)
4488 self.insertAt(commentStr["start"], lineFrom, 0) 4800 self.insertAt(boxCommentStr["start"], lineFrom, 0)
4489 4801
4490 # change the selection accordingly 4802 # change the selection accordingly
4491 self.setSelection(lineFrom, 0, endLine + 3, 0) 4803 self.setSelection(lineFrom, 0, endLine + 3, 0)
4492 self.endUndoAction() 4804 self.endUndoAction()
4493 4805
4495 def boxCommentLineOrSelection(self): 4807 def boxCommentLineOrSelection(self):
4496 """ 4808 """
4497 Public slot to box comment the current line or current selection. 4809 Public slot to box comment the current line or current selection.
4498 """ 4810 """
4499 if self.hasSelectedText(): 4811 if self.hasSelectedText():
4500 self.boxCommentSelection() 4812 self.__boxCommentSelection()
4501 else: 4813 else:
4502 self.boxCommentLine() 4814 self.__boxCommentLine()
4503 4815
4504 ########################################################################### 4816 ###########################################################################
4505 ## Indentation handling methods below 4817 ## Indentation handling methods below
4506 ########################################################################### 4818 ###########################################################################
4507 4819
4508 def __indentLine(self, indent=True): 4820 def __indentLine(self, indent=True):
4509 """ 4821 """
4510 Private method to indent or unindent the current line. 4822 Private method to indent or unindent the current line.
4511 4823
4512 @param indent flag indicating an indent operation (boolean) 4824 @param indent flag indicating an indent operation
4513 <br />If the flag is true, an indent operation is performed. 4825 <br />If the flag is true, an indent operation is performed.
4514 Otherwise the current line is unindented. 4826 Otherwise the current line is unindented.
4827 @type bool
4515 """ 4828 """
4516 line, index = self.getCursorPosition() 4829 line, index = self.getCursorPosition()
4517 self.beginUndoAction() 4830 self.beginUndoAction()
4518 if indent: 4831 if indent:
4519 self.indent(line) 4832 self.indent(line)
4527 4840
4528 def __indentSelection(self, indent=True): 4841 def __indentSelection(self, indent=True):
4529 """ 4842 """
4530 Private method to indent or unindent the current selection. 4843 Private method to indent or unindent the current selection.
4531 4844
4532 @param indent flag indicating an indent operation (boolean) 4845 @param indent flag indicating an indent operation
4533 <br />If the flag is true, an indent operation is performed. 4846 <br />If the flag is true, an indent operation is performed.
4534 Otherwise the current line is unindented. 4847 Otherwise the current line is unindented.
4848 @type bool
4535 """ 4849 """
4536 if not self.hasSelectedText(): 4850 if not self.hasSelectedText():
4537 return 4851 return
4538 4852
4539 # get the selection 4853 # get the selection
4646 4960
4647 def isLastEditPositionAvailable(self): 4961 def isLastEditPositionAvailable(self):
4648 """ 4962 """
4649 Public method to check, if a last edit position is available. 4963 Public method to check, if a last edit position is available.
4650 4964
4651 @return flag indicating availability (boolean) 4965 @return flag indicating availability
4966 @rtype bool
4652 """ 4967 """
4653 return self.__lastEditPosition is not None 4968 return self.__lastEditPosition is not None
4654 4969
4655 def gotoLastEditPosition(self): 4970 def gotoLastEditPosition(self):
4656 """ 4971 """
4661 4976
4662 def gotoMethodClass(self, goUp=False): 4977 def gotoMethodClass(self, goUp=False):
4663 """ 4978 """
4664 Public method to go to the next Python method or class definition. 4979 Public method to go to the next Python method or class definition.
4665 4980
4666 @param goUp flag indicating the move direction (boolean) 4981 @param goUp flag indicating the move direction
4982 @type bool
4667 """ 4983 """
4668 if self.isPyFile() or self.isRubyFile(): 4984 if self.isPyFile() or self.isRubyFile():
4669 lineNo = self.getCursorPosition()[0] 4985 lineNo = self.getCursorPosition()[0]
4670 line = self.text(lineNo) 4986 line = self.text(lineNo)
4671 if line.strip().startswith(("class ", "def ", "module ")): 4987 if line.strip().startswith(("class ", "def ", "module ")):
5210 5526
5211 def canAutoCompleteFromAPIs(self): 5527 def canAutoCompleteFromAPIs(self):
5212 """ 5528 """
5213 Public method to check for API availablity. 5529 Public method to check for API availablity.
5214 5530
5215 @return flag indicating autocompletion from APIs is available (boolean) 5531 @return flag indicating autocompletion from APIs is available
5532 @rtype bool
5216 """ 5533 """
5217 return self.acAPI 5534 return self.acAPI
5218 5535
5219 def autoCompleteQScintilla(self): 5536 def autoCompleteQScintilla(self):
5220 """ 5537 """
5245 def setAutoCompletionEnabled(self, enable): 5562 def setAutoCompletionEnabled(self, enable):
5246 """ 5563 """
5247 Public method to enable/disable autocompletion. 5564 Public method to enable/disable autocompletion.
5248 5565
5249 @param enable flag indicating the desired autocompletion status 5566 @param enable flag indicating the desired autocompletion status
5250 (boolean) 5567 @type bool
5251 """ 5568 """
5252 if enable: 5569 if enable:
5253 autoCompletionSource = Preferences.getEditor("AutoCompletionSource") 5570 autoCompletionSource = Preferences.getEditor("AutoCompletionSource")
5254 if autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsDocument: 5571 if autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsDocument:
5255 self.setAutoCompletionSource( 5572 self.setAutoCompletionSource(
5321 def __isStartChar(self, ch): 5638 def __isStartChar(self, ch):
5322 """ 5639 """
5323 Private method to check, if a character is an autocompletion start 5640 Private method to check, if a character is an autocompletion start
5324 character. 5641 character.
5325 5642
5326 @param ch character to be checked (one character string) 5643 @param ch character to be checked
5327 @return flag indicating the result (boolean) 5644 @type str
5645 @return flag indicating the result
5646 @rtype bool
5328 """ 5647 """
5329 if self.lexer_ is None: 5648 if self.lexer_ is None:
5330 return False 5649 return False
5331 5650
5332 wseps = self.lexer_.autoCompletionWordSeparators() 5651 wseps = self.lexer_.autoCompletionWordSeparators()
5410 def autoComplete(self, auto=False, context=True): 5729 def autoComplete(self, auto=False, context=True):
5411 """ 5730 """
5412 Public method to start auto-completion. 5731 Public method to start auto-completion.
5413 5732
5414 @param auto flag indicating a call from the __charAdded method 5733 @param auto flag indicating a call from the __charAdded method
5415 (boolean) 5734 @type bool
5416 @param context flag indicating to complete a context (boolean) 5735 @param context flag indicating to complete a context
5736 @type bool
5417 """ 5737 """
5418 if auto and not Preferences.getEditor("AutoCompletionEnabled"): 5738 if auto and not Preferences.getEditor("AutoCompletionEnabled"):
5419 # auto-completion is disabled 5739 # auto-completion is disabled
5420 return 5740 return
5421 5741
5462 def __autoComplete(self, auto=True, context=None): 5782 def __autoComplete(self, auto=True, context=None):
5463 """ 5783 """
5464 Private method to start auto-completion via plug-ins. 5784 Private method to start auto-completion via plug-ins.
5465 5785
5466 @param auto flag indicating a call from the __charAdded method 5786 @param auto flag indicating a call from the __charAdded method
5467 (boolean) 5787 @type bool
5468 @param context flag indicating to complete a context 5788 @param context flag indicating to complete a context
5469 @type bool or None 5789 @type bool or None
5470 """ 5790 """
5471 self.__acCompletions.clear() 5791 self.__acCompletions.clear()
5472 self.__acCompletionsFinished = 0 5792 self.__acCompletionsFinished = 0
5633 def canProvideDynamicAutoCompletion(self): 5953 def canProvideDynamicAutoCompletion(self):
5634 """ 5954 """
5635 Public method to test the dynamic auto-completion availability. 5955 Public method to test the dynamic auto-completion availability.
5636 5956
5637 @return flag indicating the availability of dynamic auto-completion 5957 @return flag indicating the availability of dynamic auto-completion
5638 (boolean) 5958 @rtype bool
5639 """ 5959 """
5640 return ( 5960 return (
5641 self.acAPI 5961 self.acAPI
5642 or bool(self.__completionListHookFunctions) 5962 or bool(self.__completionListHookFunctions)
5643 or bool(self.__completionListAsyncHookFunctions) 5963 or bool(self.__completionListAsyncHookFunctions)
5700 6020
5701 def canProvideCallTipps(self): 6021 def canProvideCallTipps(self):
5702 """ 6022 """
5703 Public method to test the calltips availability. 6023 Public method to test the calltips availability.
5704 6024
5705 @return flag indicating the availability of calltips (boolean) 6025 @return flag indicating the availability of calltips
6026 @rtype bool
5706 """ 6027 """
5707 return self.acAPI or bool(self.__ctHookFunctions) 6028 return self.acAPI or bool(self.__ctHookFunctions)
5708 6029
5709 def callTip(self): 6030 def callTip(self):
5710 """ 6031 """
5826 6147
5827 def __adjustedCallTipPosition(self, ctshift, pos): 6148 def __adjustedCallTipPosition(self, ctshift, pos):
5828 """ 6149 """
5829 Private method to calculate an adjusted position for showing calltips. 6150 Private method to calculate an adjusted position for showing calltips.
5830 6151
5831 @param ctshift amount the calltip shall be shifted (integer) 6152 @param ctshift amount the calltip shall be shifted
5832 @param pos position into the text (integer) 6153 @type int
5833 @return new position for the calltip (integer) 6154 @param pos position into the text
6155 @type int
6156 @return new position for the calltip
6157 @rtype int
5834 """ 6158 """
5835 ct = pos 6159 ct = pos
5836 if ctshift: 6160 if ctshift:
5837 ctmin = self.SendScintilla( 6161 ctmin = self.SendScintilla(
5838 QsciScintilla.SCI_POSITIONFROMLINE, 6162 QsciScintilla.SCI_POSITIONFROMLINE,
5861 6185
5862 def __marginNumber(self, xPos): 6186 def __marginNumber(self, xPos):
5863 """ 6187 """
5864 Private method to calculate the margin number based on a x position. 6188 Private method to calculate the margin number based on a x position.
5865 6189
5866 @param xPos x position (integer) 6190 @param xPos x position
6191 @type int
5867 @return margin number (integer, -1 for no margin) 6192 @return margin number (integer, -1 for no margin)
6193 @rtype int
5868 """ 6194 """
5869 width = 0 6195 width = 0
5870 for margin in range(5): 6196 for margin in range(5):
5871 width += self.marginWidth(margin) 6197 width += self.marginWidth(margin)
5872 if xPos <= width: 6198 if xPos <= width:
6164 def __reopenWithEncodingMenuTriggered(self, act): 6490 def __reopenWithEncodingMenuTriggered(self, act):
6165 """ 6491 """
6166 Private method to handle the rereading of the file with a selected 6492 Private method to handle the rereading of the file with a selected
6167 encoding. 6493 encoding.
6168 6494
6169 @param act reference to the action that was triggered (QAction) 6495 @param act reference to the action that was triggered
6496 @type QAction
6170 """ 6497 """
6171 encoding = act.data() 6498 encoding = act.data()
6172 self.readFile(self.fileName, encoding=encoding) 6499 self.readFile(self.fileName, encoding=encoding)
6173 self.__convertTabs() 6500 self.__convertTabs()
6174 self.__checkEncoding() 6501 self.__checkEncoding()
6303 6630
6304 def __shouldAutosave(self): 6631 def __shouldAutosave(self):
6305 """ 6632 """
6306 Private method to check the autosave flags. 6633 Private method to check the autosave flags.
6307 6634
6308 @return flag indicating this editor should be saved (boolean) 6635 @return flag indicating this editor should be saved
6636 @rtype bool
6309 """ 6637 """
6310 return ( 6638 return (
6311 bool(self.fileName) 6639 bool(self.fileName)
6312 and not self.__autosaveManuallyDisabled 6640 and not self.__autosaveManuallyDisabled
6313 and not self.isReadOnly() 6641 and not self.isReadOnly()
6583 6911
6584 def getCoverageLines(self): 6912 def getCoverageLines(self):
6585 """ 6913 """
6586 Public method to get the lines containing a coverage marker. 6914 Public method to get the lines containing a coverage marker.
6587 6915
6588 @return list of lines containing a coverage marker (list of integer) 6916 @return list of lines containing a coverage marker
6917 @rtype list of int
6589 """ 6918 """
6590 lines = [] 6919 lines = []
6591 line = -1 6920 line = -1
6592 while True: 6921 while True:
6593 line = self.markerFindNext(line + 1, 1 << self.notcovered) 6922 line = self.markerFindNext(line + 1, 1 << self.notcovered)
6599 6928
6600 def hasCoverageMarkers(self): 6929 def hasCoverageMarkers(self):
6601 """ 6930 """
6602 Public method to test, if there are coverage markers. 6931 Public method to test, if there are coverage markers.
6603 6932
6604 @return flag indicating the presence of coverage markers (boolean) 6933 @return flag indicating the presence of coverage markers
6934 @rtype bool
6605 """ 6935 """
6606 return len(self.notcoveredMarkers) > 0 6936 return len(self.notcoveredMarkers) > 0
6607 6937
6608 @pyqtSlot() 6938 @pyqtSlot()
6609 def nextUncovered(self): 6939 def nextUncovered(self):
6750 self.syntaxerrors[handle].append((msg, index)) 7080 self.syntaxerrors[handle].append((msg, index))
6751 if show: 7081 if show:
6752 self.setCursorPosition(line - 1, index) 7082 self.setCursorPosition(line - 1, index)
6753 self.ensureLineVisible(line - 1) 7083 self.ensureLineVisible(line - 1)
6754 else: 7084 else:
6755 for handle in list(self.syntaxerrors.keys()): 7085 for handle in list(self.syntaxerrors):
6756 if self.markerLine(handle) == line - 1: 7086 if self.markerLine(handle) == line - 1:
6757 del self.syntaxerrors[handle] 7087 del self.syntaxerrors[handle]
6758 self.markerDeleteHandle(handle) 7088 self.markerDeleteHandle(handle)
6759 self.syntaxerrorToggled.emit(self) 7089 self.syntaxerrorToggled.emit(self)
6760 7090
6763 7093
6764 def getSyntaxErrorLines(self): 7094 def getSyntaxErrorLines(self):
6765 """ 7095 """
6766 Public method to get the lines containing a syntax error. 7096 Public method to get the lines containing a syntax error.
6767 7097
6768 @return list of lines containing a syntax error (list of integer) 7098 @return list of lines containing a syntax error
7099 @rtype list of int
6769 """ 7100 """
6770 lines = [] 7101 lines = []
6771 line = -1 7102 line = -1
6772 while True: 7103 while True:
6773 line = self.markerFindNext(line + 1, 1 << self.syntaxerror) 7104 line = self.markerFindNext(line + 1, 1 << self.syntaxerror)
6779 7110
6780 def hasSyntaxErrors(self): 7111 def hasSyntaxErrors(self):
6781 """ 7112 """
6782 Public method to check for the presence of syntax errors. 7113 Public method to check for the presence of syntax errors.
6783 7114
6784 @return flag indicating the presence of syntax errors (boolean) 7115 @return flag indicating the presence of syntax errors
7116 @rtype bool
6785 """ 7117 """
6786 return len(self.syntaxerrors) > 0 7118 return len(self.syntaxerrors) > 0
6787 7119
6788 @pyqtSlot() 7120 @pyqtSlot()
6789 def gotoSyntaxError(self): 7121 def gotoSyntaxError(self):
6802 @pyqtSlot() 7134 @pyqtSlot()
6803 def clearSyntaxError(self): 7135 def clearSyntaxError(self):
6804 """ 7136 """
6805 Public slot to handle the 'Clear all syntax error' context menu action. 7137 Public slot to handle the 'Clear all syntax error' context menu action.
6806 """ 7138 """
6807 for handle in list(self.syntaxerrors.keys()): 7139 for handle in list(self.syntaxerrors):
6808 line = self.markerLine(handle) + 1 7140 line = self.markerLine(handle) + 1
6809 self.toggleSyntaxError(line, 0, False) 7141 self.toggleSyntaxError(line, 0, False)
6810 7142
6811 self.syntaxerrors.clear() 7143 self.syntaxerrors.clear()
6812 self.syntaxerrorToggled.emit(self) 7144 self.syntaxerrorToggled.emit(self)
6907 self.markerLine(handle) == line - 1 7239 self.markerLine(handle) == line - 1
6908 and warn not in self._warnings[handle] 7240 and warn not in self._warnings[handle]
6909 ): 7241 ):
6910 self._warnings[handle].append(warn) 7242 self._warnings[handle].append(warn)
6911 else: 7243 else:
6912 for handle in list(self._warnings.keys()): 7244 for handle in list(self._warnings):
6913 if self.markerLine(handle) == line - 1: 7245 if self.markerLine(handle) == line - 1:
6914 del self._warnings[handle] 7246 del self._warnings[handle]
6915 self.markerDeleteHandle(handle) 7247 self.markerDeleteHandle(handle)
6916 self.syntaxerrorToggled.emit(self) 7248 self.syntaxerrorToggled.emit(self)
6917 # signal is also used for warnings 7249 # signal is also used for warnings
6921 7253
6922 def getWarningLines(self): 7254 def getWarningLines(self):
6923 """ 7255 """
6924 Public method to get the lines containing a warning. 7256 Public method to get the lines containing a warning.
6925 7257
6926 @return list of lines containing a warning (list of integer) 7258 @return list of lines containing a warning
7259 @rtype list of int
6927 """ 7260 """
6928 lines = [] 7261 lines = []
6929 line = -1 7262 line = -1
6930 while True: 7263 while True:
6931 line = self.markerFindNext(line + 1, 1 << self.warning) 7264 line = self.markerFindNext(line + 1, 1 << self.warning)
6937 7270
6938 def hasWarnings(self): 7271 def hasWarnings(self):
6939 """ 7272 """
6940 Public method to check for the presence of warnings. 7273 Public method to check for the presence of warnings.
6941 7274
6942 @return flag indicating the presence of warnings (boolean) 7275 @return flag indicating the presence of warnings
7276 @rtype bool
6943 """ 7277 """
6944 return len(self._warnings) > 0 7278 return len(self._warnings) > 0
6945 7279
6946 @pyqtSlot() 7280 @pyqtSlot()
6947 def nextWarning(self): 7281 def nextWarning(self):
7019 """ 7353 """
7020 Private method to clear warnings of a specific kind. 7354 Private method to clear warnings of a specific kind.
7021 7355
7022 @param warningKind kind of warning to clear (Editor.WarningCode, 7356 @param warningKind kind of warning to clear (Editor.WarningCode,
7023 Editor.WarningPython, Editor.WarningStyle) 7357 Editor.WarningPython, Editor.WarningStyle)
7024 """ 7358 @type int
7025 for handle in list(self._warnings.keys()): 7359 """
7360 for handle in list(self._warnings):
7026 issues = [] 7361 issues = []
7027 for msg, warningType in self._warnings[handle]: 7362 for msg, warningType in self._warnings[handle]:
7028 if warningType == warningKind: 7363 if warningType == warningKind:
7029 continue 7364 continue
7030 7365
7137 7472
7138 def __setAnnotation(self, line): 7473 def __setAnnotation(self, line):
7139 """ 7474 """
7140 Private method to set the annotations for the given line. 7475 Private method to set the annotations for the given line.
7141 7476
7142 @param line number of the line that needs annotation (integer) 7477 @param line number of the line that needs annotation
7478 @type int
7143 """ 7479 """
7144 if hasattr(QsciScintilla, "annotate"): 7480 if hasattr(QsciScintilla, "annotate"):
7145 warningAnnotations = [] 7481 warningAnnotations = []
7146 errorAnnotations = [] 7482 errorAnnotations = []
7147 styleAnnotations = [] 7483 styleAnnotations = []
7281 def __getMacroName(self): 7617 def __getMacroName(self):
7282 """ 7618 """
7283 Private method to select a macro name from the list of macros. 7619 Private method to select a macro name from the list of macros.
7284 7620
7285 @return Tuple of macro name and a flag, indicating, if the user 7621 @return Tuple of macro name and a flag, indicating, if the user
7286 pressed ok or canceled the operation. (string, boolean) 7622 pressed ok or canceled the operation.
7623 @rtype tuple of (str, bool)
7287 """ 7624 """
7288 qs = [] 7625 qs = []
7289 for s in self.macros: 7626 for s in self.macros:
7290 qs.append(s) 7627 qs.append(s)
7291 qs.sort() 7628 qs.sort()
7471 7808
7472 This overwritten method redirects the action to our 7809 This overwritten method redirects the action to our
7473 ViewManager.closeEditor, which in turn calls our closeIt 7810 ViewManager.closeEditor, which in turn calls our closeIt
7474 method. 7811 method.
7475 7812
7476 @return flag indicating a successful close of the editor (boolean) 7813 @return flag indicating a successful close of the editor
7814 @rtype bool
7477 """ 7815 """
7478 return self.vm.closeEditor(self) 7816 return self.vm.closeEditor(self)
7479 7817
7480 def closeIt(self): 7818 def closeIt(self):
7481 """ 7819 """
7565 7903
7566 @param event the event object 7904 @param event the event object
7567 @type QFocusEvent 7905 @type QFocusEvent
7568 """ 7906 """
7569 self.recolor() 7907 self.recolor()
7908
7570 self.vm.editActGrp.setEnabled(True) 7909 self.vm.editActGrp.setEnabled(True)
7571 self.vm.editorActGrp.setEnabled(True) 7910 self.vm.editorActGrp.setEnabled(True)
7572 self.vm.copyActGrp.setEnabled(True) 7911 self.vm.copyActGrp.setEnabled(True)
7573 self.vm.viewActGrp.setEnabled(True) 7912 self.vm.viewActGrp.setEnabled(True)
7574 self.vm.searchActGrp.setEnabled(True) 7913 self.vm.searchActGrp.setEnabled(True)
7914
7575 with contextlib.suppress(AttributeError): 7915 with contextlib.suppress(AttributeError):
7576 self.setCaretWidth(self.caretWidth) 7916 self.setCaretWidth(self.caretWidth)
7577 self.__updateReadOnly(False) 7917 self.__updateReadOnly(False)
7918 self.setCursorFlashTime(QApplication.cursorFlashTime())
7919
7920 super().focusInEvent(event)
7921
7922 def focusOutEvent(self, event):
7923 """
7924 Protected method called when the editor loses focus.
7925
7926 @param event the event object
7927 @type QFocusEvent
7928 """
7929 if Preferences.getEditor("AutosaveOnFocusLost") and self.__shouldAutosave():
7930 self.saveFile()
7931
7932 self.vm.editorActGrp.setEnabled(False)
7933 self.setCaretWidth(0)
7934
7935 self.cancelCallTips()
7936
7937 super().focusOutEvent(event)
7938
7939 def changeEvent(self, evt):
7940 """
7941 Protected method called to process an event.
7942
7943 This implements special handling for the events showMaximized,
7944 showMinimized and showNormal. The windows caption is shortened
7945 for the minimized mode and reset to the full filename for the
7946 other modes. This is to make the editor windows work nicer
7947 with the QWorkspace.
7948
7949 @param evt the event, that was generated
7950 @type QEvent
7951 """
7952 if evt.type() == QEvent.Type.WindowStateChange and bool(self.fileName):
7953 cap = (
7954 os.path.basename(self.fileName)
7955 if self.windowState() == Qt.WindowState.WindowMinimized
7956 else self.fileName
7957 )
7958 if self.checkReadOnly():
7959 cap = self.tr("{0} (ro)").format(cap)
7960 self.setWindowTitle(cap)
7961
7962 super().changeEvent(evt)
7963
7964 def mousePressEvent(self, event):
7965 """
7966 Protected method to handle the mouse press event.
7967
7968 @param event the mouse press event
7969 @type QMouseEvent
7970 """
7971 if event.button() == Qt.MouseButton.XButton1:
7972 self.undo()
7973 event.accept()
7974 elif event.button() == Qt.MouseButton.XButton2:
7975 self.redo()
7976 event.accept()
7977 elif event.button() == Qt.MouseButton.LeftButton and bool(
7978 event.modifiers()
7979 & (Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.AltModifier)
7980 ):
7981 line, index = self.lineIndexFromPoint(event.position().toPoint())
7982 self.addCursor(line, index)
7983 event.accept()
7984 else:
7985 self.vm.eventFilter(self, event)
7986 super().mousePressEvent(event)
7987
7988 def mouseDoubleClickEvent(self, evt):
7989 """
7990 Protected method to handle mouse double click events.
7991
7992 @param evt reference to the mouse event
7993 @type QMouseEvent
7994 """
7995 super().mouseDoubleClickEvent(evt)
7996
7997 # accept all double click events even if not handled by QScintilla
7998 evt.accept()
7999
8000 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons())
8001
8002 def wheelEvent(self, evt):
8003 """
8004 Protected method to handle wheel events.
8005
8006 @param evt reference to the wheel event
8007 @type QWheelEvent
8008 """
8009 delta = evt.angleDelta().y()
8010 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
8011 if delta < 0:
8012 self.zoomOut()
8013 elif delta > 0:
8014 self.zoomIn()
8015 evt.accept()
8016 return
8017
8018 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
8019 if delta < 0:
8020 self.gotoMethodClass(False)
8021 elif delta > 0:
8022 self.gotoMethodClass(True)
8023 evt.accept()
8024 return
8025
8026 super().wheelEvent(evt)
8027
8028 def event(self, evt):
8029 """
8030 Public method handling events.
8031
8032 @param evt reference to the event
8033 @type QEvent
8034 @return flag indicating, if the event was handled
8035 @rtype bool
8036 """
8037 if evt.type() == QEvent.Type.Gesture:
8038 self.gestureEvent(evt)
8039 return True
8040
8041 return super().event(evt)
8042
8043 def gestureEvent(self, evt):
8044 """
8045 Protected method handling gesture events.
8046
8047 @param evt reference to the gesture event
8048 @type QGestureEvent
8049 """
8050 pinch = evt.gesture(Qt.GestureType.PinchGesture)
8051 if pinch:
8052 if pinch.state() == Qt.GestureState.GestureStarted:
8053 zoom = (self.getZoom() + 10) / 10.0
8054 pinch.setTotalScaleFactor(zoom)
8055 elif pinch.state() == Qt.GestureState.GestureUpdated:
8056 zoom = int(pinch.totalScaleFactor() * 10) - 10
8057 if zoom <= -9:
8058 zoom = -9
8059 pinch.setTotalScaleFactor(0.1)
8060 elif zoom >= 20:
8061 zoom = 20
8062 pinch.setTotalScaleFactor(3.0)
8063 self.zoomTo(zoom)
8064 evt.accept()
8065
8066 def resizeEvent(self, evt):
8067 """
8068 Protected method handling resize events.
8069
8070 @param evt reference to the resize event
8071 @type QResizeEvent
8072 """
8073 super().resizeEvent(evt)
8074 self.__markerMap.calculateGeometry()
8075
8076 def viewportEvent(self, evt):
8077 """
8078 Protected method handling event of the viewport.
8079
8080 @param evt reference to the event
8081 @type QEvent
8082 @return flag indiating that the event was handled
8083 @rtype bool
8084 """
8085 with contextlib.suppress(AttributeError):
8086 self.__markerMap.calculateGeometry()
8087 return super().viewportEvent(evt)
8088
8089 def __updateReadOnly(self, bForce=True):
8090 """
8091 Private method to update the readOnly information for this editor.
8092
8093 If bForce is True, then updates everything regardless if
8094 the attributes have actually changed, such as during
8095 initialization time. A signal is emitted after the
8096 caption change.
8097
8098 @param bForce True to force change, False to only update and emit
8099 signal if there was an attribute change.
8100 @type bool
8101 """
8102 if self.fileName == "" or not FileSystemUtilities.isPlainFileName(
8103 self.fileName
8104 ):
8105 return
8106
8107 readOnly = self.checkReadOnly()
8108 if not bForce and (readOnly == self.isReadOnly()):
8109 return
8110
8111 cap = self.fileName
8112 if readOnly:
8113 cap = self.tr("{0} (ro)".format(cap))
8114 self.setReadOnly(readOnly)
8115 self.setWindowTitle(cap)
8116 self.captionChanged.emit(cap, self)
8117
8118 def checkReadOnly(self):
8119 """
8120 Public method to check the 'read only' state.
8121
8122 @return flag indicate a 'read only' state
8123 @rtype bool
8124 """
8125 return (
8126 FileSystemUtilities.isPlainFileName(self.fileName)
8127 and not os.access(self.fileName, os.W_OK)
8128 ) or self.isReadOnly()
8129
8130 @pyqtSlot()
8131 def checkRereadFile(self):
8132 """
8133 Public slot to check, if the file needs to be re-read, and refresh it if
8134 needed.
8135 """
7578 if ( 8136 if (
7579 self.vm.editorsCheckFocusInEnabled() 8137 self.fileName
7580 and not self.inReopenPrompt
7581 and self.fileName
7582 and pathlib.Path(self.fileName).exists() 8138 and pathlib.Path(self.fileName).exists()
7583 and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified 8139 and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified
7584 ): 8140 ):
7585 self.inReopenPrompt = True
7586 if Preferences.getEditor("AutoReopen") and not self.isModified(): 8141 if Preferences.getEditor("AutoReopen") and not self.isModified():
7587 self.refresh() 8142 self.refresh()
7588 else: 8143 else:
7589 msg = self.tr( 8144 msg = self.tr(
7590 """<p>The file <b>{0}</b> has been changed while it""" 8145 """<p>The file <b>{0}</b> has been changed while it"""
7607 if res: 8162 if res:
7608 self.refresh() 8163 self.refresh()
7609 else: 8164 else:
7610 # do not prompt for this change again... 8165 # do not prompt for this change again...
7611 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime 8166 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
7612 self.inReopenPrompt = False 8167
7613 8168 @pyqtSlot()
7614 self.setCursorFlashTime(QApplication.cursorFlashTime()) 8169 def recordModificationTime(self):
7615 8170 """
7616 super().focusInEvent(event) 8171 Public slot to record the modification time of our file.
7617 8172 """
7618 def focusOutEvent(self, event): 8173 if self.fileName and pathlib.Path(self.fileName).exists():
7619 """ 8174 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
7620 Protected method called when the editor loses focus.
7621
7622 @param event the event object
7623 @type QFocusEvent
7624 """
7625 if Preferences.getEditor("AutosaveOnFocusLost") and self.__shouldAutosave():
7626 self.saveFile()
7627
7628 self.vm.editorActGrp.setEnabled(False)
7629 self.setCaretWidth(0)
7630
7631 self.cancelCallTips()
7632
7633 super().focusOutEvent(event)
7634
7635 def changeEvent(self, evt):
7636 """
7637 Protected method called to process an event.
7638
7639 This implements special handling for the events showMaximized,
7640 showMinimized and showNormal. The windows caption is shortened
7641 for the minimized mode and reset to the full filename for the
7642 other modes. This is to make the editor windows work nicer
7643 with the QWorkspace.
7644
7645 @param evt the event, that was generated
7646 @type QEvent
7647 """
7648 if evt.type() == QEvent.Type.WindowStateChange and bool(self.fileName):
7649 cap = (
7650 os.path.basename(self.fileName)
7651 if self.windowState() == Qt.WindowState.WindowMinimized
7652 else self.fileName
7653 )
7654 if self.checkReadOnly():
7655 cap = self.tr("{0} (ro)").format(cap)
7656 self.setWindowTitle(cap)
7657
7658 super().changeEvent(evt)
7659
7660 def mousePressEvent(self, event):
7661 """
7662 Protected method to handle the mouse press event.
7663
7664 @param event the mouse press event
7665 @type QMouseEvent
7666 """
7667 if event.button() == Qt.MouseButton.XButton1:
7668 self.undo()
7669 event.accept()
7670 elif event.button() == Qt.MouseButton.XButton2:
7671 self.redo()
7672 event.accept()
7673 elif event.button() == Qt.MouseButton.LeftButton and bool(
7674 event.modifiers()
7675 & (Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.AltModifier)
7676 ):
7677 line, index = self.lineIndexFromPoint(event.position().toPoint())
7678 self.addCursor(line, index)
7679 event.accept()
7680 else:
7681 self.vm.eventFilter(self, event)
7682 super().mousePressEvent(event)
7683
7684 def mouseDoubleClickEvent(self, evt):
7685 """
7686 Protected method to handle mouse double click events.
7687
7688 @param evt reference to the mouse event
7689 @type QMouseEvent
7690 """
7691 super().mouseDoubleClickEvent(evt)
7692
7693 # accept all double click events even if not handled by QScintilla
7694 evt.accept()
7695
7696 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons())
7697
7698 def wheelEvent(self, evt):
7699 """
7700 Protected method to handle wheel events.
7701
7702 @param evt reference to the wheel event
7703 @type QWheelEvent
7704 """
7705 delta = evt.angleDelta().y()
7706 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
7707 if delta < 0:
7708 self.zoomOut()
7709 elif delta > 0:
7710 self.zoomIn()
7711 evt.accept()
7712 return
7713
7714 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
7715 if delta < 0:
7716 self.gotoMethodClass(False)
7717 elif delta > 0:
7718 self.gotoMethodClass(True)
7719 evt.accept()
7720 return
7721
7722 super().wheelEvent(evt)
7723
7724 def event(self, evt):
7725 """
7726 Public method handling events.
7727
7728 @param evt reference to the event
7729 @type QEvent
7730 @return flag indicating, if the event was handled
7731 @rtype bool
7732 """
7733 if evt.type() == QEvent.Type.Gesture:
7734 self.gestureEvent(evt)
7735 return True
7736
7737 return super().event(evt)
7738
7739 def gestureEvent(self, evt):
7740 """
7741 Protected method handling gesture events.
7742
7743 @param evt reference to the gesture event
7744 @type QGestureEvent
7745 """
7746 pinch = evt.gesture(Qt.GestureType.PinchGesture)
7747 if pinch:
7748 if pinch.state() == Qt.GestureState.GestureStarted:
7749 zoom = (self.getZoom() + 10) / 10.0
7750 pinch.setTotalScaleFactor(zoom)
7751 elif pinch.state() == Qt.GestureState.GestureUpdated:
7752 zoom = int(pinch.totalScaleFactor() * 10) - 10
7753 if zoom <= -9:
7754 zoom = -9
7755 pinch.setTotalScaleFactor(0.1)
7756 elif zoom >= 20:
7757 zoom = 20
7758 pinch.setTotalScaleFactor(3.0)
7759 self.zoomTo(zoom)
7760 evt.accept()
7761
7762 def resizeEvent(self, evt):
7763 """
7764 Protected method handling resize events.
7765
7766 @param evt reference to the resize event
7767 @type QResizeEvent
7768 """
7769 super().resizeEvent(evt)
7770 self.__markerMap.calculateGeometry()
7771
7772 def viewportEvent(self, evt):
7773 """
7774 Protected method handling event of the viewport.
7775
7776 @param evt reference to the event
7777 @type QEvent
7778 @return flag indiating that the event was handled
7779 @rtype bool
7780 """
7781 with contextlib.suppress(AttributeError):
7782 self.__markerMap.calculateGeometry()
7783 return super().viewportEvent(evt)
7784
7785 def __updateReadOnly(self, bForce=True):
7786 """
7787 Private method to update the readOnly information for this editor.
7788
7789 If bForce is True, then updates everything regardless if
7790 the attributes have actually changed, such as during
7791 initialization time. A signal is emitted after the
7792 caption change.
7793
7794 @param bForce True to force change, False to only update and emit
7795 signal if there was an attribute change.
7796 """
7797 if self.fileName == "" or not self.isLocalFile():
7798 return
7799
7800 readOnly = self.checkReadOnly()
7801 if not bForce and (readOnly == self.isReadOnly()):
7802 return
7803
7804 cap = self.fileName
7805 if readOnly:
7806 cap = self.tr("{0} (ro)".format(cap))
7807 self.setReadOnly(readOnly)
7808 self.setWindowTitle(cap)
7809 self.captionChanged.emit(cap, self)
7810
7811 def checkReadOnly(self):
7812 """
7813 Public method to check the 'read only' state.
7814
7815 @return flag indicate a 'read only' state
7816 @rtype bool
7817 """
7818 return (
7819 self.isLocalFile() and not os.access(self.fileName, os.W_OK)
7820 ) or self.isReadOnly()
7821 8175
7822 @pyqtSlot() 8176 @pyqtSlot()
7823 def refresh(self): 8177 def refresh(self):
7824 """ 8178 """
7825 Public slot to refresh the editor contents. 8179 Public slot to refresh the editor contents.
7847 self.close() 8201 self.close()
7848 return 8202 return
7849 8203
7850 # reread the file 8204 # reread the file
7851 try: 8205 try:
7852 self.readFile(self.fileName) 8206 self.readFile(self.fileName, noempty=True)
7853 except OSError: 8207 except OSError:
7854 # do not prompt for this change again... 8208 # do not prompt for this change again...
7855 self.lastModified = QDateTime.currentDateTime() 8209 self.lastModified = QDateTime.currentDateTime()
7856 self.setModified(False) 8210 self.setModified(False)
7857 self.__convertTabs() 8211 self.__convertTabs()
7878 8232
7879 def setMonospaced(self, on): 8233 def setMonospaced(self, on):
7880 """ 8234 """
7881 Public method to set/reset a monospaced font. 8235 Public method to set/reset a monospaced font.
7882 8236
7883 @param on flag to indicate usage of a monospace font (boolean) 8237 @param on flag to indicate usage of a monospace font
8238 @type bool
7884 """ 8239 """
7885 if on: 8240 if on:
7886 if not self.lexer_: 8241 if not self.lexer_:
7887 f = Preferences.getEditorOtherFonts("MonospacedFont") 8242 f = Preferences.getEditorOtherFonts("MonospacedFont")
7888 self.monospacedStyles(f) 8243 self.monospacedStyles(f)
7910 8265
7911 def dragEnterEvent(self, event): 8266 def dragEnterEvent(self, event):
7912 """ 8267 """
7913 Protected method to handle the drag enter event. 8268 Protected method to handle the drag enter event.
7914 8269
7915 @param event the drag enter event (QDragEnterEvent) 8270 @param event the drag enter event
8271 @type QDragEnterEvent
7916 """ 8272 """
7917 self.inDragDrop = event.mimeData().hasUrls() 8273 self.inDragDrop = event.mimeData().hasUrls()
7918 if self.inDragDrop: 8274 if self.inDragDrop:
7919 event.acceptProposedAction() 8275 event.acceptProposedAction()
7920 else: 8276 else:
7922 8278
7923 def dragMoveEvent(self, event): 8279 def dragMoveEvent(self, event):
7924 """ 8280 """
7925 Protected method to handle the drag move event. 8281 Protected method to handle the drag move event.
7926 8282
7927 @param event the drag move event (QDragMoveEvent) 8283 @param event the drag move event
8284 @type QDragMoveEvent
7928 """ 8285 """
7929 if self.inDragDrop: 8286 if self.inDragDrop:
7930 event.accept() 8287 event.accept()
7931 else: 8288 else:
7932 super().dragMoveEvent(event) 8289 super().dragMoveEvent(event)
7933 8290
7934 def dragLeaveEvent(self, event): 8291 def dragLeaveEvent(self, event):
7935 """ 8292 """
7936 Protected method to handle the drag leave event. 8293 Protected method to handle the drag leave event.
7937 8294
7938 @param event the drag leave event (QDragLeaveEvent) 8295 @param event the drag leave event
8296 @type QDragLeaveEvent
7939 """ 8297 """
7940 if self.inDragDrop: 8298 if self.inDragDrop:
7941 self.inDragDrop = False 8299 self.inDragDrop = False
7942 event.accept() 8300 event.accept()
7943 else: 8301 else:
7945 8303
7946 def dropEvent(self, event): 8304 def dropEvent(self, event):
7947 """ 8305 """
7948 Protected method to handle the drop event. 8306 Protected method to handle the drop event.
7949 8307
7950 @param event the drop event (QDropEvent) 8308 @param event the drop event
8309 @type QDropEvent
7951 """ 8310 """
7952 if event.mimeData().hasUrls(): 8311 if event.mimeData().hasUrls():
7953 for url in event.mimeData().urls(): 8312 for url in event.mimeData().urls():
7954 fname = url.toLocalFile() 8313 fname = url.toLocalFile()
7955 if fname: 8314 if fname:
7975 8334
7976 def __initContextMenuResources(self): 8335 def __initContextMenuResources(self):
7977 """ 8336 """
7978 Private method used to setup the Resources context sub menu. 8337 Private method used to setup the Resources context sub menu.
7979 8338
7980 @return reference to the generated menu (QMenu) 8339 @return reference to the generated menu
8340 @rtype QMenu
7981 """ 8341 """
7982 menu = QMenu(self.tr("Resources")) 8342 menu = QMenu(self.tr("Resources"))
7983 8343
7984 menu.addAction(self.tr("Add file..."), self.__addFileResource) 8344 menu.addAction(self.tr("Add file..."), self.__addFileResource)
7985 menu.addAction(self.tr("Add files..."), self.__addFileResources) 8345 menu.addAction(self.tr("Add files..."), self.__addFileResources)
8208 def editorCommand(self, cmd): 8568 def editorCommand(self, cmd):
8209 """ 8569 """
8210 Public method to perform a simple editor command. 8570 Public method to perform a simple editor command.
8211 8571
8212 @param cmd the scintilla command to be performed 8572 @param cmd the scintilla command to be performed
8573 @type int
8213 """ 8574 """
8214 if cmd == QsciScintilla.SCI_TAB: 8575 if cmd == QsciScintilla.SCI_TAB:
8215 try: 8576 try:
8216 templateViewer = ericApp().getObject("TemplateViewer") 8577 templateViewer = ericApp().getObject("TemplateViewer")
8217 except KeyError: 8578 except KeyError:
8269 8630
8270 def __applyTemplate(self, templateName, language): 8631 def __applyTemplate(self, templateName, language):
8271 """ 8632 """
8272 Private method to apply a template by name. 8633 Private method to apply a template by name.
8273 8634
8274 @param templateName name of the template to apply (string) 8635 @param templateName name of the template to apply
8636 @type str
8275 @param language name of the language (group) to get the template 8637 @param language name of the language (group) to get the template
8276 from (string) 8638 from
8639 @type str
8277 """ 8640 """
8278 try: 8641 try:
8279 templateViewer = ericApp().getObject("TemplateViewer") 8642 templateViewer = ericApp().getObject("TemplateViewer")
8280 except KeyError: 8643 except KeyError:
8281 # template viewer is not active 8644 # template viewer is not active
8358 8721
8359 def __setSpellingLanguage(self, language, pwl="", pel=""): 8722 def __setSpellingLanguage(self, language, pwl="", pel=""):
8360 """ 8723 """
8361 Private method to set the spell checking language. 8724 Private method to set the spell checking language.
8362 8725
8363 @param language spell checking language to be set (string) 8726 @param language spell checking language to be set
8364 @param pwl name of the personal/project word list (string) 8727 @type str
8365 @param pel name of the personal/project exclude list (string) 8728 @param pwl name of the personal/project word list
8729 @type str
8730 @param pel name of the personal/project exclude list
8731 @type str
8366 """ 8732 """
8367 if self.spell and self.spell.getLanguage() != language: 8733 if self.spell and self.spell.getLanguage() != language:
8368 self.spell.setLanguage(language, pwl=pwl, pel=pel) 8734 self.spell.setLanguage(language, pwl=pwl, pel=pel)
8369 self.spell.checkDocumentIncrementally() 8735 self.spell.checkDocumentIncrementally()
8370 8736
8601 Public method to get some share status info. 8967 Public method to get some share status info.
8602 8968
8603 @return tuple indicating, if the editor is sharable, the sharing 8969 @return tuple indicating, if the editor is sharable, the sharing
8604 status, if it is inside a locally initiated shared edit session 8970 status, if it is inside a locally initiated shared edit session
8605 and if it is inside a remotely initiated shared edit session 8971 and if it is inside a remotely initiated shared edit session
8606 (boolean, boolean, boolean, boolean) 8972 @rtype tuple of (bool, bool, bool, bool)
8607 """ 8973 """
8608 return ( 8974 return (
8609 ( 8975 (
8610 bool(self.fileName) 8976 bool(self.fileName)
8611 and self.project.isOpen() 8977 and self.project.isOpen()
8618 8984
8619 def shareConnected(self, connected): 8985 def shareConnected(self, connected):
8620 """ 8986 """
8621 Public method to handle a change of the connected state. 8987 Public method to handle a change of the connected state.
8622 8988
8623 @param connected flag indicating the connected state (boolean) 8989 @param connected flag indicating the connected state
8990 @type bool
8624 """ 8991 """
8625 if not connected: 8992 if not connected:
8626 self.__inRemoteSharedEdit = False 8993 self.__inRemoteSharedEdit = False
8627 self.setReadOnly(False) 8994 self.setReadOnly(False)
8628 self.__updateReadOnly() 8995 self.__updateReadOnly()
8632 8999
8633 def shareEditor(self, share): 9000 def shareEditor(self, share):
8634 """ 9001 """
8635 Public method to set the shared status of the editor. 9002 Public method to set the shared status of the editor.
8636 9003
8637 @param share flag indicating the share status (boolean) 9004 @param share flag indicating the share status
9005 @type bool
8638 """ 9006 """
8639 self.__isShared = share 9007 self.__isShared = share
8640 if not share: 9008 if not share:
8641 self.shareConnected(False) 9009 self.shareConnected(False)
8642 9010
8669 9037
8670 def cancelSharedEdit(self, send=True): 9038 def cancelSharedEdit(self, send=True):
8671 """ 9039 """
8672 Public method to cancel a shared edit session for the editor. 9040 Public method to cancel a shared edit session for the editor.
8673 9041
8674 @param send flag indicating to send the CancelEdit command (boolean) 9042 @param send flag indicating to send the CancelEdit command
9043 @type bool
8675 """ 9044 """
8676 self.__inSharedEdit = False 9045 self.__inSharedEdit = False
8677 self.__savedText = "" 9046 self.__savedText = ""
8678 if send: 9047 if send:
8679 self.__send(Editor.CancelEditToken) 9048 self.__send(Editor.CancelEditToken)
8680 9049
8681 def __send(self, token, args=None): 9050 def __send(self, token, args=None):
8682 """ 9051 """
8683 Private method to send an editor command to remote editors. 9052 Private method to send an editor command to remote editors.
8684 9053
8685 @param token command token (string) 9054 @param token command token
8686 @param args arguments for the command (string) 9055 @type str
9056 @param args arguments for the command
9057 @type str
8687 """ 9058 """
8688 if self.vm.isConnected(): 9059 if self.vm.isConnected():
8689 msg = "" 9060 msg = ""
8690 if token in ( 9061 if token in (
8691 Editor.StartEditToken, 9062 Editor.StartEditToken,
8717 9088
8718 def __dispatchCommand(self, command): 9089 def __dispatchCommand(self, command):
8719 """ 9090 """
8720 Private method to dispatch received commands. 9091 Private method to dispatch received commands.
8721 9092
8722 @param command command to be processed (string) 9093 @param command command to be processed
9094 @type str
8723 """ 9095 """
8724 token, argsString = command.split(Editor.Separator, 1) 9096 token, argsString = command.split(Editor.Separator, 1)
8725 if token == Editor.StartEditToken: 9097 if token == Editor.StartEditToken:
8726 self.__processStartEditCommand(argsString) 9098 self.__processStartEditCommand(argsString)
8727 elif token == Editor.CancelEditToken: 9099 elif token == Editor.CancelEditToken:
8760 def __calculateChanges(self, old, new): 9132 def __calculateChanges(self, old, new):
8761 """ 9133 """
8762 Private method to determine change commands to convert old text into 9134 Private method to determine change commands to convert old text into
8763 new text. 9135 new text.
8764 9136
8765 @param old old text (string) 9137 @param old old text
8766 @param new new text (string) 9138 @type str
8767 @return commands to change old into new (string) 9139 @param new new text
9140 @type str
9141 @return commands to change old into new
9142 @rtype str
8768 """ 9143 """
8769 oldL = old.splitlines() 9144 oldL = old.splitlines()
8770 newL = new.splitlines() 9145 newL = new.splitlines()
8771 matcher = difflib.SequenceMatcher(None, oldL, newL) 9146 matcher = difflib.SequenceMatcher(None, oldL, newL)
8772 9147
8892 9267
8893 def __searchCurrentWord(self, forward=True): 9268 def __searchCurrentWord(self, forward=True):
8894 """ 9269 """
8895 Private slot to search the next occurrence of the current word. 9270 Private slot to search the next occurrence of the current word.
8896 9271
8897 @param forward flag indicating the search direction (boolean) 9272 @param forward flag indicating the search direction
9273 @type bool
8898 """ 9274 """
8899 self.hideFindIndicator() 9275 self.hideFindIndicator()
8900 line, index = self.getCursorPosition() 9276 line, index = self.getCursorPosition()
8901 word = self.getCurrentWord() 9277 word = self.getCurrentWord()
8902 wordStart, wordEnd = self.getCurrentWordBoundaries() 9278 wordStart, wordEnd = self.getCurrentWordBoundaries()
8990 9366
8991 # step 3: sort the lines 9367 # step 3: sort the lines
8992 eol = self.getLineSeparator() 9368 eol = self.getLineSeparator()
8993 lastWithEol = True 9369 lastWithEol = True
8994 newLines = [] 9370 newLines = []
8995 for txt in sorted(selText.keys(), key=keyFun, reverse=reverse): 9371 for txt in sorted(selText, key=keyFun, reverse=reverse):
8996 for line in selText[txt]: 9372 for line in selText[txt]:
8997 txt = txtLines[line] 9373 txt = txtLines[line]
8998 if not txt.endswith(eol): 9374 if not txt.endswith(eol):
8999 lastWithEol = False 9375 lastWithEol = False
9000 txt += eol 9376 txt += eol
9133 a plug-in. 9509 a plug-in.
9134 9510
9135 @param name name of the plug-in 9511 @param name name of the plug-in
9136 @type str 9512 @type str
9137 """ 9513 """
9138 for key in list(self.__mouseClickHandlers.keys()): 9514 for key in list(self.__mouseClickHandlers):
9139 if self.__mouseClickHandlers[key][0] == name: 9515 if self.__mouseClickHandlers[key][0] == name:
9140 del self.__mouseClickHandlers[key] 9516 del self.__mouseClickHandlers[key]
9141 9517
9142 def gotoReferenceHandler(self, referencesList): 9518 def gotoReferenceHandler(self, referencesList):
9143 """ 9519 """
9223 @return EditorConfig dictionary 9599 @return EditorConfig dictionary
9224 @rtype dict 9600 @rtype dict
9225 """ 9601 """
9226 editorConfig = {} 9602 editorConfig = {}
9227 9603
9228 if fileName and self.isLocalFile(): 9604 if fileName and FileSystemUtilities.isPlainFileName(self.fileName):
9229 try: 9605 try:
9230 editorConfig = editorconfig.get_properties(fileName) 9606 editorConfig = editorconfig.get_properties(fileName)
9231 except editorconfig.EditorConfigError: 9607 except editorconfig.EditorConfigError:
9232 EricMessageBox.warning( 9608 EricMessageBox.warning(
9233 self, 9609 self,
9256 @type bool 9632 @type bool
9257 @param config reference to an EditorConfig object or None 9633 @param config reference to an EditorConfig object or None
9258 @type dict 9634 @type dict
9259 @return value of requested setting or None if nothing was found and 9635 @return value of requested setting or None if nothing was found and
9260 nodefault parameter was True 9636 nodefault parameter was True
9261 @rtype any 9637 @rtype Any
9262 """ 9638 """
9263 if config is None: 9639 if config is None:
9264 config = self.__editorConfig 9640 config = self.__editorConfig
9265 9641
9266 if not config: 9642 if not config:
9317 Public method to get the requested option via EditorConfig. 9693 Public method to get the requested option via EditorConfig.
9318 9694
9319 @param option Preferences option key 9695 @param option Preferences option key
9320 @type str 9696 @type str
9321 @return value of requested setting 9697 @return value of requested setting
9322 @rtype any 9698 @rtype Any
9323 """ 9699 """
9324 return self.__getEditorConfig(option) 9700 return self.__getEditorConfig(option)
9325 9701
9326 def __getOverrideValue(self, option): 9702 def __getOverrideValue(self, option):
9327 """ 9703 """
9328 Private method to get an override value for the current file type. 9704 Private method to get an override value for the current file type.
9329 9705
9330 @param option Preferences option key 9706 @param option Preferences option key
9331 @type str 9707 @type str
9332 @return override value; None in case nothing is defined 9708 @return override value; None in case nothing is defined
9333 @rtype any 9709 @rtype Any
9334 """ 9710 """
9335 if option in ("TabWidth", "IndentWidth"): 9711 if option in ("TabWidth", "IndentWidth"):
9336 overrides = Preferences.getEditor("TabIndentOverride") 9712 overrides = Preferences.getEditor("TabIndentOverride")
9337 language = self.filetype or self.apiLanguage 9713 language = self.filetype or self.apiLanguage
9338 if language in overrides: 9714 if language in overrides:

eric ide

mercurial