eric6/QScintilla/Editor.py

branch
maintenance
changeset 8273
698ae46f40a4
parent 8176
31965986ecd1
parent 8259
2bbec88047dd
child 8400
b3eefd7e58d1
equal deleted inserted replaced
8190:fb0ef164f536 8273:698ae46f40a4
8 """ 8 """
9 9
10 import os 10 import os
11 import re 11 import re
12 import difflib 12 import difflib
13 import contextlib
14
15 import editorconfig
13 16
14 from PyQt5.QtCore import ( 17 from PyQt5.QtCore import (
15 pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QFileInfo, 18 pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QFileInfo,
16 QCryptographicHash, QEvent, QDateTime, QPoint 19 QCryptographicHash, QEvent, QDateTime, QPoint
17 ) 20 )
35 import Preferences 38 import Preferences
36 import Utilities 39 import Utilities
37 from Utilities import MouseUtilities 40 from Utilities import MouseUtilities
38 41
39 import UI.PixmapCache 42 import UI.PixmapCache
40
41 from ThirdParty.EditorConfig import editorconfig
42 43
43 EditorAutoCompletionListID = 1 44 EditorAutoCompletionListID = 1
44 TemplateCompletionListID = 2 45 TemplateCompletionListID = 2
45 46
46 47
191 @type TaskViewer 192 @type TaskViewer
192 @param parent reference to the parent widget 193 @param parent reference to the parent widget
193 @type QWidget 194 @type QWidget
194 @exception OSError raised to indicate an issue accessing the file 195 @exception OSError raised to indicate an issue accessing the file
195 """ 196 """
196 super(Editor, self).__init__(parent) 197 super().__init__(parent)
197 self.setAttribute(Qt.WidgetAttribute.WA_KeyCompression) 198 self.setAttribute(Qt.WidgetAttribute.WA_KeyCompression)
198 self.setUtf8(True) 199 self.setUtf8(True)
199 200
200 self.dbs = dbs 201 self.dbs = dbs
201 self.taskViewer = tv 202 self.taskViewer = tv
686 elif self.filetype in ["Python", "Python3", "MicroPython"]: 687 elif self.filetype in ["Python", "Python3", "MicroPython"]:
687 bindName = "dummy.py" 688 bindName = "dummy.py"
688 689
689 if not bindName and line0.startswith("#!"): 690 if not bindName and line0.startswith("#!"):
690 # #! marker detection 691 # #! marker detection
691 if "python3" in line0: 692 if (
692 bindName = "dummy.py" 693 "python3" in line0 or
693 self.filetype = "Python3" 694 "python" in line0 or
694 elif "python" in line0: 695 "pypy3" in line0 or
695 bindName = "dummy.py" 696 "pypy" in line0
696 self.filetype = "Python3" 697 ):
697 elif "pypy3" in line0:
698 bindName = "dummy.py"
699 self.filetype = "Python3"
700 elif "pypy" in line0:
701 bindName = "dummy.py" 698 bindName = "dummy.py"
702 self.filetype = "Python3" 699 self.filetype = "Python3"
703 elif ("/bash" in line0 or "/sh" in line0): 700 elif ("/bash" in line0 or "/sh" in line0):
704 bindName = "dummy.sh" 701 bindName = "dummy.sh"
705 elif "ruby" in line0: 702 elif "ruby" in line0:
1615 1612
1616 def __checkEncoding(self): 1613 def __checkEncoding(self):
1617 """ 1614 """
1618 Private method to check the selected encoding of the encodings submenu. 1615 Private method to check the selected encoding of the encodings submenu.
1619 """ 1616 """
1620 try: 1617 with contextlib.suppress(AttributeError, KeyError):
1621 (self.supportedEncodings[self.__normalizedEncoding()] 1618 (self.supportedEncodings[self.__normalizedEncoding()]
1622 .setChecked(True)) 1619 .setChecked(True))
1623 except (AttributeError, KeyError):
1624 pass
1625 1620
1626 def __encodingChanged(self, encoding, propagate=True): 1621 def __encodingChanged(self, encoding, propagate=True):
1627 """ 1622 """
1628 Private slot to handle a change of the encoding. 1623 Private slot to handle a change of the encoding.
1629 1624
1672 1667
1673 def __checkEol(self): 1668 def __checkEol(self):
1674 """ 1669 """
1675 Private method to check the selected eol type of the eol submenu. 1670 Private method to check the selected eol type of the eol submenu.
1676 """ 1671 """
1677 try: 1672 with contextlib.suppress(AttributeError, TypeError):
1678 self.supportedEols[self.getLineSeparator()].setChecked(True) 1673 self.supportedEols[self.getLineSeparator()].setChecked(True)
1679 except (AttributeError, TypeError):
1680 pass
1681 1674
1682 def __eolChanged(self): 1675 def __eolChanged(self):
1683 """ 1676 """
1684 Private slot to handle a change of the eol mode. 1677 Private slot to handle a change of the eol mode.
1685 """ 1678 """
1712 def __checkSpellLanguage(self): 1705 def __checkSpellLanguage(self):
1713 """ 1706 """
1714 Private slot to check the selected spell check language action. 1707 Private slot to check the selected spell check language action.
1715 """ 1708 """
1716 language = self.getSpellingLanguage() 1709 language = self.getSpellingLanguage()
1717 try: 1710 with contextlib.suppress(AttributeError, KeyError):
1718 self.supportedSpellLanguages[language].setChecked(True) 1711 self.supportedSpellLanguages[language].setChecked(True)
1719 except (AttributeError, KeyError):
1720 pass
1721 1712
1722 def __spellLanguageChanged(self, language, propagate=True): 1713 def __spellLanguageChanged(self, language, propagate=True):
1723 """ 1714 """
1724 Private slot to handle a change of the spell check language. 1715 Private slot to handle a change of the spell check language.
1725 1716
1811 self.__setMarginsDisplay() 1802 self.__setMarginsDisplay()
1812 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None: 1803 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None:
1813 self.SCN_STYLENEEDED.connect(self.__styleNeeded) 1804 self.SCN_STYLENEEDED.connect(self.__styleNeeded)
1814 1805
1815 # get the font for style 0 and set it as the default font 1806 # get the font for style 0 and set it as the default font
1816 if pyname and pyname.startswith("Pygments|"): 1807 key = (
1817 key = 'Scintilla/Guessed/style0/font' 1808 'Scintilla/Guessed/style0/font'
1818 else: 1809 if pyname and pyname.startswith("Pygments|") else
1819 key = 'Scintilla/{0}/style0/font'.format(self.lexer_.language()) 1810 'Scintilla/{0}/style0/font'.format(self.lexer_.language())
1811 )
1820 fdesc = Preferences.Prefs.settings.value(key) 1812 fdesc = Preferences.Prefs.settings.value(key)
1821 if fdesc is not None: 1813 if fdesc is not None:
1822 font = QFont(fdesc[0], int(fdesc[1])) 1814 font = QFont(fdesc[0], int(fdesc[1]))
1823 self.lexer_.setDefaultFont(font) 1815 self.lexer_.setDefaultFont(font)
1824 self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla") 1816 self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
1827 1819
1828 # now set the lexer properties 1820 # now set the lexer properties
1829 self.lexer_.initProperties() 1821 self.lexer_.initProperties()
1830 1822
1831 # initialize the lexer APIs settings 1823 # initialize the lexer APIs settings
1832 if self.project.isOpen() and self.project.isProjectFile(filename): 1824 projectType = (
1833 projectType = self.project.getProjectType() 1825 self.project.getProjectType()
1834 else: 1826 if self.project.isOpen() and self.project.isProjectFile(filename)
1835 projectType = "" 1827 else ""
1828 )
1836 api = self.vm.getAPIsManager().getAPIs(self.apiLanguage, 1829 api = self.vm.getAPIsManager().getAPIs(self.apiLanguage,
1837 projectType=projectType) 1830 projectType=projectType)
1838 if api is not None and not api.isEmpty(): 1831 if api is not None and not api.isEmpty():
1839 self.lexer_.setAPIs(api.getQsciAPIs()) 1832 self.lexer_.setAPIs(api.getQsciAPIs())
1840 self.acAPI = True 1833 self.acAPI = True
2163 @return flag indicating a Javascript file (boolean) 2156 @return flag indicating a Javascript file (boolean)
2164 """ 2157 """
2165 if self.filetype == "JavaScript": 2158 if self.filetype == "JavaScript":
2166 return True 2159 return True
2167 2160
2168 if self.filetype == "": 2161 if (
2169 if ( 2162 self.filetype == "" and
2170 self.fileName and 2163 self.fileName and
2171 os.path.splitext(self.fileName)[1] == ".js" 2164 os.path.splitext(self.fileName)[1] == ".js"
2172 ): 2165 ):
2173 self.filetype = "JavaScript" 2166 self.filetype = "JavaScript"
2174 return True 2167 return True
2175 2168
2176 return False 2169 return False
2177 2170
2178 def highlightVisible(self): 2171 def highlightVisible(self):
2179 """ 2172 """
2246 @param annotationLinesAdded number of added/deleted annotation lines 2239 @param annotationLinesAdded number of added/deleted annotation lines
2247 (integer) 2240 (integer)
2248 """ 2241 """
2249 if ( 2242 if (
2250 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) and 2243 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) and
2251 linesAdded != 0 2244 linesAdded != 0 and
2245 self.breaks
2252 ): 2246 ):
2253 if self.breaks: 2247 bps = [] # list of breakpoints
2254 bps = [] # list of breakpoints 2248 for handle, (ln, cond, temp, enabled, ignorecount) in (
2255 for handle, (ln, cond, temp, enabled, ignorecount) in ( 2249 self.breaks.items()
2256 self.breaks.items() 2250 ):
2257 ): 2251 line = self.markerLine(handle) + 1
2258 line = self.markerLine(handle) + 1 2252 if ln != line:
2259 if ln != line: 2253 bps.append((ln, line))
2260 bps.append((ln, line)) 2254 self.breaks[handle] = (line, cond, temp, enabled,
2261 self.breaks[handle] = (line, cond, temp, enabled, 2255 ignorecount)
2262 ignorecount) 2256 self.inLinesChanged = True
2263 self.inLinesChanged = True 2257 for ln, line in sorted(bps, reverse=linesAdded > 0):
2264 for ln, line in sorted(bps, reverse=linesAdded > 0): 2258 index1 = self.breakpointModel.getBreakPointIndex(
2265 index1 = self.breakpointModel.getBreakPointIndex( 2259 self.fileName, ln)
2266 self.fileName, ln) 2260 index2 = self.breakpointModel.index(index1.row(), 1)
2267 index2 = self.breakpointModel.index(index1.row(), 1) 2261 self.breakpointModel.setData(index2, line)
2268 self.breakpointModel.setData(index2, line) 2262 self.inLinesChanged = False
2269 self.inLinesChanged = False
2270 2263
2271 def __restoreBreakpoints(self): 2264 def __restoreBreakpoints(self):
2272 """ 2265 """
2273 Private method to restore the breakpoints. 2266 Private method to restore the breakpoints.
2274 """ 2267 """
2847 self.markerDeleteAll(self.taskmarker) 2840 self.markerDeleteAll(self.taskmarker)
2848 self.taskViewer.clearFileTasks(self.fileName) 2841 self.taskViewer.clearFileTasks(self.fileName)
2849 self.__hasTaskMarkers = False 2842 self.__hasTaskMarkers = False
2850 2843
2851 # now search tasks and record them 2844 # now search tasks and record them
2852 lineIndex = -1 2845 for lineIndex, line in enumerate(txtList):
2853 for line in txtList:
2854 lineIndex += 1
2855 shouldBreak = False 2846 shouldBreak = False
2856 2847
2857 if line.endswith("__NO-TASK__"): 2848 if line.endswith("__NO-TASK__"):
2858 # ignore potential task marker 2849 # ignore potential task marker
2859 continue 2850 continue
3254 permissions = os.stat(fn).st_mode 3245 permissions = os.stat(fn).st_mode
3255 perms_valid = True 3246 perms_valid = True
3256 except OSError: 3247 except OSError:
3257 # if there was an error, ignore it 3248 # if there was an error, ignore it
3258 perms_valid = False 3249 perms_valid = False
3259 try: 3250 with contextlib.suppress(OSError):
3260 os.remove(bfn) 3251 os.remove(bfn)
3261 except OSError: 3252 with contextlib.suppress(OSError):
3262 # if there was an error, ignore it
3263 pass
3264 try:
3265 os.rename(fn, bfn) 3253 os.rename(fn, bfn)
3266 except OSError:
3267 # if there was an error, ignore it
3268 pass
3269 3254
3270 # now write text to the file fn 3255 # now write text to the file fn
3271 try: 3256 try:
3272 editorConfigEncoding = self.__getEditorConfig( 3257 editorConfigEncoding = self.__getEditorConfig(
3273 "DefaultEncoding", nodefault=True, config=config) 3258 "DefaultEncoding", nodefault=True, config=config)
3297 if ( 3282 if (
3298 self.fileName and 3283 self.fileName and
3299 self.project.startswithProjectPath(self.fileName) 3284 self.project.startswithProjectPath(self.fileName)
3300 ): 3285 ):
3301 path = os.path.dirname(self.fileName) 3286 path = os.path.dirname(self.fileName)
3302 else: 3287 elif not self.fileName:
3303 path = self.project.getProjectPath() 3288 path = self.project.getProjectPath()
3304 3289
3305 if not path and self.fileName: 3290 if not path and self.fileName:
3306 path = os.path.dirname(self.fileName) 3291 path = os.path.dirname(self.fileName)
3307 if not path: 3292 if not path:
3362 fn = self.__getSaveFileName(path) 3347 fn = self.__getSaveFileName(path)
3363 if not fn: 3348 if not fn:
3364 return False 3349 return False
3365 3350
3366 res = self.writeFile(fn) 3351 res = self.writeFile(fn)
3367 if res: 3352 if (
3353 res and
3354 self.project.isOpen() and
3355 self.project.startswithProjectPath(fn)
3356 ):
3368 # save to project, if a project is loaded 3357 # save to project, if a project is loaded
3369 if ( 3358 self.project.appendFile(fn)
3370 self.project.isOpen() and
3371 self.project.startswithProjectPath(fn)
3372 ):
3373 self.project.appendFile(fn)
3374 3359
3375 return res 3360 return res
3376 3361
3377 def saveFile(self, saveas=False, path=None): 3362 def saveFile(self, saveas=False, path=None):
3378 """ 3363 """
3582 if wc is None or not useWordChars: 3567 if wc is None or not useWordChars:
3583 pattern = r"\b[\w_]+\b" 3568 pattern = r"\b[\w_]+\b"
3584 else: 3569 else:
3585 wc = re.sub(r'\w', "", wc) 3570 wc = re.sub(r'\w', "", wc)
3586 pattern = r"\b[\w{0}]+\b".format(re.escape(wc)) 3571 pattern = r"\b[\w{0}]+\b".format(re.escape(wc))
3587 if self.caseSensitive(): 3572 rx = (
3588 rx = re.compile(pattern) 3573 re.compile(pattern)
3589 else: 3574 if self.caseSensitive() else
3590 rx = re.compile(pattern, re.IGNORECASE) 3575 re.compile(pattern, re.IGNORECASE)
3576 )
3591 3577
3592 text = self.text(line) 3578 text = self.text(line)
3593 for match in rx.finditer(text): 3579 for match in rx.finditer(text):
3594 start, end = match.span() 3580 start, end = match.span()
3595 if start <= index <= end: 3581 if start <= index <= end:
3691 3677
3692 pos = self.positionBefore(pos) 3678 pos = self.positionBefore(pos)
3693 ch = self.charAt(pos) 3679 ch = self.charAt(pos)
3694 3680
3695 # Don't go past the end of the previous line 3681 # Don't go past the end of the previous line
3696 if ch == '\n' or ch == '\r': 3682 if ch in ('\n', '\r'):
3697 return "", pos 3683 return "", pos
3698 3684
3699 return ch, pos 3685 return ch, pos
3700 3686
3701 def getSearchText(self, selectionOnly=False): 3687 def getSearchText(self, selectionOnly=False):
3897 line, index = self.getCursorPosition() 3883 line, index = self.getCursorPosition()
3898 self.beginUndoAction() 3884 self.beginUndoAction()
3899 if Preferences.getEditor("CommentColumn0"): 3885 if Preferences.getEditor("CommentColumn0"):
3900 self.insertAt(self.lexer_.commentStr(), line, 0) 3886 self.insertAt(self.lexer_.commentStr(), line, 0)
3901 else: 3887 else:
3902 self.insertAt(self.lexer_.commentStr(), line, 3888 lineText = self.text(line)
3903 self.indentation(line)) 3889 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
3890 self.insertAt(self.lexer_.commentStr(), line, pos)
3904 self.endUndoAction() 3891 self.endUndoAction()
3905 3892
3906 def uncommentLine(self): 3893 def uncommentLine(self):
3907 """ 3894 """
3908 Public slot to uncomment the current line. 3895 Public slot to uncomment the current line.
3921 # now remove the comment string 3908 # now remove the comment string
3922 self.beginUndoAction() 3909 self.beginUndoAction()
3923 if Preferences.getEditor("CommentColumn0"): 3910 if Preferences.getEditor("CommentColumn0"):
3924 self.setSelection(line, 0, line, len(commentStr)) 3911 self.setSelection(line, 0, line, len(commentStr))
3925 else: 3912 else:
3926 self.setSelection(line, self.indentation(line), 3913 lineText = self.text(line)
3927 line, self.indentation(line) + len(commentStr)) 3914 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
3915 self.setSelection(line, pos, line, pos + len(commentStr))
3928 self.removeSelectedText() 3916 self.removeSelectedText()
3929 self.endUndoAction() 3917 self.endUndoAction()
3930 3918
3931 def commentSelection(self): 3919 def commentSelection(self):
3932 """ 3920 """
3940 3928
3941 commentStr = self.lexer_.commentStr() 3929 commentStr = self.lexer_.commentStr()
3942 3930
3943 # get the selection boundaries 3931 # get the selection boundaries
3944 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 3932 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
3945 if indexTo == 0: 3933 endLine = lineTo if indexTo else lineTo - 1
3946 endLine = lineTo - 1
3947 else:
3948 endLine = lineTo
3949 3934
3950 self.beginUndoAction() 3935 self.beginUndoAction()
3951 # iterate over the lines 3936 # iterate over the lines
3952 for line in range(lineFrom, endLine + 1): 3937 for line in range(lineFrom, endLine + 1):
3953 if Preferences.getEditor("CommentColumn0"): 3938 if Preferences.getEditor("CommentColumn0"):
3954 self.insertAt(commentStr, line, 0) 3939 self.insertAt(commentStr, line, 0)
3955 else: 3940 else:
3956 self.insertAt(commentStr, line, self.indentation(line)) 3941 lineText = self.text(line)
3942 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
3943 self.insertAt(commentStr, line, pos)
3957 3944
3958 # change the selection accordingly 3945 # change the selection accordingly
3959 self.setSelection(lineFrom, 0, endLine + 1, 0) 3946 self.setSelection(lineFrom, 0, endLine + 1, 0)
3960 self.endUndoAction() 3947 self.endUndoAction()
3961 3948
3971 3958
3972 commentStr = self.lexer_.commentStr() 3959 commentStr = self.lexer_.commentStr()
3973 3960
3974 # get the selection boundaries 3961 # get the selection boundaries
3975 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 3962 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
3976 if indexTo == 0: 3963 endLine = lineTo if indexTo else lineTo - 1
3977 endLine = lineTo - 1
3978 else:
3979 endLine = lineTo
3980 3964
3981 self.beginUndoAction() 3965 self.beginUndoAction()
3982 # iterate over the lines 3966 # iterate over the lines
3983 for line in range(lineFrom, endLine + 1): 3967 for line in range(lineFrom, endLine + 1):
3984 # check if line starts with our comment string (i.e. was commented 3968 # check if line starts with our comment string (i.e. was commented
3987 continue 3971 continue
3988 3972
3989 if Preferences.getEditor("CommentColumn0"): 3973 if Preferences.getEditor("CommentColumn0"):
3990 self.setSelection(line, 0, line, len(commentStr)) 3974 self.setSelection(line, 0, line, len(commentStr))
3991 else: 3975 else:
3992 self.setSelection(line, 3976 lineText = self.text(line)
3993 self.indentation(line), 3977 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
3994 line, 3978 self.setSelection(line, pos, line, pos + len(commentStr))
3995 self.indentation(line) + len(commentStr))
3996 self.removeSelectedText() 3979 self.removeSelectedText()
3997 3980
3998 # adjust selection start 3981 # adjust selection start
3999 if line == lineFrom: 3982 if line == lineFrom:
4000 indexFrom -= len(commentStr) 3983 indexFrom -= len(commentStr)
4117 4100
4118 commentStr = self.lexer_.boxCommentStr() 4101 commentStr = self.lexer_.boxCommentStr()
4119 4102
4120 # get the selection boundaries 4103 # get the selection boundaries
4121 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4104 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4122 if indexTo == 0: 4105 endLine = lineTo if indexTo else lineTo - 1
4123 endLine = lineTo - 1
4124 else:
4125 endLine = lineTo
4126 4106
4127 self.beginUndoAction() 4107 self.beginUndoAction()
4128 # iterate over the lines 4108 # iterate over the lines
4129 for line in range(lineFrom, endLine + 1): 4109 for line in range(lineFrom, endLine + 1):
4130 self.insertAt(commentStr['middle'], line, 0) 4110 self.insertAt(commentStr['middle'], line, 0)
4184 if not self.hasSelectedText(): 4164 if not self.hasSelectedText():
4185 return 4165 return
4186 4166
4187 # get the selection 4167 # get the selection
4188 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4168 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4189 4169 endLine = lineTo if indexTo else lineTo - 1
4190 if indexTo == 0:
4191 endLine = lineTo - 1
4192 else:
4193 endLine = lineTo
4194 4170
4195 self.beginUndoAction() 4171 self.beginUndoAction()
4196 # iterate over the lines 4172 # iterate over the lines
4197 for line in range(lineFrom, endLine + 1): 4173 for line in range(lineFrom, endLine + 1):
4198 if indent: 4174 if indent:
4546 4522
4547 # set folding margin settings 4523 # set folding margin settings
4548 if Preferences.getEditor("FoldingMargin"): 4524 if Preferences.getEditor("FoldingMargin"):
4549 self.setMarginWidth(self.__foldMargin, 16) 4525 self.setMarginWidth(self.__foldMargin, 16)
4550 folding = Preferences.getEditor("FoldingStyle") 4526 folding = Preferences.getEditor("FoldingStyle")
4551 try: 4527 with contextlib.suppress(AttributeError):
4552 folding = QsciScintilla.FoldStyle(folding) 4528 folding = QsciScintilla.FoldStyle(folding)
4553 except AttributeError:
4554 pass
4555 self.setFolding(folding, self.__foldMargin) 4529 self.setFolding(folding, self.__foldMargin)
4556 self.setFoldMarginColors( 4530 self.setFoldMarginColors(
4557 Preferences.getEditorColour("FoldmarginBackground"), 4531 Preferences.getEditorColour("FoldmarginBackground"),
4558 Preferences.getEditorColour("FoldmarginBackground")) 4532 Preferences.getEditorColour("FoldmarginBackground"))
4559 self.setFoldMarkersColors( 4533 self.setFoldMarkersColors(
4599 self.setIndentationGuidesForegroundColor( 4573 self.setIndentationGuidesForegroundColor(
4600 Preferences.getEditorColour("IndentationGuidesForeground")) 4574 Preferences.getEditorColour("IndentationGuidesForeground"))
4601 if Preferences.getEditor("ShowWhitespace"): 4575 if Preferences.getEditor("ShowWhitespace"):
4602 self.setWhitespaceVisibility( 4576 self.setWhitespaceVisibility(
4603 QsciScintilla.WhitespaceVisibility.WsVisible) 4577 QsciScintilla.WhitespaceVisibility.WsVisible)
4604 try: 4578 with contextlib.suppress(AttributeError):
4605 self.setWhitespaceForegroundColor( 4579 self.setWhitespaceForegroundColor(
4606 Preferences.getEditorColour("WhitespaceForeground")) 4580 Preferences.getEditorColour("WhitespaceForeground"))
4607 self.setWhitespaceBackgroundColor( 4581 self.setWhitespaceBackgroundColor(
4608 Preferences.getEditorColour("WhitespaceBackground")) 4582 Preferences.getEditorColour("WhitespaceBackground"))
4609 self.setWhitespaceSize( 4583 self.setWhitespaceSize(
4610 Preferences.getEditor("WhitespaceSize")) 4584 Preferences.getEditor("WhitespaceSize"))
4611 except AttributeError:
4612 # QScintilla before 2.5 doesn't support this
4613 pass
4614 else: 4585 else:
4615 self.setWhitespaceVisibility( 4586 self.setWhitespaceVisibility(
4616 QsciScintilla.WhitespaceVisibility.WsInvisible) 4587 QsciScintilla.WhitespaceVisibility.WsInvisible)
4617 self.setEolVisibility(Preferences.getEditor("ShowEOL")) 4588 self.setEolVisibility(Preferences.getEditor("ShowEOL"))
4618 self.setAutoIndent(Preferences.getEditor("AutoIndentation")) 4589 self.setAutoIndent(Preferences.getEditor("AutoIndentation"))
4694 self.highlightIndicator, QsciScintilla.INDIC_FULLBOX, 4665 self.highlightIndicator, QsciScintilla.INDIC_FULLBOX,
4695 Preferences.getEditorColour("HighlightMarker")) 4666 Preferences.getEditorColour("HighlightMarker"))
4696 4667
4697 self.setCursorFlashTime(QApplication.cursorFlashTime()) 4668 self.setCursorFlashTime(QApplication.cursorFlashTime())
4698 4669
4699 try: 4670 with contextlib.suppress(AttributeError):
4700 if Preferences.getEditor("AnnotationsEnabled"): 4671 if Preferences.getEditor("AnnotationsEnabled"):
4701 self.setAnnotationDisplay( 4672 self.setAnnotationDisplay(
4702 QsciScintilla.AnnotationDisplay.AnnotationBoxed) 4673 QsciScintilla.AnnotationDisplay.AnnotationBoxed)
4703 else: 4674 else:
4704 self.setAnnotationDisplay( 4675 self.setAnnotationDisplay(
4705 QsciScintilla.AnnotationDisplay.AnnotationHidden) 4676 QsciScintilla.AnnotationDisplay.AnnotationHidden)
4706 except AttributeError:
4707 pass
4708 self.__setAnnotationStyles() 4677 self.__setAnnotationStyles()
4709 4678
4710 if Preferences.getEditor("OverrideEditAreaColours"): 4679 if Preferences.getEditor("OverrideEditAreaColours"):
4711 self.setColor(Preferences.getEditorColour("EditAreaForeground")) 4680 self.setColor(Preferences.getEditorColour("EditAreaForeground"))
4712 self.setPaper(Preferences.getEditorColour("EditAreaBackground")) 4681 self.setPaper(Preferences.getEditorColour("EditAreaBackground"))
4787 Preferences.getEditorColour("CallTipsForeground")) 4756 Preferences.getEditorColour("CallTipsForeground"))
4788 self.setCallTipsHighlightColor( 4757 self.setCallTipsHighlightColor(
4789 Preferences.getEditorColour("CallTipsHighlight")) 4758 Preferences.getEditorColour("CallTipsHighlight"))
4790 self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible")) 4759 self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible"))
4791 calltipsStyle = Preferences.getEditor("CallTipsStyle") 4760 calltipsStyle = Preferences.getEditor("CallTipsStyle")
4792 try: 4761 with contextlib.suppress(AttributeError):
4793 self.setCallTipsPosition( 4762 self.setCallTipsPosition(
4794 Preferences.getEditor("CallTipsPosition")) 4763 Preferences.getEditor("CallTipsPosition"))
4795 except AttributeError:
4796 pass
4797 4764
4798 if Preferences.getEditor("CallTipsEnabled"): 4765 if Preferences.getEditor("CallTipsEnabled"):
4799 if calltipsStyle == QsciScintilla.CallTipsStyle.CallTipsNoContext: 4766 if calltipsStyle == QsciScintilla.CallTipsStyle.CallTipsNoContext:
4800 self.setCallTipsStyle( 4767 self.setCallTipsStyle(
4801 QsciScintilla.CallTipsStyle.CallTipsNoContext) 4768 QsciScintilla.CallTipsStyle.CallTipsNoContext)
4942 """ 4909 """
4943 if self.lexer_ is None: 4910 if self.lexer_ is None:
4944 return False 4911 return False
4945 4912
4946 wseps = self.lexer_.autoCompletionWordSeparators() 4913 wseps = self.lexer_.autoCompletionWordSeparators()
4947 for wsep in wseps: 4914 return any(wsep.endswith(ch) for wsep in wseps)
4948 if wsep.endswith(ch):
4949 return True
4950
4951 return False
4952 4915
4953 def __autocompletionCancelled(self): 4916 def __autocompletionCancelled(self):
4954 """ 4917 """
4955 Private slot to handle the cancellation of an auto-completion list. 4918 Private slot to handle the cancellation of an auto-completion list.
4956 """ 4919 """
5046 self.__acTimer.stop() 5009 self.__acTimer.stop()
5047 self.__acContext = context 5010 self.__acContext = context
5048 self.__acTimer.start() 5011 self.__acTimer.start()
5049 else: 5012 else:
5050 self.__autoComplete(auto, context) 5013 self.__autoComplete(auto, context)
5051 elif not auto:
5052 self.autoCompleteQScintilla()
5053 elif ( 5014 elif (
5054 self.autoCompletionSource() != 5015 not auto or
5055 QsciScintilla.AutoCompletionSource.AcsNone 5016 (self.autoCompletionSource() !=
5017 QsciScintilla.AutoCompletionSource.AcsNone)
5056 ): 5018 ):
5057 self.autoCompleteQScintilla() 5019 self.autoCompleteQScintilla()
5058 5020
5059 def __getAcText(self): 5021 def __getAcText(self):
5060 """ 5022 """
5064 @rtype str 5026 @rtype str
5065 """ 5027 """
5066 line, col = self.getCursorPosition() 5028 line, col = self.getCursorPosition()
5067 text = self.text(line) 5029 text = self.text(line)
5068 try: 5030 try:
5069 if self.__isStartChar(text[col - 1]): 5031 acText = (
5070 acText = self.getWordLeft(line, col - 1) + text[col - 1] 5032 self.getWordLeft(line, col - 1) + text[col - 1]
5071 else: 5033 if self.__isStartChar(text[col - 1]) else
5072 acText = self.getWordLeft(line, col) 5034 self.getWordLeft(line, col)
5035 )
5073 except IndexError: 5036 except IndexError:
5074 acText = "" 5037 acText = ""
5075 5038
5076 return acText 5039 return acText
5077 5040
5089 5052
5090 # Suppress empty completions 5053 # Suppress empty completions
5091 if auto and self.__acText == '': 5054 if auto and self.__acText == '':
5092 return 5055 return
5093 5056
5094 if self.__acCacheEnabled: 5057 completions = (
5095 completions = self.__acCache.get(self.__acText) 5058 self.__acCache.get(self.__acText)
5096 else: 5059 if self.__acCacheEnabled else
5097 completions = None 5060 None
5061 )
5098 if completions is not None: 5062 if completions is not None:
5099 # show list with cached entries 5063 # show list with cached entries
5100 if self.isListActive(): 5064 if self.isListActive():
5101 self.cancelList() 5065 self.cancelList()
5102 5066
5169 Private method to show the completions list. 5133 Private method to show the completions list.
5170 5134
5171 @param completions completions to be shown 5135 @param completions completions to be shown
5172 @type list of str or set of str 5136 @type list of str or set of str
5173 """ 5137 """
5174 if Preferences.getEditor("AutoCompletionReversedList"): 5138 acCompletions = (
5175 acCompletions = sorted( 5139 sorted(
5176 list(completions), 5140 list(completions),
5177 key=self.__replaceLeadingUnderscores) 5141 key=self.__replaceLeadingUnderscores)
5178 else: 5142 if Preferences.getEditor("AutoCompletionReversedList") else
5179 acCompletions = sorted(list(completions)) 5143 sorted(list(completions))
5144 )
5180 self.showUserList(EditorAutoCompletionListID, acCompletions) 5145 self.showUserList(EditorAutoCompletionListID, acCompletions)
5181 5146
5182 def __replaceLeadingUnderscores(self, txt): 5147 def __replaceLeadingUnderscores(self, txt):
5183 """ 5148 """
5184 Private method to replace the first two underlines for invers sorting. 5149 Private method to replace the first two underlines for invers sorting.
5313 Public method to show calltips. 5278 Public method to show calltips.
5314 """ 5279 """
5315 if bool(self.__ctHookFunctions): 5280 if bool(self.__ctHookFunctions):
5316 self.__callTip() 5281 self.__callTip()
5317 else: 5282 else:
5318 super(Editor, self).callTip() 5283 super().callTip()
5319 5284
5320 def __callTip(self): 5285 def __callTip(self):
5321 """ 5286 """
5322 Private method to show call tips provided by a plugin. 5287 Private method to show call tips provided by a plugin.
5323 """ 5288 """
5354 self.SendScintilla(QsciScintilla.SCI_CALLTIPCANCEL) 5319 self.SendScintilla(QsciScintilla.SCI_CALLTIPCANCEL)
5355 5320
5356 if not found: 5321 if not found:
5357 return 5322 return
5358 5323
5324 callTips = []
5359 if self.__ctHookFunctions: 5325 if self.__ctHookFunctions:
5360 callTips = []
5361 for key in self.__ctHookFunctions: 5326 for key in self.__ctHookFunctions:
5362 callTips.extend(self.__ctHookFunctions[key](self, pos, commas)) 5327 callTips.extend(self.__ctHookFunctions[key](self, pos, commas))
5363 callTips = list(set(callTips)) 5328 callTips = list(set(callTips))
5364 callTips.sort() 5329 callTips.sort()
5330 else:
5331 # try QScintilla calltips
5332 super().callTip()
5333 return
5365 if len(callTips) == 0: 5334 if len(callTips) == 0:
5366 if Preferences.getEditor("CallTipsScintillaOnFail"): 5335 if Preferences.getEditor("CallTipsScintillaOnFail"):
5367 # try QScintilla calltips 5336 # try QScintilla calltips
5368 super(Editor, self).callTip() 5337 super().callTip()
5369 return 5338 return
5370 5339
5371 ctshift = 0 5340 ctshift = 0
5372 for ct in callTips: 5341 for ct in callTips:
5373 shift = ct.index("(") 5342 shift = ct.index("(")
5374 if ctshift < shift: 5343 if ctshift < shift:
5375 ctshift = shift 5344 ctshift = shift
5376 5345
5377 cv = self.callTipsVisible() 5346 cv = self.callTipsVisible()
5378 if cv > 0: 5347 ct = (
5379 # this is just a safe guard 5348 # this is just a safe guard
5380 ct = self._encodeString("\n".join(callTips[:cv])) 5349 self._encodeString("\n".join(callTips[:cv]))
5381 else: 5350 if cv > 0 else
5382 # until here and unindent below 5351 # until here and unindent below
5383 ct = self._encodeString("\n".join(callTips)) 5352 self._encodeString("\n".join(callTips))
5353 )
5384 5354
5385 self.SendScintilla(QsciScintilla.SCI_CALLTIPSHOW, 5355 self.SendScintilla(QsciScintilla.SCI_CALLTIPSHOW,
5386 self.__adjustedCallTipPosition(ctshift, pos), ct) 5356 self.__adjustedCallTipPosition(ctshift, pos), ct)
5387 if b'\n' in ct: 5357 if b'\n' in ct:
5388 return 5358 return
5432 QsciScintilla.SCI_POSITIONFROMLINE, 5402 QsciScintilla.SCI_POSITIONFROMLINE,
5433 self.SendScintilla(QsciScintilla.SCI_LINEFROMPOSITION, ct)) 5403 self.SendScintilla(QsciScintilla.SCI_LINEFROMPOSITION, ct))
5434 if ct - ctshift < ctmin: 5404 if ct - ctshift < ctmin:
5435 ct = ctmin 5405 ct = ctmin
5436 else: 5406 else:
5437 ct = ct - ctshift 5407 ct -= ctshift
5438 return ct 5408 return ct
5439 5409
5440 ################################################################# 5410 #################################################################
5441 ## Methods needed by the code documentation viewer 5411 ## Methods needed by the code documentation viewer
5442 ################################################################# 5412 #################################################################
5536 else: 5506 else:
5537 self.menuActs["Comment"].setEnabled(False) 5507 self.menuActs["Comment"].setEnabled(False)
5538 self.menuActs["Uncomment"].setEnabled(False) 5508 self.menuActs["Uncomment"].setEnabled(False)
5539 self.menuActs["StreamComment"].setEnabled(False) 5509 self.menuActs["StreamComment"].setEnabled(False)
5540 self.menuActs["BoxComment"].setEnabled(False) 5510 self.menuActs["BoxComment"].setEnabled(False)
5511
5512 cline = self.getCursorPosition()[0]
5513 line = self.text(cline)
5514 self.menuActs["Docstring"].setEnabled(
5515 self.getDocstringGenerator().isFunctionStart(line))
5541 5516
5542 self.menuActs["TypingAidsEnabled"].setEnabled( 5517 self.menuActs["TypingAidsEnabled"].setEnabled(
5543 self.completer is not None) 5518 self.completer is not None)
5544 self.menuActs["TypingAidsEnabled"].setChecked( 5519 self.menuActs["TypingAidsEnabled"].setChecked(
5545 self.completer is not None and self.completer.isEnabled()) 5520 self.completer is not None and self.completer.isEnabled())
5573 else: 5548 else:
5574 self.menuActs["NewSplit"].setIcon( 5549 self.menuActs["NewSplit"].setIcon(
5575 UI.PixmapCache.getIcon("splitVertical")) 5550 UI.PixmapCache.getIcon("splitVertical"))
5576 5551
5577 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty()) 5552 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty())
5578
5579 cline = self.getCursorPosition()[0]
5580 line = self.text(cline)
5581 self.menuActs["Docstring"].setEnabled(
5582 self.getDocstringGenerator().isFunctionStart(line))
5583 5553
5584 self.showMenu.emit("Main", self.menu, self) 5554 self.showMenu.emit("Main", self.menu, self)
5585 5555
5586 def __showContextMenuAutocompletion(self): 5556 def __showContextMenuAutocompletion(self):
5587 """ 5557 """
6381 Public slot to handle the 'Goto syntax error' context menu action. 6351 Public slot to handle the 'Goto syntax error' context menu action.
6382 """ 6352 """
6383 seline = self.markerFindNext(0, 1 << self.syntaxerror) 6353 seline = self.markerFindNext(0, 1 << self.syntaxerror)
6384 if seline >= 0: 6354 if seline >= 0:
6385 index = 0 6355 index = 0
6386 for handle in self.syntaxerrors.keys(): 6356 for handle in self.syntaxerrors:
6387 if self.markerLine(handle) == seline: 6357 if self.markerLine(handle) == seline:
6388 index = self.syntaxerrors[handle][0][1] 6358 index = self.syntaxerrors[handle][0][1]
6389 self.setCursorPosition(seline, index) 6359 self.setCursorPosition(seline, index)
6390 self.ensureLineVisible(seline) 6360 self.ensureLineVisible(seline)
6391 6361
6687 warningAnnotations = [] 6657 warningAnnotations = []
6688 errorAnnotations = [] 6658 errorAnnotations = []
6689 styleAnnotations = [] 6659 styleAnnotations = []
6690 6660
6691 # step 1: do warnings 6661 # step 1: do warnings
6692 for handle in self.warnings.keys(): 6662 for handle in self.warnings:
6693 if self.markerLine(handle) == line: 6663 if self.markerLine(handle) == line:
6694 for msg, warningType in self.warnings[handle]: 6664 for msg, warningType in self.warnings[handle]:
6695 if warningType == self.WarningStyle: 6665 if warningType == self.WarningStyle:
6696 styleAnnotations.append( 6666 styleAnnotations.append(
6697 self.tr("Style: {0}").format(msg)) 6667 self.tr("Style: {0}").format(msg))
6698 else: 6668 else:
6699 warningAnnotations.append( 6669 warningAnnotations.append(
6700 self.tr("Warning: {0}").format(msg)) 6670 self.tr("Warning: {0}").format(msg))
6701 6671
6702 # step 2: do syntax errors 6672 # step 2: do syntax errors
6703 for handle in self.syntaxerrors.keys(): 6673 for handle in self.syntaxerrors:
6704 if self.markerLine(handle) == line: 6674 if self.markerLine(handle) == line:
6705 for msg, _ in self.syntaxerrors[handle]: 6675 for msg, _ in self.syntaxerrors[handle]:
6706 errorAnnotations.append( 6676 errorAnnotations.append(
6707 self.tr("Error: {0}").format(msg)) 6677 self.tr("Error: {0}").format(msg))
6708 6678
6966 6936
6967 def undo(self): 6937 def undo(self):
6968 """ 6938 """
6969 Public method to undo the last recorded change. 6939 Public method to undo the last recorded change.
6970 """ 6940 """
6971 super(Editor, self).undo() 6941 super().undo()
6972 self.undoAvailable.emit(self.isUndoAvailable()) 6942 self.undoAvailable.emit(self.isUndoAvailable())
6973 self.redoAvailable.emit(self.isRedoAvailable()) 6943 self.redoAvailable.emit(self.isRedoAvailable())
6974 6944
6975 def redo(self): 6945 def redo(self):
6976 """ 6946 """
6977 Public method to redo the last recorded change. 6947 Public method to redo the last recorded change.
6978 """ 6948 """
6979 super(Editor, self).redo() 6949 super().redo()
6980 self.undoAvailable.emit(self.isUndoAvailable()) 6950 self.undoAvailable.emit(self.isUndoAvailable())
6981 self.redoAvailable.emit(self.isRedoAvailable()) 6951 self.redoAvailable.emit(self.isRedoAvailable())
6982 6952
6983 def close(self, alsoDelete=False): 6953 def close(self, alsoDelete=False):
6984 """ 6954 """
7020 self.__processSyntaxCheckError) 6990 self.__processSyntaxCheckError)
7021 6991
7022 if self.spell: 6992 if self.spell:
7023 self.spell.stopIncrementalCheck() 6993 self.spell.stopIncrementalCheck()
7024 6994
7025 try: 6995 with contextlib.suppress(TypeError):
7026 self.project.projectPropertiesChanged.disconnect( 6996 self.project.projectPropertiesChanged.disconnect(
7027 self.__projectPropertiesChanged) 6997 self.__projectPropertiesChanged)
7028 except TypeError:
7029 pass
7030 6998
7031 if self.fileName: 6999 if self.fileName:
7032 self.taskViewer.clearFileTasks(self.fileName, True) 7000 self.taskViewer.clearFileTasks(self.fileName, True)
7033 7001
7034 super(Editor, self).close() 7002 super().close()
7035 7003
7036 def keyPressEvent(self, ev): 7004 def keyPressEvent(self, ev):
7037 """ 7005 """
7038 Protected method to handle the user input a key at a time. 7006 Protected method to handle the user input a key at a time.
7039 7007
7048 @param encString string to use to enclose the selection 7016 @param encString string to use to enclose the selection
7049 (one or two characters) 7017 (one or two characters)
7050 @type str 7018 @type str
7051 """ 7019 """
7052 startChar = encString[0] 7020 startChar = encString[0]
7053 if len(encString) == 2: 7021 endChar = encString[1] if len(encString) == 2 else startChar
7054 endChar = encString[1]
7055 else:
7056 endChar = startChar
7057 7022
7058 sline, sindex, eline, eindex = self.getSelection() 7023 sline, sindex, eline, eindex = self.getSelection()
7059 replaceText = startChar + self.selectedText() + endChar 7024 replaceText = startChar + self.selectedText() + endChar
7060 self.beginUndoAction() 7025 self.beginUndoAction()
7061 self.replaceSelectedText(replaceText) 7026 self.replaceSelectedText(replaceText)
7064 7029
7065 txt = ev.text() 7030 txt = ev.text()
7066 7031
7067 # See it is text to insert. 7032 # See it is text to insert.
7068 if len(txt) and txt >= " ": 7033 if len(txt) and txt >= " ":
7069 if self.hasSelectedText(): 7034 if (
7070 if txt in Editor.EncloseChars: 7035 self.hasSelectedText() and
7071 encloseSelectedText(Editor.EncloseChars[txt]) 7036 txt in Editor.EncloseChars
7072 ev.accept() 7037 ):
7073 return 7038 encloseSelectedText(Editor.EncloseChars[txt])
7039 ev.accept()
7040 return
7074 7041
7075 super(Editor, self).keyPressEvent(ev) 7042 super().keyPressEvent(ev)
7076 else: 7043 else:
7077 ev.ignore() 7044 ev.ignore()
7078 7045
7079 def focusInEvent(self, event): 7046 def focusInEvent(self, event):
7080 """ 7047 """
7092 self.vm.editActGrp.setEnabled(True) 7059 self.vm.editActGrp.setEnabled(True)
7093 self.vm.editorActGrp.setEnabled(True) 7060 self.vm.editorActGrp.setEnabled(True)
7094 self.vm.copyActGrp.setEnabled(True) 7061 self.vm.copyActGrp.setEnabled(True)
7095 self.vm.viewActGrp.setEnabled(True) 7062 self.vm.viewActGrp.setEnabled(True)
7096 self.vm.searchActGrp.setEnabled(True) 7063 self.vm.searchActGrp.setEnabled(True)
7097 try: 7064 with contextlib.suppress(AttributeError):
7098 self.setCaretWidth(self.caretWidth) 7065 self.setCaretWidth(self.caretWidth)
7099 except AttributeError:
7100 pass
7101 self.__updateReadOnly(False) 7066 self.__updateReadOnly(False)
7102 if ( 7067 if (
7103 self.vm.editorsCheckFocusInEnabled() and 7068 self.vm.editorsCheckFocusInEnabled() and
7104 not self.inReopenPrompt and self.fileName and 7069 not self.inReopenPrompt and self.fileName and
7105 QFileInfo(self.fileName).lastModified().toString() != 7070 QFileInfo(self.fileName).lastModified().toString() !=
7131 self.lastModified = QFileInfo(self.fileName).lastModified() 7096 self.lastModified = QFileInfo(self.fileName).lastModified()
7132 self.inReopenPrompt = False 7097 self.inReopenPrompt = False
7133 7098
7134 self.setCursorFlashTime(QApplication.cursorFlashTime()) 7099 self.setCursorFlashTime(QApplication.cursorFlashTime())
7135 7100
7136 super(Editor, self).focusInEvent(event) 7101 super().focusInEvent(event)
7137 7102
7138 def focusOutEvent(self, event): 7103 def focusOutEvent(self, event):
7139 """ 7104 """
7140 Protected method called when the editor loses focus. 7105 Protected method called when the editor loses focus.
7141 7106
7143 @type QFocusEvent 7108 @type QFocusEvent
7144 """ 7109 """
7145 self.vm.editorActGrp.setEnabled(False) 7110 self.vm.editorActGrp.setEnabled(False)
7146 self.setCaretWidth(0) 7111 self.setCaretWidth(0)
7147 7112
7148 super(Editor, self).focusOutEvent(event) 7113 super().focusOutEvent(event)
7149 7114
7150 def changeEvent(self, evt): 7115 def changeEvent(self, evt):
7151 """ 7116 """
7152 Protected method called to process an event. 7117 Protected method called to process an event.
7153 7118
7173 cap = self.fileName 7138 cap = self.fileName
7174 if self.isReadOnly(): 7139 if self.isReadOnly():
7175 cap = self.tr("{0} (ro)").format(cap) 7140 cap = self.tr("{0} (ro)").format(cap)
7176 self.setWindowTitle(cap) 7141 self.setWindowTitle(cap)
7177 7142
7178 super(Editor, self).changeEvent(evt) 7143 super().changeEvent(evt)
7179 7144
7180 def mousePressEvent(self, event): 7145 def mousePressEvent(self, event):
7181 """ 7146 """
7182 Protected method to handle the mouse press event. 7147 Protected method to handle the mouse press event.
7183 7148
7184 @param event the mouse press event 7149 @param event the mouse press event
7185 @type QMouseEvent 7150 @type QMouseEvent
7186 """ 7151 """
7187 self.vm.eventFilter(self, event) 7152 self.vm.eventFilter(self, event)
7188 super(Editor, self).mousePressEvent(event) 7153 super().mousePressEvent(event)
7189 7154
7190 def mouseDoubleClickEvent(self, evt): 7155 def mouseDoubleClickEvent(self, evt):
7191 """ 7156 """
7192 Protected method to handle mouse double click events. 7157 Protected method to handle mouse double click events.
7193 7158
7194 @param evt reference to the mouse event 7159 @param evt reference to the mouse event
7195 @type QMouseEvent 7160 @type QMouseEvent
7196 """ 7161 """
7197 super(Editor, self).mouseDoubleClickEvent(evt) 7162 super().mouseDoubleClickEvent(evt)
7198 7163
7199 self.mouseDoubleClick.emit(evt.pos(), evt.buttons()) 7164 self.mouseDoubleClick.emit(evt.pos(), evt.buttons())
7200 7165
7201 def wheelEvent(self, evt): 7166 def wheelEvent(self, evt):
7202 """ 7167 """
7220 elif delta > 0: 7185 elif delta > 0:
7221 self.gotoMethodClass(True) 7186 self.gotoMethodClass(True)
7222 evt.accept() 7187 evt.accept()
7223 return 7188 return
7224 7189
7225 super(Editor, self).wheelEvent(evt) 7190 super().wheelEvent(evt)
7226 7191
7227 def event(self, evt): 7192 def event(self, evt):
7228 """ 7193 """
7229 Public method handling events. 7194 Public method handling events.
7230 7195
7235 """ 7200 """
7236 if evt.type() == QEvent.Type.Gesture: 7201 if evt.type() == QEvent.Type.Gesture:
7237 self.gestureEvent(evt) 7202 self.gestureEvent(evt)
7238 return True 7203 return True
7239 7204
7240 return super(Editor, self).event(evt) 7205 return super().event(evt)
7241 7206
7242 def gestureEvent(self, evt): 7207 def gestureEvent(self, evt):
7243 """ 7208 """
7244 Protected method handling gesture events. 7209 Protected method handling gesture events.
7245 7210
7267 Protected method handling resize events. 7232 Protected method handling resize events.
7268 7233
7269 @param evt reference to the resize event 7234 @param evt reference to the resize event
7270 @type QResizeEvent 7235 @type QResizeEvent
7271 """ 7236 """
7272 super(Editor, self).resizeEvent(evt) 7237 super().resizeEvent(evt)
7273 self.__markerMap.calculateGeometry() 7238 self.__markerMap.calculateGeometry()
7274 7239
7275 def viewportEvent(self, evt): 7240 def viewportEvent(self, evt):
7276 """ 7241 """
7277 Protected method handling event of the viewport. 7242 Protected method handling event of the viewport.
7279 @param evt reference to the event 7244 @param evt reference to the event
7280 @type QEvent 7245 @type QEvent
7281 @return flag indiating that the event was handled 7246 @return flag indiating that the event was handled
7282 @rtype bool 7247 @rtype bool
7283 """ 7248 """
7284 try: 7249 with contextlib.suppress(AttributeError):
7285 self.__markerMap.calculateGeometry() 7250 self.__markerMap.calculateGeometry()
7286 except AttributeError: 7251 return super().viewportEvent(evt)
7287 # ignore this - there seems to be a runtime issue when the editor
7288 # is created
7289 pass
7290 return super(Editor, self).viewportEvent(evt)
7291 7252
7292 def __updateReadOnly(self, bForce=True): 7253 def __updateReadOnly(self, bForce=True):
7293 """ 7254 """
7294 Private method to update the readOnly information for this editor. 7255 Private method to update the readOnly information for this editor.
7295 7256
7395 def clearStyles(self): 7356 def clearStyles(self):
7396 """ 7357 """
7397 Public method to set the styles according the selected Qt style 7358 Public method to set the styles according the selected Qt style
7398 or the selected editor colours. 7359 or the selected editor colours.
7399 """ 7360 """
7400 super(Editor, self).clearStyles() 7361 super().clearStyles()
7401 if Preferences.getEditor("OverrideEditAreaColours"): 7362 if Preferences.getEditor("OverrideEditAreaColours"):
7402 self.setColor(Preferences.getEditorColour("EditAreaForeground")) 7363 self.setColor(Preferences.getEditorColour("EditAreaForeground"))
7403 self.setPaper(Preferences.getEditorColour("EditAreaBackground")) 7364 self.setPaper(Preferences.getEditorColour("EditAreaBackground"))
7404 7365
7405 ################################################################# 7366 #################################################################
7414 """ 7375 """
7415 self.inDragDrop = event.mimeData().hasUrls() 7376 self.inDragDrop = event.mimeData().hasUrls()
7416 if self.inDragDrop: 7377 if self.inDragDrop:
7417 event.acceptProposedAction() 7378 event.acceptProposedAction()
7418 else: 7379 else:
7419 super(Editor, self).dragEnterEvent(event) 7380 super().dragEnterEvent(event)
7420 7381
7421 def dragMoveEvent(self, event): 7382 def dragMoveEvent(self, event):
7422 """ 7383 """
7423 Protected method to handle the drag move event. 7384 Protected method to handle the drag move event.
7424 7385
7425 @param event the drag move event (QDragMoveEvent) 7386 @param event the drag move event (QDragMoveEvent)
7426 """ 7387 """
7427 if self.inDragDrop: 7388 if self.inDragDrop:
7428 event.accept() 7389 event.accept()
7429 else: 7390 else:
7430 super(Editor, self).dragMoveEvent(event) 7391 super().dragMoveEvent(event)
7431 7392
7432 def dragLeaveEvent(self, event): 7393 def dragLeaveEvent(self, event):
7433 """ 7394 """
7434 Protected method to handle the drag leave event. 7395 Protected method to handle the drag leave event.
7435 7396
7437 """ 7398 """
7438 if self.inDragDrop: 7399 if self.inDragDrop:
7439 self.inDragDrop = False 7400 self.inDragDrop = False
7440 event.accept() 7401 event.accept()
7441 else: 7402 else:
7442 super(Editor, self).dragLeaveEvent(event) 7403 super().dragLeaveEvent(event)
7443 7404
7444 def dropEvent(self, event): 7405 def dropEvent(self, event):
7445 """ 7406 """
7446 Protected method to handle the drop event. 7407 Protected method to handle the drop event.
7447 7408
7459 self.tr("Drop Error"), 7420 self.tr("Drop Error"),
7460 self.tr("""<p><b>{0}</b> is not a file.</p>""") 7421 self.tr("""<p><b>{0}</b> is not a file.</p>""")
7461 .format(fname)) 7422 .format(fname))
7462 event.acceptProposedAction() 7423 event.acceptProposedAction()
7463 else: 7424 else:
7464 super(Editor, self).dropEvent(event) 7425 super().dropEvent(event)
7465 7426
7466 self.inDragDrop = False 7427 self.inDragDrop = False
7467 7428
7468 ################################################################# 7429 #################################################################
7469 ## Support for Qt resources files 7430 ## Support for Qt resources files
7732 matchingPairs = ['()', '[]', '{}', '<>', "''", '""'] 7693 matchingPairs = ['()', '[]', '{}', '<>', "''", '""']
7733 # __IGNORE_WARNING_M613__ 7694 # __IGNORE_WARNING_M613__
7734 if text in matchingPairs: 7695 if text in matchingPairs:
7735 self.delete() 7696 self.delete()
7736 7697
7737 super(Editor, self).editorCommand(cmd) 7698 super().editorCommand(cmd)
7738 7699
7739 def __applyTemplate(self, templateName, language): 7700 def __applyTemplate(self, templateName, language):
7740 """ 7701 """
7741 Private method to apply a template by name. 7702 Private method to apply a template by name.
7742 7703
7801 7762
7802 def projectClosed(self): 7763 def projectClosed(self):
7803 """ 7764 """
7804 Public slot to handle the closing of a project. 7765 Public slot to handle the closing of a project.
7805 """ 7766 """
7806 try: 7767 with contextlib.suppress(TypeError):
7807 self.project.projectPropertiesChanged.disconnect( 7768 self.project.projectPropertiesChanged.disconnect(
7808 self.__projectPropertiesChanged) 7769 self.__projectPropertiesChanged)
7809 except TypeError:
7810 pass
7811 7770
7812 ####################################################################### 7771 #######################################################################
7813 ## Spell checking related methods 7772 ## Spell checking related methods
7814 ####################################################################### 7773 #######################################################################
7815 7774
7873 def setAutoSpellChecking(self): 7832 def setAutoSpellChecking(self):
7874 """ 7833 """
7875 Public method to set the automatic spell checking. 7834 Public method to set the automatic spell checking.
7876 """ 7835 """
7877 if Preferences.getEditor("AutoSpellCheckingEnabled"): 7836 if Preferences.getEditor("AutoSpellCheckingEnabled"):
7878 try: 7837 with contextlib.suppress(TypeError):
7879 self.SCN_CHARADDED.connect( 7838 self.SCN_CHARADDED.connect(
7880 self.__spellCharAdded, Qt.ConnectionType.UniqueConnection) 7839 self.__spellCharAdded, Qt.ConnectionType.UniqueConnection)
7881 except TypeError:
7882 pass
7883 self.spell.checkDocumentIncrementally() 7840 self.spell.checkDocumentIncrementally()
7884 else: 7841 else:
7885 try: 7842 with contextlib.suppress(TypeError):
7886 self.SCN_CHARADDED.disconnect(self.__spellCharAdded) 7843 self.SCN_CHARADDED.disconnect(self.__spellCharAdded)
7887 except TypeError:
7888 pass
7889 self.clearAllIndicators(self.spellingIndicator) 7844 self.clearAllIndicators(self.spellingIndicator)
7890 7845
7891 def isSpellCheckRegion(self, pos): 7846 def isSpellCheckRegion(self, pos):
7892 """ 7847 """
7893 Public method to check, if the given position is within a region, that 7848 Public method to check, if the given position is within a region, that
7903 @return flag indicating pos is in a spell check region 7858 @return flag indicating pos is in a spell check region
7904 @rtype bool 7859 @rtype bool
7905 """ 7860 """
7906 if self.__spellCheckStringsOnly: 7861 if self.__spellCheckStringsOnly:
7907 if ( 7862 if (
7908 self.__fileNameExtension in 7863 (self.__fileNameExtension in
7909 Preferences.getEditor("FullSpellCheckExtensions") 7864 Preferences.getEditor("FullSpellCheckExtensions")) or
7910 ): 7865 (not self.__fileNameExtension and
7911 return True 7866 Preferences.getEditor("FullSpellCheckUnknown"))
7912 elif (
7913 not self.__fileNameExtension and
7914 Preferences.getEditor("FullSpellCheckUnknown")
7915 ): 7867 ):
7916 return True 7868 return True
7917 else: 7869 else:
7918 style = self.styleAt(pos) 7870 style = self.styleAt(pos)
7919 if self.lexer_ is not None: 7871 if self.lexer_ is not None:
8347 wordStart, wordEnd = self.getCurrentWordBoundaries() 8299 wordStart, wordEnd = self.getCurrentWordBoundaries()
8348 wordStartPos = self.positionFromLineIndex(line, wordStart) 8300 wordStartPos = self.positionFromLineIndex(line, wordStart)
8349 wordEndPos = self.positionFromLineIndex(line, wordEnd) 8301 wordEndPos = self.positionFromLineIndex(line, wordEnd)
8350 8302
8351 regExp = re.compile(r"\b{0}\b".format(word)) 8303 regExp = re.compile(r"\b{0}\b".format(word))
8352 if forward: 8304 startPos = wordEndPos if forward else wordStartPos
8353 startPos = wordEndPos
8354 else:
8355 startPos = wordStartPos
8356 8305
8357 matches = [m for m in regExp.finditer(self.text())] 8306 matches = [m for m in regExp.finditer(self.text())]
8358 if matches: 8307 if matches:
8359 if forward: 8308 if forward:
8360 matchesAfter = [m for m in matches if m.start() >= startPos] 8309 matchesAfter = [m for m in matches if m.start() >= startPos]
8469 modifiers = evt.modifiers() 8418 modifiers = evt.modifiers()
8470 button = evt.button() 8419 button = evt.button()
8471 key = (int(modifiers), int(button)) 8420 key = (int(modifiers), int(button))
8472 8421
8473 self.vm.eventFilter(self, evt) 8422 self.vm.eventFilter(self, evt)
8474 super(Editor, self).mouseReleaseEvent(evt) 8423 super().mouseReleaseEvent(evt)
8475 8424
8476 if ( 8425 if (
8477 button != Qt.MouseButton.NoButton and 8426 button != Qt.MouseButton.NoButton and
8478 Preferences.getEditor("MouseClickHandlersEnabled") and 8427 Preferences.getEditor("MouseClickHandlersEnabled") and
8479 key in self.__mouseClickHandlers 8428 key in self.__mouseClickHandlers

eric ide

mercurial