src/eric7/QScintilla/Editor.py

branch
eric7-maintenance
changeset 10460
3b34efa2857c
parent 10349
df7edc29cbfb
parent 10449
cc468bd2abdf
child 10534
783d835d7fe4
--- a/src/eric7/QScintilla/Editor.py	Sun Dec 03 14:54:00 2023 +0100
+++ b/src/eric7/QScintilla/Editor.py	Mon Jan 01 11:10:45 2024 +0100
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-# Copyright (c) 2002 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+# Copyright (c) 2002 - 2024 Detlev Offenbach <detlev@die-offenbachs.de>
 #
 
 """
@@ -51,7 +51,7 @@
 from eric7.EricWidgets import EricFileDialog, EricMessageBox
 from eric7.EricWidgets.EricApplication import ericApp
 from eric7.Globals import recentNameBreakpointConditions
-from eric7.SystemUtilities import OSUtilities, PythonUtilities
+from eric7.SystemUtilities import FileSystemUtilities, OSUtilities, PythonUtilities
 from eric7.UI import PythonDisViewer
 from eric7.Utilities import MouseUtilities
 
@@ -146,12 +146,14 @@
     settingsRead = pyqtSignal()
     mouseDoubleClick = pyqtSignal(QPoint, Qt.MouseButton)
 
+    # TODO: convert to an enum.Enum
     WarningCode = 1
     WarningPython = 2
     WarningStyle = 3
     WarningInfo = 4
     WarningError = 5
 
+    # TODO: convert to an enum.IntEnum (also in Assistant plugin)
     # Autocompletion icon definitions
     ClassID = 1
     ClassProtectedID = 2
@@ -418,7 +420,10 @@
                 if not Utilities.MimeTypes.isTextFile(self.fileName):
                     raise OSError()
 
-                if self.isLocalFile() and pathlib.Path(self.fileName).exists():
+                if (
+                    FileSystemUtilities.isPlainFileName(self.fileName)
+                    and pathlib.Path(self.fileName).exists()
+                ):
                     fileSizeKB = pathlib.Path(self.fileName).stat().st_size // 1024
                     if fileSizeKB > Preferences.getEditor("RejectFilesize"):
                         EricMessageBox.warning(
@@ -632,43 +637,19 @@
         """
         renamed = self.fileName != name
 
+        oldFileName = self.fileName
         self.fileName = name
 
         if renamed:
             self.vm.setEditorName(self, self.fileName)
+            self.vm.removeWatchedFilePath(oldFileName)
+            self.vm.addWatchedFilePath(self.fileName)
 
         if self.fileName:
             self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower()
         else:
             self.__fileNameExtension = ""
 
-    def isLocalFile(self):
-        """
-        Public method to check, if the editor contains a local file.
-
-        @return flag indicating a local file
-        @rtype bool
-        """
-        return not self.fileName.startswith(("device:", "remote:"))
-
-    def isDeviceFile(self):
-        """
-        Public method to check, if the editor contains a MCU device file.
-
-        @return flag indicating a MCU device file
-        @rtype bool
-        """
-        return self.fileName.startswith("device:")
-
-    def isRemoteFile(self):
-        """
-        Public method to check, if the editor contains a remote file.
-
-        @return flag indicating a remote file
-        @rtype bool
-        """
-        return self.fileName.startswith("remote:")
-
     def __registerImages(self):
         """
         Private method to register images for autocompletion lists.
@@ -767,8 +748,9 @@
         Private method to generate a dummy filename for binding a lexer.
 
         @param line0 first line of text to use in the generation process
-            (string)
-        @return dummy file name to be used for binding a lexer (string)
+        @type str
+        @return dummy file name to be used for binding a lexer
+        @rtype str
         """
         bindName = ""
         line0 = line0.lower()
@@ -842,8 +824,10 @@
         """
         Public method to get a reference to the main context menu or a submenu.
 
-        @param menuName name of the menu (string)
-        @return reference to the requested menu (QMenu) or None
+        @param menuName name of the menu
+        @type str
+        @return reference to the requested menu or None
+        @rtype QMenu
         """
         try:
             return self.__menus[menuName]
@@ -854,7 +838,8 @@
         """
         Public method to check the miniMenu flag.
 
-        @return flag indicating a minimized context menu (boolean)
+        @return flag indicating a minimized context menu
+        @rtype bool
         """
         return self.miniMenu
 
@@ -1214,8 +1199,7 @@
 
         self.supportedLanguages = {}
         supportedLanguages = Lexers.getSupportedLanguages()
-        languages = sorted(supportedLanguages.keys())
-        for language in languages:
+        for language in sorted(supportedLanguages):
             if language != "Guessed":
                 self.supportedLanguages[language] = supportedLanguages[language][:2]
                 act = menu.addAction(
@@ -1525,7 +1509,8 @@
         """
         Public method to export the file.
 
-        @param exporterFormat format the file should be exported into (string)
+        @param exporterFormat format the file should be exported into
+        @type str
         """
         if exporterFormat:
             exporter = Exporters.getExporter(exporterFormat, self)
@@ -1565,7 +1550,8 @@
         """
         Private method to select a specific pygments lexer.
 
-        @return name of the selected pygments lexer (string)
+        @return name of the selected pygments lexer
+        @rtype str
         """
         from pygments.lexers import get_all_lexers  # __IGNORE_WARNING_I102__
 
@@ -1593,7 +1579,8 @@
         """
         Private method to handle the selection of a lexer language.
 
-        @param act reference to the action that was triggered (QAction)
+        @param act reference to the action that was triggered
+        @type QAction
         """
         if act == self.noLanguageAct:
             self.__resetLanguage()
@@ -1616,8 +1603,10 @@
         """
         Private method handling a change of a connected editor's language.
 
-        @param language language to be set (string)
-        @param propagate flag indicating to propagate the change (boolean)
+        @param language language to be set
+        @type str
+        @param propagate flag indicating to propagate the change
+        @type bool
         """
         if language == "":
             self.__resetLanguage(propagate=propagate)
@@ -1637,7 +1626,8 @@
         """
         Private method used to reset the language selection.
 
-        @param propagate flag indicating to propagate the change (boolean)
+        @param propagate flag indicating to propagate the change
+        @type bool
         """
         if self.lexer_ is not None and (
             self.lexer_.lexer() == "container" or self.lexer_.lexer() is None
@@ -1671,11 +1661,15 @@
         Public method to set a lexer language.
 
         @param filename filename used to determine the associated lexer
-            language (string)
+            language
+        @type str
         @param initTextDisplay flag indicating an initialization of the text
-            display is required as well (boolean)
-        @param propagate flag indicating to propagate the change (boolean)
-        @param pyname name of the pygments lexer to use (string)
+            display is required as well
+        @type bool
+        @param propagate flag indicating to propagate the change
+        @type bool
+        @param pyname name of the pygments lexer to use
+        @type str
         """
         # clear all warning and syntax error markers
         self.clearSyntaxError()
@@ -1738,7 +1732,8 @@
         """
         Private method to handle the selection of an encoding.
 
-        @param act reference to the action that was triggered (QAction)
+        @param act reference to the action that was triggered
+        @type QAction
         """
         encoding = act.data()
         self.setModified(True)
@@ -1773,8 +1768,10 @@
         """
         Private method to calculate the normalized encoding string.
 
-        @param encoding encoding to be normalized (string)
-        @return normalized encoding (string)
+        @param encoding encoding to be normalized
+        @type str
+        @return normalized encoding
+        @rtype str
         """
         if not encoding:
             encoding = self.encoding
@@ -1795,7 +1792,8 @@
         """
         Private method to handle the selection of an eol type.
 
-        @param act reference to the action that was triggered (QAction)
+        @param act reference to the action that was triggered
+        @type QAction
         """
         eol = act.data()
         self.setEolModeByEolString(eol)
@@ -1821,6 +1819,19 @@
             self.eolChanged.emit(eol)
             self.inEolChanged = False
 
+    def convertEols(self, eolMode):
+        """
+        Public method to convert the end-of-line marker.
+
+        This variant of the method emits a signal to update the IDE after
+        the original method was called.
+
+        @param eolMode end-of-line mode
+        @type QsciScintilla.EolMode
+        """
+        super().convertEols(eolMode)
+        self.__eolChanged()
+
     @pyqtSlot()
     def __showContextMenuSpellCheck(self):
         """
@@ -2019,7 +2030,8 @@
         """
         Public method to retrieve a reference to the lexer object.
 
-        @return the lexer object (Lexer)
+        @return the lexer object
+        @rtype Lexer
         """
         return self.lexer_
 
@@ -2028,10 +2040,13 @@
         Public method to retrieve the language of the editor.
 
         @param normalized flag indicating to normalize some Pygments
-            lexer names (boolean)
+            lexer names
+        @type bool
         @param forPygments flag indicating to normalize some lexer
-            names for Pygments (boolean)
-        @return language of the editor (string)
+            names for Pygments
+        @type bool
+        @return language of the editor
+        @rtype str
         """
         if self.apiLanguage == "Guessed" or self.apiLanguage.startswith("Pygments|"):
             lang = self.lexer_.name()
@@ -2082,7 +2097,8 @@
         """
         Public method to retrieve a reference to the completer object.
 
-        @return the completer object (CompleterBase)
+        @return the completer object
+        @rtype CompleterBase
         """
         return self.completer
 
@@ -2162,7 +2178,8 @@
         """
         Public method to set the display string for an unnamed editor.
 
-        @param noName display string for this unnamed editor (string)
+        @param noName display string for this unnamed editor
+        @type str
         """
         self.noName = noName
 
@@ -2170,7 +2187,8 @@
         """
         Public method to get the display string for an unnamed editor.
 
-        @return display string for this unnamed editor (string)
+        @return display string for this unnamed editor
+        @rtype str
         """
         return self.noName
 
@@ -2178,7 +2196,8 @@
         """
         Public method to return the name of the file being displayed.
 
-        @return filename of the displayed file (string)
+        @return filename of the displayed file
+        @rtype str
         """
         return self.fileName
 
@@ -2186,7 +2205,8 @@
         """
         Public method to return the type of the file being displayed.
 
-        @return type of the displayed file (string)
+        @return type of the displayed file
+        @rtype str
         """
         return self.filetype
 
@@ -2196,7 +2216,8 @@
         eflag: marker.
 
         @return type of the displayed file, if set by an eflag: marker or an
-            empty string (string)
+            empty string
+        @rtype str
         """
         if self.filetypeByFlag:
             return self.filetype
@@ -2207,7 +2228,8 @@
         """
         Public method to determine the file type using various tests.
 
-        @return type of the displayed file or an empty string (string)
+        @return type of the displayed file or an empty string
+        @rtype str
         """
         ftype = self.filetype
         if not ftype:
@@ -2225,7 +2247,8 @@
         """
         Public method to return the current encoding.
 
-        @return current encoding (string)
+        @return current encoding
+        @rtype str
         """
         return self.encoding
 
@@ -2234,7 +2257,8 @@
         Private method to return the Python main version or 0 if it's
         not a Python file at all.
 
-        @return Python version or 0 if it's not a Python file (int)
+        @return Python version or 0 if it's not a Python file
+        @rtype int
         """
         return PythonUtilities.determinePythonVersion(self.fileName, self.text(0), self)
 
@@ -2242,7 +2266,8 @@
         """
         Public method to return a flag indicating a Python (2 or 3) file.
 
-        @return flag indicating a Python3 file (boolean)
+        @return flag indicating a Python3 file
+        @rtype bool
         """
         return self.__getPyVersion() == 3
 
@@ -2250,7 +2275,8 @@
         """
         Public method to return a flag indicating a Python3 file.
 
-        @return flag indicating a Python3 file (boolean)
+        @return flag indicating a Python3 file
+        @rtype bool
         """
         return self.__getPyVersion() == 3
 
@@ -2282,7 +2308,8 @@
         """
         Public method to return a flag indicating a Ruby file.
 
-        @return flag indicating a Ruby file (boolean)
+        @return flag indicating a Ruby file
+        @rtype bool
         """
         if self.filetype == "Ruby":
             return True
@@ -2305,7 +2332,8 @@
         """
         Public method to return a flag indicating a Javascript file.
 
-        @return flag indicating a Javascript file (boolean)
+        @return flag indicating a Javascript file
+        @rtype bool
         """
         if self.filetype == "JavaScript":
             return True
@@ -2346,10 +2374,13 @@
         """
         Public method to highlight [or de-highlight] a particular line.
 
-        @param line line number to highlight (integer)
+        @param line line number to highlight
+        @type int
         @param error flag indicating whether the error highlight should be
-            used (boolean)
-        @param syntaxError flag indicating a syntax error (boolean)
+            used
+        @type bool
+        @param syntaxError flag indicating a syntax error
+        @type bool
         """
         if line is None:
             self.lastHighlight = None
@@ -2376,7 +2407,8 @@
         """
         Public method to return the position of the highlight bar.
 
-        @return line number of the highlight bar (integer)
+        @return line number of the highlight bar
+        @rtype int
         """
         if self.lastHighlight is not None:
             return self.markerLine(self.lastHighlight)
@@ -2403,17 +2435,26 @@
         """
         Private method to handle changes of the number of lines.
 
-        @param pos start position of change (integer)
-        @param mtype flags identifying the change (integer)
-        @param text text that is given to the Undo system (string)
-        @param length length of the change (integer)
-        @param linesAdded number of added/deleted lines (integer)
-        @param line line number of a fold level or marker change (integer)
-        @param foldNow new fold level (integer)
-        @param foldPrev previous fold level (integer)
+        @param pos start position of change
+        @type int
+        @param mtype flags identifying the change
+        @type int
+        @param text text that is given to the Undo system
+        @type str
+        @param length length of the change
+        @type int
+        @param linesAdded number of added/deleted lines
+        @type int
+        @param line line number of a fold level or marker change
+        @type int
+        @param foldNow new fold level
+        @type int
+        @param foldPrev previous fold level
+        @type int
         @param token ???
+        @type int
         @param annotationLinesAdded number of added/deleted annotation lines
-            (integer)
+        @type int
         """
         if mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT):
             # 1. set/reset the autosave timer
@@ -2528,7 +2569,8 @@
         Note: This doesn't clear the breakpoint in the debugger,
         it just deletes it from the editor internal list of breakpoints.
 
-        @param line line number of the breakpoint (integer)
+        @param line line number of the breakpoint
+        @type int
         """
         if self.inLinesChanged:
             return
@@ -2544,9 +2586,11 @@
         """
         Public method to set a new breakpoint and its properties.
 
-        @param line line number of the breakpoint (integer)
-        @param properties properties for the breakpoint (tuple)
+        @param line line number of the breakpoint
+        @type int
+        @param properties properties for the breakpoint
                 (condition, temporary flag, enabled flag, ignore count)
+        @type tuple of (str, bool, bool, int)
         """
         if not properties[2]:
             marker = self.dbreakpoint
@@ -2565,8 +2609,10 @@
         """
         Private method to toggle a breakpoint.
 
-        @param line line number of the breakpoint (integer)
-        @param temporary flag indicating a temporary breakpoint (boolean)
+        @param line line number of the breakpoint
+        @type int
+        @param temporary flag indicating a temporary breakpoint
+        @type bool
         """
         for handle in self.breaks:
             if self.markerLine(handle) == line - 1:
@@ -2588,8 +2634,10 @@
         """
         Private method to add a new breakpoint.
 
-        @param line line number of the breakpoint (integer)
-        @param temporary flag indicating a temporary breakpoint (boolean)
+        @param line line number of the breakpoint
+        @type int
+        @param temporary flag indicating a temporary breakpoint
+        @type bool
         """
         if self.fileName and self.isPyFile():
             linestarts = PythonDisViewer.linestarts(self.text())
@@ -2620,7 +2668,8 @@
         """
         Private method to toggle a breakpoints enabled status.
 
-        @param line line number of the breakpoint (integer)
+        @param line line number of the breakpoint
+        @type int
         """
         for handle in self.breaks:
             if self.markerLine(handle) == line - 1:
@@ -2635,7 +2684,8 @@
         Public method to check for the presence of a breakpoint at the current
         line.
 
-        @return flag indicating the presence of a breakpoint (boolean)
+        @return flag indicating the presence of a breakpoint
+        @rtype bool
         """
         line, _ = self.getCursorPosition()
         return self.markersAtLine(line) & self.breakpointMask != 0
@@ -2644,7 +2694,8 @@
         """
         Public method to get the lines containing a breakpoint.
 
-        @return list of lines containing a breakpoint (list of integer)
+        @return list of lines containing a breakpoint
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -2660,7 +2711,8 @@
         """
         Public method to check for the presence of breakpoints.
 
-        @return flag indicating the presence of breakpoints (boolean)
+        @return flag indicating the presence of breakpoints
+        @rtype bool
         """
         return len(self.breaks) > 0
 
@@ -2822,7 +2874,8 @@
         """
         Public method to toggle a bookmark.
 
-        @param line line number of the bookmark (integer)
+        @param line line number of the bookmark
+        @type int
         """
         for handle in self.bookmarks:
             if self.markerLine(handle) == line - 1:
@@ -2841,7 +2894,7 @@
         Public method to retrieve the bookmarks.
 
         @return sorted list of all lines containing a bookmark
-            (list of integer)
+        @rtype list of int
         """
         bmlist = []
         for handle in self.bookmarks:
@@ -2854,7 +2907,8 @@
         """
         Public method to get the lines containing a bookmark.
 
-        @return list of lines containing a bookmark (list of integer)
+        @return list of lines containing a bookmark
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -2870,7 +2924,8 @@
         """
         Public method to check for the presence of bookmarks.
 
-        @return flag indicating the presence of bookmarks (boolean)
+        @return flag indicating the presence of bookmarks
+        @rtype bool
         """
         return len(self.bookmarks) > 0
 
@@ -2998,7 +3053,7 @@
         Private slot to generate a print preview.
 
         @param printer reference to the printer object
-            (QScintilla.Printer.Printer)
+        @type QScintilla.Printer.Printer
         """
         printer.printRange(self)
 
@@ -3010,7 +3065,8 @@
         """
         Public method to get the lines containing a task.
 
-        @return list of lines containing a task (list of integer)
+        @return list of lines containing a task
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -3026,7 +3082,8 @@
         """
         Public method to determine, if this editor contains any task markers.
 
-        @return flag indicating the presence of task markers (boolean)
+        @return flag indicating the presence of task markers
+        @rtype bool
         """
         return self.__hasTaskMarkers
 
@@ -3117,9 +3174,12 @@
         """
         Private method to create a pixmap for the change markers.
 
-        @param key key of the color to use (string)
-        @param size size of the pixmap (integer)
-        @return create pixmap (QPixmap)
+        @param key key of the color to use
+        @type str
+        @param size size of the pixmap
+        @type int
+        @return create pixmap
+        @rtype QPixmap
         """
         pixmap = QPixmap(size, size)
         pixmap.fill(Qt.GlobalColor.transparent)
@@ -3240,7 +3300,8 @@
         """
         Public method to get the lines containing a change.
 
-        @return list of lines containing a change (list of integer)
+        @return list of lines containing a change
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -3256,7 +3317,8 @@
         """
         Public method to determine, if this editor contains any change markers.
 
-        @return flag indicating the presence of change markers (boolean)
+        @return flag indicating the presence of change markers
+        @rtype bool
         """
         return self.__hasChangeMarkers
 
@@ -3306,7 +3368,8 @@
         """
         Private method to extract flags and process them.
 
-        @return list of change flags (list of string)
+        @return list of change flags
+        @rtype list of str
         """
         txt = self.text()
         flags = Utilities.extractFlags(txt)
@@ -3338,7 +3401,8 @@
         """
         Public method to check dirty status and open a message window.
 
-        @return flag indicating successful reset of the dirty flag (boolean)
+        @return flag indicating successful reset of the dirty flag
+        @rtype bool
         """
         if self.isModified():
             fn = self.fileName
@@ -3348,7 +3412,9 @@
                 self,
                 self.tr("File Modified"),
                 self.tr("<p>The file <b>{0}</b> has unsaved changes.</p>").format(fn),
-                self.saveFile if not self.isRemoteFile() else None,
+                self.saveFile
+                if not FileSystemUtilities.isRemoteFileName(self.fileName)
+                else None,
             )
             if res:
                 self.vm.setEditorName(self, self.fileName)
@@ -3376,15 +3442,20 @@
                     break
                     # Couldn't find the unmodified state
 
-    def readFile(self, fn, createIt=False, encoding=""):
+    def readFile(self, fn, createIt=False, encoding="", noempty=False):
         """
         Public method to read the text from a file.
 
-        @param fn filename to read from (string)
+        @param fn filename to read from
+        @type str
         @param createIt flag indicating the creation of a new file, if the
-            given one doesn't exist (boolean)
-        @param encoding encoding to be used to read the file (string)
+            given one doesn't exist (defaults to False)
+        @type bool (optional)
+        @param encoding encoding to be used to read the file (defaults to "")
             (Note: this parameter overrides encoding detection)
+        @type str (optional)
+        @param noempty flag indicating to not set an empty text (defaults to False)
+        @type bool (optional)
         """
         self.__loadEditorConfig(fileName=fn)
 
@@ -3412,10 +3483,12 @@
             )
             raise
 
+        if noempty and not bool(txt):
+            return
+
         with EricOverrideCursor():
-            modified = False
-
             self.setText(txt)
+            self.setModified(False)
 
             # get eric specific flags
             self.__processFlags()
@@ -3428,10 +3501,10 @@
             else:
                 fileEol = self.detectEolString(txt)
                 self.setEolModeByEolString(fileEol)
+                self.__eolChanged()
 
             self.extractTasks()
 
-            self.setModified(modified)
             self.lastModified = pathlib.Path(fn).stat().st_mtime
 
     @pyqtSlot()
@@ -3539,8 +3612,10 @@
         """
         Private method to get the name of the file to be saved.
 
-        @param path directory to save the file in (string)
-        @return file name (string)
+        @param path directory to save the file in
+        @type str
+        @return file name
+        @rtype str
         """
         # save to project, if a project is loaded
         if self.project.isOpen():
@@ -3602,8 +3677,10 @@
         """
         Public method to save a copy of the file.
 
-        @param path directory to save the file in (string)
-        @return flag indicating success (boolean)
+        @param path directory to save the file in
+        @type str
+        @return flag indicating success
+        @rtype bool
         """
         fn = self.__getSaveFileName(path)
         if not fn:
@@ -3620,15 +3697,20 @@
         """
         Public method to save the text to a file.
 
-        @param saveas flag indicating a 'save as' action (boolean)
-        @param path directory to save the file in (string)
-        @return flag indicating success (boolean)
-        """
-        if not saveas and (not self.isModified() or self.isRemoteFile()):
+        @param saveas flag indicating a 'save as' action
+        @type bool
+        @param path directory to save the file in
+        @type str
+        @return flag indicating success
+        @rtype bool
+        """
+        if not saveas and (
+            not self.isModified() or FileSystemUtilities.isRemoteFileName(self.fileName)
+        ):
             # do nothing if text wasn't changed or is a remote file
             return False
 
-        if self.isDeviceFile():
+        if FileSystemUtilities.isDeviceFileName(self.fileName):
             return self.__saveDeviceFile(saveas=saveas)
 
         newName = None
@@ -3738,8 +3820,10 @@
             fn = fn.replace("\\", "/")
             if "/" in fn:
                 dn = fn.rsplit("/", 1)[0]
-                filemanager.makedirs(dn.replace("device:", ""))
-            success = filemanager.writeFile(fn.replace("device:", ""), self.text())
+                filemanager.makedirs(FileSystemUtilities.plainFileName(dn))
+            success = filemanager.writeFile(
+                FileSystemUtilities.plainFileName(fn), self.text()
+            )
             if success:
                 self.setFileName(fn)
                 self.setModified(False)
@@ -3752,7 +3836,8 @@
         """
         Public method to handle the editorRenamed signal.
 
-        @param fn filename to be set for the editor (string).
+        @param fn filename to be set for the editor
+        @type str
         """
         self.__clearBreakpoints(fn)
 
@@ -3938,9 +4023,12 @@
         """
         Public method to get the word to the left of a position.
 
-        @param line number of line to look at (int)
-        @param index position to look at (int)
-        @return the word to the left of that position (string)
+        @param line number of line to look at
+        @type int
+        @param index position to look at
+        @type int
+        @return the word to the left of that position
+        @rtype str
         """
         return self.getWord(line, index, 1)
 
@@ -3948,9 +4036,12 @@
         """
         Public method to get the word to the right of a position.
 
-        @param line number of line to look at (int)
-        @param index position to look at (int)
-        @return the word to the right of that position (string)
+        @param line number of line to look at
+        @type int
+        @param index position to look at
+        @type int
+        @return the word to the right of that position
+        @rtype str
         """
         return self.getWord(line, index, 2)
 
@@ -3958,7 +4049,8 @@
         """
         Public method to get the word at the current position.
 
-        @return the word at that current position (string)
+        @return the word at that current position
+        @rtype str
         """
         line, index = self.getCursorPosition()
         return self.getWord(line, index)
@@ -3968,7 +4060,7 @@
         Public method to get the word boundaries at the current position.
 
         @return tuple with start and end indexes of the current word
-            (integer, integer)
+        @rtype tuple of (int, int)
         """
         line, index = self.getCursorPosition()
         return self.getWordBoundaries(line, index)
@@ -3977,8 +4069,10 @@
         """
         Public method to select the word at a position.
 
-        @param line number of line to look at (int)
-        @param index position to look at (int)
+        @param line number of line to look at
+        @type int
+        @param index position to look at
+        @type int
         """
         start, end = self.getWordBoundaries(line, index)
         self.setSelection(line, start, line, end)
@@ -3995,9 +4089,11 @@
         Private method to get the character to the left of the current position
         in the current line.
 
-        @param pos position to get character at (integer)
-        @return requested character or "", if there are no more (string) and
-            the next position (i.e. pos - 1)
+        @param pos position to get character at
+        @type int
+        @return requested character or "", if there are no more and the next position
+            (i.e. pos - 1)
+        @rtype tuple of (str, int)
         """
         if pos <= 0:
             return "", pos
@@ -4017,8 +4113,10 @@
         next search operation.
 
         @param selectionOnly flag indicating that only selected text should be
-            returned (boolean)
-        @return selection or current word (string)
+            returned
+        @type bool
+        @return selection or current word
+        @rtype str
         """
         if self.hasSelectedText():
             text = self.selectedText()
@@ -4039,8 +4137,10 @@
         """
         Public method to set a search indicator for the given range.
 
-        @param startPos start position of the indicator (integer)
-        @param indicLength length of the indicator (integer)
+        @param startPos start position of the indicator
+        @type int
+        @param indicLength length of the indicator
+        @type int
         """
         self.setIndicatorRange(self.searchIndicator, startPos, indicLength)
         line = self.lineIndexFromPosition(startPos)[0]
@@ -4113,7 +4213,8 @@
         """
         Public method to get the lines containing a search indicator.
 
-        @return list of lines containing a search indicator (list of integer)
+        @return list of lines containing a search indicator
+        @rtype list of int
         """
         return self.__searchIndicatorLines[:]
 
@@ -4176,9 +4277,12 @@
         Private method to check, if the given line is a comment line as
         produced by the configured comment rules.
 
-        @param line text of the line to check (string)
-        @param commentStr comment string to check against (string)
-        @return flag indicating a commented line (boolean)
+        @param line text of the line to check
+        @type str
+        @param commentStr comment string to check against
+        @type str
+        @return flag indicating a commented line
+        @rtype bool
         """
         if Preferences.getEditor("CommentColumn0"):
             return line.startswith(commentStr)
@@ -4186,9 +4290,24 @@
             return line.strip().startswith(commentStr)
 
     @pyqtSlot()
-    def toggleCommentBlock(self):
-        """
-        Public slot to toggle the comment of a block.
+    def toggleComment(self):
+        """
+        Public slot to toggle a block or stream comment.
+
+        If the lexer supports a block comment, that is used for toggling the
+        comment. Otherwise a stream comment is used if that is supported. If
+        none of these are supported, the request is ignored silently.
+        """
+        if self.lexer_ is not None:
+            if self.lexer_.canBlockComment():
+                self.__toggleBlockComment()
+            elif self.lexer_.canStreamComment():
+                self.__toggleStreamComment()
+
+    @pyqtSlot()
+    def __toggleBlockComment(self):
+        """
+        Private slot to toggle the comment of a block.
 
         If the editor contains selected text and the start line is not commented, it
         will be commented. Otherwise the selection will be un-commented. In case there
@@ -4234,9 +4353,9 @@
             self.setCursorPosition(line, index - len(commentStr))
 
     @pyqtSlot()
-    def commentLine(self):
-        """
-        Public slot to comment the current line.
+    def __commentLine(self):
+        """
+        Private slot to comment the current line.
         """
         if self.lexer_ is None or not self.lexer_.canBlockComment():
             return
@@ -4252,9 +4371,9 @@
         self.endUndoAction()
 
     @pyqtSlot()
-    def uncommentLine(self):
-        """
-        Public slot to uncomment the current line.
+    def __uncommentLine(self):
+        """
+        Private slot to uncomment the current line.
         """
         if self.lexer_ is None or not self.lexer_.canBlockComment():
             return
@@ -4279,9 +4398,9 @@
         self.endUndoAction()
 
     @pyqtSlot()
-    def commentSelection(self):
-        """
-        Public slot to comment the current selection.
+    def __commentSelection(self):
+        """
+        Private slot to comment the current selection.
         """
         if self.lexer_ is None or not self.lexer_.canBlockComment():
             return
@@ -4310,9 +4429,9 @@
         self.endUndoAction()
 
     @pyqtSlot()
-    def uncommentSelection(self):
-        """
-        Public slot to uncomment the current selection.
+    def __uncommentSelection(self):
+        """
+        Private slot to uncomment the current selection.
         """
         if self.lexer_ is None or not self.lexer_.canBlockComment():
             return
@@ -4362,42 +4481,140 @@
     def commentLineOrSelection(self):
         """
         Public slot to comment the current line or current selection.
-        """
-        if self.hasSelectedText():
-            self.commentSelection()
-        else:
-            self.commentLine()
+
+        If the lexer supports a block comment, that is used for commenting.
+        Otherwise a stream comment is used if that is supported. If none of
+        these are supported, the request is ignored silently.
+        """
+        if self.lexer_ is not None:
+            if self.lexer_.canBlockComment():
+                if self.hasSelectedText():
+                    self.__commentSelection()
+                else:
+                    self.__commentLine()
+            elif self.lexer_.canStreamComment():
+                # delegate to the stream comment method
+                self.streamCommentLineOrSelection()
 
     @pyqtSlot()
     def uncommentLineOrSelection(self):
         """
         Public slot to uncomment the current line or current selection.
-        """
-        if self.hasSelectedText():
-            self.uncommentSelection()
-        else:
-            self.uncommentLine()
-
-    @pyqtSlot()
-    def streamCommentLine(self):
-        """
-        Public slot to stream comment the current line.
+
+        If the lexer supports a block comment, that is used for uncommenting.
+        Otherwise a stream comment is used if that is supported. If none of
+        these are supported, the request is ignored silently.
+        """
+        if self.lexer_ is not None:
+            if self.lexer_.canBlockComment():
+                if self.hasSelectedText():
+                    self.__uncommentSelection()
+                else:
+                    self.__uncommentLine()
+            elif self.lexer_.canStreamComment():
+                # delegate to the stream uncomment method
+                self.streamUncommentLineOrSelection()
+
+    def __isStreamCommentedLine(self, line, streamCommentStr):
+        """
+        Private method to check, if the line is commented by a stream comment.
+
+        @param line text of the line to check
+        @type str
+        @param streamCommentStr dictionary containing the stream comment start and
+            end strings
+        @type dict
+        @return flag indicating a stream commented line
+        @rtype bool
+        """
+        line = line.strip()
+        return line.startswith(streamCommentStr["start"]) and line.endswith(
+            streamCommentStr["end"]
+        )
+
+    @pyqtSlot()
+    def __toggleStreamComment(self):
+        """
+        Private slot to toggle the comment of a block.
+
+        If the editor contains selected text and the start line is not commented, it
+        will be commented. Otherwise the selection will be un-commented. In case there
+        is no selected text and the current line is not commented, it will be commented.
+        If is commented, the comment block will be removed.
         """
         if self.lexer_ is None or not self.lexer_.canStreamComment():
             return
 
-        commentStr = self.lexer_.streamCommentStr()
+        streamCommentStr = self.lexer_.streamCommentStr()
+        line, index = self.getCursorPosition()
+
+        if self.hasSelectedText():
+            # Check if the selection starts with a stream comment string.
+            if self.text(self.getSelection()[0]).startswith(streamCommentStr["start"]):
+                self.streamUncommentLineOrSelection()
+            else:
+                self.streamCommentLineOrSelection()
+        elif self.__isStreamCommentedLine(self.text(line), streamCommentStr):
+            # It is a stream commented line.
+            self.streamUncommentLineOrSelection()
+        elif self.text(line).lstrip(" \t").startswith(streamCommentStr["start"]):
+            # The cursor is at the first line of a stream comment.
+            pos = len(self.text(line).replace(self.text(line).lstrip(" \t"), ""))
+            endline = line
+            lines = self.lines()
+            while endline < lines and not self.text(endline).rstrip().endswith(
+                streamCommentStr["end"]
+            ):
+                endline += 1
+
+            # Uncomment the determined block and reset the cursor position
+            self.setSelection(line, pos, endline, self.lineLength(endline))
+            self.uncommentLineOrSelection()
+            self.setCursorPosition(line, index - len(streamCommentStr["start"]))
+        elif self.text(line).rstrip().endswith(streamCommentStr["end"]):
+            # The cursor is at the last line of a stream comment.
+            begline = line
+            while begline > 0 and not self.text(begline).lstrip(" \t").startswith(
+                streamCommentStr["start"]
+            ):
+                begline -= 1
+            pos = len(self.text(begline).replace(self.text(begline).lstrip(" \t"), ""))
+
+            # Uncomment the determined block and reset the cursor position
+            self.setSelection(begline, pos, line, self.lineLength(line))
+            self.uncommentLineOrSelection()
+            self.setCursorPosition(
+                line, min(index, self.lineLength(line) - len(self.getLineSeparator()))
+            )
+        else:
+            # No selected text and the current line does not start with a stream comment
+            # string, so comment the line.
+            self.streamCommentLineOrSelection()
+
+    @pyqtSlot()
+    def __streamCommentLine(self):
+        """
+        Private slot to stream comment the current line.
+        """
+        if self.lexer_ is None or not self.lexer_.canStreamComment():
+            return
+
+        streamCommentStr = self.lexer_.streamCommentStr()
         line, index = self.getCursorPosition()
 
         self.beginUndoAction()
-        self.insertAt(commentStr["end"], line, self.lineLength(line))
-        self.insertAt(commentStr["start"], line, 0)
+        self.insertAt(
+            streamCommentStr["end"],
+            line,
+            self.lineLength(line) - len(self.getLineSeparator()),
+        )
+        self.insertAt(streamCommentStr["start"], line, 0)
         self.endUndoAction()
 
     @pyqtSlot()
-    def streamCommentSelection(self):
-        """
-        Public slot to comment the current selection.
+    def __streamCommentSelection(self):
+        """
+        Private slot to comment the current selection.
         """
         if self.lexer_ is None or not self.lexer_.canStreamComment():
             return
@@ -4405,63 +4622,158 @@
         if not self.hasSelectedText():
             return
 
-        commentStr = self.lexer_.streamCommentStr()
+        streamCommentStr = self.lexer_.streamCommentStr()
 
         # get the selection boundaries
         lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
         if indexTo == 0:
             endLine = lineTo - 1
-            endIndex = self.lineLength(endLine)
+            endIndex = self.lineLength(endLine) - len(self.getLineSeparator())
         else:
             endLine = lineTo
             endIndex = indexTo
 
         self.beginUndoAction()
-        self.insertAt(commentStr["end"], endLine, endIndex)
-        self.insertAt(commentStr["start"], lineFrom, indexFrom)
+        self.insertAt(streamCommentStr["end"], endLine, endIndex)
+        self.insertAt(streamCommentStr["start"], lineFrom, indexFrom)
 
         # change the selection accordingly
         if indexTo > 0:
-            indexTo += len(commentStr["end"])
+            indexTo += len(streamCommentStr["end"])
             if lineFrom == endLine:
-                indexTo += len(commentStr["start"])
+                indexTo += len(streamCommentStr["start"])
         self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
         self.endUndoAction()
 
     @pyqtSlot()
+    def __streamUncommentLine(self):
+        """
+        Private slot to stream uncomment the current line.
+        """
+        if self.lexer_ is None or not self.lexer_.canStreamComment():
+            return
+
+        streamCommentStr = self.lexer_.streamCommentStr()
+        line, index = self.getCursorPosition()
+
+        # check if line starts and ends with the stream comment strings
+        if not self.__isStreamCommentedLine(self.text(line), streamCommentStr):
+            return
+
+        self.beginUndoAction()
+        # 1. remove comment end string
+        self.setSelection(
+            line,
+            self.lineLength(line)
+            - len(self.getLineSeparator())
+            - len(streamCommentStr["end"]),
+            line,
+            self.lineLength(line) - len(self.getLineSeparator()),
+        )
+        self.removeSelectedText()
+
+        # 2. remove comment start string
+        lineText = self.text(line)
+        pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
+        self.setSelection(line, pos, line, pos + len(streamCommentStr["start"]))
+        self.removeSelectedText()
+        self.endUndoAction()
+
+    @pyqtSlot()
+    def __streamUncommentSelection(self):
+        """
+        Private slot to stream uncomment the current selection.
+        """
+        if self.lexer_ is None or not self.lexer_.canStreamComment():
+            return
+
+        if not self.hasSelectedText():
+            return
+
+        streamCommentStr = self.lexer_.streamCommentStr()
+
+        # get the selection boundaries
+        lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
+        if indexTo == 0:
+            endLine = lineTo - 1
+            endIndex = self.lineLength(endLine) - len(self.getLineSeparator())
+        else:
+            endLine = lineTo
+            endIndex = indexTo
+
+        self.beginUndoAction()
+        self.setSelection(lineFrom, indexFrom, endLine, endIndex)
+        selTxt = self.selectedText()
+        if selTxt.endswith(streamCommentStr["end"]):
+            self.setSelection(
+                endLine, endIndex - len(streamCommentStr["end"]), endLine, endIndex
+            )
+            self.removeSelectedText()
+
+            # modify selection end accordingly
+            if indexTo > 0:
+                indexTo -= len(streamCommentStr["end"])
+        if selTxt.startswith(streamCommentStr["start"]):
+            self.setSelection(
+                lineFrom,
+                indexFrom,
+                lineFrom,
+                indexFrom + len(streamCommentStr["start"]),
+            )
+            self.removeSelectedText()
+
+            # modify selection end accordingly
+            if lineFrom == lineTo and indexTo > 0:
+                indexTo -= len(streamCommentStr["start"])
+        self.endUndoAction()
+
+        # now set the new selection
+        self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
+
+    @pyqtSlot()
     def streamCommentLineOrSelection(self):
         """
         Public slot to stream comment the current line or current selection.
         """
         if self.hasSelectedText():
-            self.streamCommentSelection()
-        else:
-            self.streamCommentLine()
-
-    @pyqtSlot()
-    def boxCommentLine(self):
-        """
-        Public slot to box comment the current line.
+            self.__streamCommentSelection()
+        else:
+            self.__streamCommentLine()
+
+    @pyqtSlot()
+    def streamUncommentLineOrSelection(self):
+        """
+        Public slot to stream uncomment the current line or current selection.
+        """
+        if self.hasSelectedText():
+            self.__streamUncommentSelection()
+        else:
+            self.__streamUncommentLine()
+
+    @pyqtSlot()
+    def __boxCommentLine(self):
+        """
+        Private slot to box comment the current line.
         """
         if self.lexer_ is None or not self.lexer_.canBoxComment():
             return
 
-        commentStr = self.lexer_.boxCommentStr()
+        boxCommentStr = self.lexer_.boxCommentStr()
         line, index = self.getCursorPosition()
 
         eol = self.getLineSeparator()
         self.beginUndoAction()
         self.insertAt(eol, line, self.lineLength(line))
-        self.insertAt(commentStr["end"], line + 1, 0)
-        self.insertAt(commentStr["middle"], line, 0)
+        self.insertAt(boxCommentStr["end"], line + 1, 0)
+        self.insertAt(boxCommentStr["middle"], line, 0)
         self.insertAt(eol, line, 0)
-        self.insertAt(commentStr["start"], line, 0)
+        self.insertAt(boxCommentStr["start"], line, 0)
         self.endUndoAction()
 
     @pyqtSlot()
-    def boxCommentSelection(self):
-        """
-        Public slot to box comment the current selection.
+    def __boxCommentSelection(self):
+        """
+        Private slot to box comment the current selection.
         """
         if self.lexer_ is None or not self.lexer_.canBoxComment():
             return
@@ -4469,7 +4781,7 @@
         if not self.hasSelectedText():
             return
 
-        commentStr = self.lexer_.boxCommentStr()
+        boxCommentStr = self.lexer_.boxCommentStr()
 
         # get the selection boundaries
         lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
@@ -4478,14 +4790,14 @@
         self.beginUndoAction()
         # iterate over the lines
         for line in range(lineFrom, endLine + 1):
-            self.insertAt(commentStr["middle"], line, 0)
+            self.insertAt(boxCommentStr["middle"], line, 0)
 
         # now do the comments before and after the selection
         eol = self.getLineSeparator()
         self.insertAt(eol, endLine, self.lineLength(endLine))
-        self.insertAt(commentStr["end"], endLine + 1, 0)
+        self.insertAt(boxCommentStr["end"], endLine + 1, 0)
         self.insertAt(eol, lineFrom, 0)
-        self.insertAt(commentStr["start"], lineFrom, 0)
+        self.insertAt(boxCommentStr["start"], lineFrom, 0)
 
         # change the selection accordingly
         self.setSelection(lineFrom, 0, endLine + 3, 0)
@@ -4497,9 +4809,9 @@
         Public slot to box comment the current line or current selection.
         """
         if self.hasSelectedText():
-            self.boxCommentSelection()
-        else:
-            self.boxCommentLine()
+            self.__boxCommentSelection()
+        else:
+            self.__boxCommentLine()
 
     ###########################################################################
     ## Indentation handling methods below
@@ -4509,9 +4821,10 @@
         """
         Private method to indent or unindent the current line.
 
-        @param indent flag indicating an indent operation (boolean)
-                <br />If the flag is true, an indent operation is performed.
-                Otherwise the current line is unindented.
+        @param indent flag indicating an indent operation
+            <br />If the flag is true, an indent operation is performed.
+            Otherwise the current line is unindented.
+        @type bool
         """
         line, index = self.getCursorPosition()
         self.beginUndoAction()
@@ -4529,9 +4842,10 @@
         """
         Private method to indent or unindent the current selection.
 
-        @param indent flag indicating an indent operation (boolean)
-                <br />If the flag is true, an indent operation is performed.
-                Otherwise the current line is unindented.
+        @param indent flag indicating an indent operation
+            <br />If the flag is true, an indent operation is performed.
+            Otherwise the current line is unindented.
+        @type bool
         """
         if not self.hasSelectedText():
             return
@@ -4648,7 +4962,8 @@
         """
         Public method to check, if a last edit position is available.
 
-        @return flag indicating availability (boolean)
+        @return flag indicating availability
+        @rtype bool
         """
         return self.__lastEditPosition is not None
 
@@ -4663,7 +4978,8 @@
         """
         Public method to go to the next Python method or class definition.
 
-        @param goUp flag indicating the move direction (boolean)
+        @param goUp flag indicating the move direction
+        @type bool
         """
         if self.isPyFile() or self.isRubyFile():
             lineNo = self.getCursorPosition()[0]
@@ -5212,7 +5528,8 @@
         """
         Public method to check for API availablity.
 
-        @return flag indicating autocompletion from APIs is available (boolean)
+        @return flag indicating autocompletion from APIs is available
+        @rtype bool
         """
         return self.acAPI
 
@@ -5247,7 +5564,7 @@
         Public method to enable/disable autocompletion.
 
         @param enable flag indicating the desired autocompletion status
-            (boolean)
+        @type bool
         """
         if enable:
             autoCompletionSource = Preferences.getEditor("AutoCompletionSource")
@@ -5323,8 +5640,10 @@
         Private method to check, if a character is an autocompletion start
         character.
 
-        @param ch character to be checked (one character string)
-        @return flag indicating the result (boolean)
+        @param ch character to be checked
+        @type str
+        @return flag indicating the result
+        @rtype bool
         """
         if self.lexer_ is None:
             return False
@@ -5412,8 +5731,9 @@
         Public method to start auto-completion.
 
         @param auto flag indicating a call from the __charAdded method
-            (boolean)
-        @param context flag indicating to complete a context (boolean)
+        @type bool
+        @param context flag indicating to complete a context
+        @type bool
         """
         if auto and not Preferences.getEditor("AutoCompletionEnabled"):
             # auto-completion is disabled
@@ -5464,7 +5784,7 @@
         Private method to start auto-completion via plug-ins.
 
         @param auto flag indicating a call from the __charAdded method
-            (boolean)
+        @type bool
         @param context flag indicating to complete a context
         @type bool or None
         """
@@ -5635,7 +5955,7 @@
         Public method to test the dynamic auto-completion availability.
 
         @return flag indicating the availability of dynamic auto-completion
-            (boolean)
+        @rtype bool
         """
         return (
             self.acAPI
@@ -5702,7 +6022,8 @@
         """
         Public method to test the calltips availability.
 
-        @return flag indicating the availability of calltips (boolean)
+        @return flag indicating the availability of calltips
+        @rtype bool
         """
         return self.acAPI or bool(self.__ctHookFunctions)
 
@@ -5828,9 +6149,12 @@
         """
         Private method to calculate an adjusted position for showing calltips.
 
-        @param ctshift amount the calltip shall be shifted (integer)
-        @param pos position into the text (integer)
-        @return new position for the calltip (integer)
+        @param ctshift amount the calltip shall be shifted
+        @type int
+        @param pos position into the text
+        @type int
+        @return new position for the calltip
+        @rtype int
         """
         ct = pos
         if ctshift:
@@ -5863,8 +6187,10 @@
         """
         Private method to calculate the margin number based on a x position.
 
-        @param xPos x position (integer)
+        @param xPos x position
+        @type int
         @return margin number (integer, -1 for no margin)
+        @rtype int
         """
         width = 0
         for margin in range(5):
@@ -6166,7 +6492,8 @@
         Private method to handle the rereading of the file with a selected
         encoding.
 
-        @param act reference to the action that was triggered (QAction)
+        @param act reference to the action that was triggered
+        @type QAction
         """
         encoding = act.data()
         self.readFile(self.fileName, encoding=encoding)
@@ -6305,7 +6632,8 @@
         """
         Private method to check the autosave flags.
 
-        @return flag indicating this editor should be saved (boolean)
+        @return flag indicating this editor should be saved
+        @rtype bool
         """
         return (
             bool(self.fileName)
@@ -6585,7 +6913,8 @@
         """
         Public method to get the lines containing a coverage marker.
 
-        @return list of lines containing a coverage marker (list of integer)
+        @return list of lines containing a coverage marker
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -6601,7 +6930,8 @@
         """
         Public method to test, if there are coverage markers.
 
-        @return flag indicating the presence of coverage markers (boolean)
+        @return flag indicating the presence of coverage markers
+        @rtype bool
         """
         return len(self.notcoveredMarkers) > 0
 
@@ -6752,7 +7082,7 @@
                 self.setCursorPosition(line - 1, index)
                 self.ensureLineVisible(line - 1)
         else:
-            for handle in list(self.syntaxerrors.keys()):
+            for handle in list(self.syntaxerrors):
                 if self.markerLine(handle) == line - 1:
                     del self.syntaxerrors[handle]
                     self.markerDeleteHandle(handle)
@@ -6765,7 +7095,8 @@
         """
         Public method to get the lines containing a syntax error.
 
-        @return list of lines containing a syntax error (list of integer)
+        @return list of lines containing a syntax error
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -6781,7 +7112,8 @@
         """
         Public method to check for the presence of syntax errors.
 
-        @return flag indicating the presence of syntax errors (boolean)
+        @return flag indicating the presence of syntax errors
+        @rtype bool
         """
         return len(self.syntaxerrors) > 0
 
@@ -6804,7 +7136,7 @@
         """
         Public slot to handle the 'Clear all syntax error' context menu action.
         """
-        for handle in list(self.syntaxerrors.keys()):
+        for handle in list(self.syntaxerrors):
             line = self.markerLine(handle) + 1
             self.toggleSyntaxError(line, 0, False)
 
@@ -6909,7 +7241,7 @@
                     ):
                         self._warnings[handle].append(warn)
         else:
-            for handle in list(self._warnings.keys()):
+            for handle in list(self._warnings):
                 if self.markerLine(handle) == line - 1:
                     del self._warnings[handle]
                     self.markerDeleteHandle(handle)
@@ -6923,7 +7255,8 @@
         """
         Public method to get the lines containing a warning.
 
-        @return list of lines containing a warning (list of integer)
+        @return list of lines containing a warning
+        @rtype list of int
         """
         lines = []
         line = -1
@@ -6939,7 +7272,8 @@
         """
         Public method to check for the presence of warnings.
 
-        @return flag indicating the presence of warnings (boolean)
+        @return flag indicating the presence of warnings
+        @rtype bool
         """
         return len(self._warnings) > 0
 
@@ -7021,8 +7355,9 @@
 
         @param warningKind kind of warning to clear (Editor.WarningCode,
             Editor.WarningPython, Editor.WarningStyle)
-        """
-        for handle in list(self._warnings.keys()):
+        @type int
+        """
+        for handle in list(self._warnings):
             issues = []
             for msg, warningType in self._warnings[handle]:
                 if warningType == warningKind:
@@ -7139,7 +7474,8 @@
         """
         Private method to set the annotations for the given line.
 
-        @param line number of the line that needs annotation (integer)
+        @param line number of the line that needs annotation
+        @type int
         """
         if hasattr(QsciScintilla, "annotate"):
             warningAnnotations = []
@@ -7283,7 +7619,8 @@
         Private method to select a macro name from the list of macros.
 
         @return Tuple of macro name and a flag, indicating, if the user
-            pressed ok or canceled the operation. (string, boolean)
+            pressed ok or canceled the operation.
+        @rtype tuple of (str, bool)
         """
         qs = []
         for s in self.macros:
@@ -7473,7 +7810,8 @@
         ViewManager.closeEditor, which in turn calls our closeIt
         method.
 
-        @return flag indicating a successful close of the editor (boolean)
+        @return flag indicating a successful close of the editor
+        @rtype bool
         """
         return self.vm.closeEditor(self)
 
@@ -7567,50 +7905,16 @@
         @type QFocusEvent
         """
         self.recolor()
+
         self.vm.editActGrp.setEnabled(True)
         self.vm.editorActGrp.setEnabled(True)
         self.vm.copyActGrp.setEnabled(True)
         self.vm.viewActGrp.setEnabled(True)
         self.vm.searchActGrp.setEnabled(True)
+
         with contextlib.suppress(AttributeError):
             self.setCaretWidth(self.caretWidth)
         self.__updateReadOnly(False)
-        if (
-            self.vm.editorsCheckFocusInEnabled()
-            and not self.inReopenPrompt
-            and self.fileName
-            and pathlib.Path(self.fileName).exists()
-            and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified
-        ):
-            self.inReopenPrompt = True
-            if Preferences.getEditor("AutoReopen") and not self.isModified():
-                self.refresh()
-            else:
-                msg = self.tr(
-                    """<p>The file <b>{0}</b> has been changed while it"""
-                    """ was opened in eric. Reread it?</p>"""
-                ).format(self.fileName)
-                yesDefault = True
-                if self.isModified():
-                    msg += self.tr(
-                        """<br><b>Warning:</b> You will lose"""
-                        """ your changes upon reopening it."""
-                    )
-                    yesDefault = False
-                res = EricMessageBox.yesNo(
-                    self,
-                    self.tr("File changed"),
-                    msg,
-                    icon=EricMessageBox.Warning,
-                    yesDefault=yesDefault,
-                )
-                if res:
-                    self.refresh()
-                else:
-                    # do not prompt for this change again...
-                    self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
-            self.inReopenPrompt = False
-
         self.setCursorFlashTime(QApplication.cursorFlashTime())
 
         super().focusInEvent(event)
@@ -7793,8 +8097,11 @@
 
         @param bForce True to force change, False to only update and emit
                 signal if there was an attribute change.
-        """
-        if self.fileName == "" or not self.isLocalFile():
+        @type bool
+        """
+        if self.fileName == "" or not FileSystemUtilities.isPlainFileName(
+            self.fileName
+        ):
             return
 
         readOnly = self.checkReadOnly()
@@ -7816,10 +8123,57 @@
         @rtype bool
         """
         return (
-            self.isLocalFile() and not os.access(self.fileName, os.W_OK)
+            FileSystemUtilities.isPlainFileName(self.fileName)
+            and not os.access(self.fileName, os.W_OK)
         ) or self.isReadOnly()
 
     @pyqtSlot()
+    def checkRereadFile(self):
+        """
+        Public slot to check, if the file needs to be re-read, and refresh it if
+        needed.
+        """
+        if (
+            self.fileName
+            and pathlib.Path(self.fileName).exists()
+            and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified
+        ):
+            if Preferences.getEditor("AutoReopen") and not self.isModified():
+                self.refresh()
+            else:
+                msg = self.tr(
+                    """<p>The file <b>{0}</b> has been changed while it"""
+                    """ was opened in eric. Reread it?</p>"""
+                ).format(self.fileName)
+                yesDefault = True
+                if self.isModified():
+                    msg += self.tr(
+                        """<br><b>Warning:</b> You will lose"""
+                        """ your changes upon reopening it."""
+                    )
+                    yesDefault = False
+                res = EricMessageBox.yesNo(
+                    self,
+                    self.tr("File changed"),
+                    msg,
+                    icon=EricMessageBox.Warning,
+                    yesDefault=yesDefault,
+                )
+                if res:
+                    self.refresh()
+                else:
+                    # do not prompt for this change again...
+                    self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
+
+    @pyqtSlot()
+    def recordModificationTime(self):
+        """
+        Public slot to record the modification time of our file.
+        """
+        if self.fileName and pathlib.Path(self.fileName).exists():
+            self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
+
+    @pyqtSlot()
     def refresh(self):
         """
         Public slot to refresh the editor contents.
@@ -7849,7 +8203,7 @@
 
         # reread the file
         try:
-            self.readFile(self.fileName)
+            self.readFile(self.fileName, noempty=True)
         except OSError:
             # do not prompt for this change again...
             self.lastModified = QDateTime.currentDateTime()
@@ -7880,7 +8234,8 @@
         """
         Public method to set/reset a monospaced font.
 
-        @param on flag to indicate usage of a monospace font (boolean)
+        @param on flag to indicate usage of a monospace font
+        @type bool
         """
         if on:
             if not self.lexer_:
@@ -7912,7 +8267,8 @@
         """
         Protected method to handle the drag enter event.
 
-        @param event the drag enter event (QDragEnterEvent)
+        @param event the drag enter event
+        @type QDragEnterEvent
         """
         self.inDragDrop = event.mimeData().hasUrls()
         if self.inDragDrop:
@@ -7924,7 +8280,8 @@
         """
         Protected method to handle the drag move event.
 
-        @param event the drag move event (QDragMoveEvent)
+        @param event the drag move event
+        @type QDragMoveEvent
         """
         if self.inDragDrop:
             event.accept()
@@ -7935,7 +8292,8 @@
         """
         Protected method to handle the drag leave event.
 
-        @param event the drag leave event (QDragLeaveEvent)
+        @param event the drag leave event
+        @type QDragLeaveEvent
         """
         if self.inDragDrop:
             self.inDragDrop = False
@@ -7947,7 +8305,8 @@
         """
         Protected method to handle the drop event.
 
-        @param event the drop event (QDropEvent)
+        @param event the drop event
+        @type QDropEvent
         """
         if event.mimeData().hasUrls():
             for url in event.mimeData().urls():
@@ -7977,7 +8336,8 @@
         """
         Private method used to setup the Resources context sub menu.
 
-        @return reference to the generated menu (QMenu)
+        @return reference to the generated menu
+        @rtype QMenu
         """
         menu = QMenu(self.tr("Resources"))
 
@@ -8210,6 +8570,7 @@
         Public method to perform a simple editor command.
 
         @param cmd the scintilla command to be performed
+        @type int
         """
         if cmd == QsciScintilla.SCI_TAB:
             try:
@@ -8271,9 +8632,11 @@
         """
         Private method to apply a template by name.
 
-        @param templateName name of the template to apply (string)
+        @param templateName name of the template to apply
+        @type str
         @param language name of the language (group) to get the template
-            from (string)
+            from
+        @type str
         """
         try:
             templateViewer = ericApp().getObject("TemplateViewer")
@@ -8360,9 +8723,12 @@
         """
         Private method to set the spell checking language.
 
-        @param language spell checking language to be set (string)
-        @param pwl name of the personal/project word list (string)
-        @param pel name of the personal/project exclude list (string)
+        @param language spell checking language to be set
+        @type str
+        @param pwl name of the personal/project word list
+        @type str
+        @param pel name of the personal/project exclude list
+        @type str
         """
         if self.spell and self.spell.getLanguage() != language:
             self.spell.setLanguage(language, pwl=pwl, pel=pel)
@@ -8603,7 +8969,7 @@
         @return tuple indicating, if the editor is sharable, the sharing
             status, if it is inside a locally initiated shared edit session
             and if it is inside a remotely initiated shared edit session
-            (boolean, boolean, boolean, boolean)
+        @rtype tuple of (bool, bool, bool, bool)
         """
         return (
             (
@@ -8620,7 +8986,8 @@
         """
         Public method to handle a change of the connected state.
 
-        @param connected flag indicating the connected state (boolean)
+        @param connected flag indicating the connected state
+        @type bool
         """
         if not connected:
             self.__inRemoteSharedEdit = False
@@ -8634,7 +9001,8 @@
         """
         Public method to set the shared status of the editor.
 
-        @param share flag indicating the share status (boolean)
+        @param share flag indicating the share status
+        @type bool
         """
         self.__isShared = share
         if not share:
@@ -8671,7 +9039,8 @@
         """
         Public method to cancel a shared edit session for the editor.
 
-        @param send flag indicating to send the CancelEdit command (boolean)
+        @param send flag indicating to send the CancelEdit command
+        @type bool
         """
         self.__inSharedEdit = False
         self.__savedText = ""
@@ -8682,8 +9051,10 @@
         """
         Private method to send an editor command to remote editors.
 
-        @param token command token (string)
-        @param args arguments for the command (string)
+        @param token command token
+        @type str
+        @param args arguments for the command
+        @type str
         """
         if self.vm.isConnected():
             msg = ""
@@ -8719,7 +9090,8 @@
         """
         Private method to dispatch received commands.
 
-        @param command command to be processed (string)
+        @param command command to be processed
+        @type str
         """
         token, argsString = command.split(Editor.Separator, 1)
         if token == Editor.StartEditToken:
@@ -8762,9 +9134,12 @@
         Private method to determine change commands to convert old text into
         new text.
 
-        @param old old text (string)
-        @param new new text (string)
-        @return commands to change old into new (string)
+        @param old old text
+        @type str
+        @param new new text
+        @type str
+        @return commands to change old into new
+        @rtype str
         """
         oldL = old.splitlines()
         newL = new.splitlines()
@@ -8894,7 +9269,8 @@
         """
         Private slot to search the next occurrence of the current word.
 
-        @param forward flag indicating the search direction (boolean)
+        @param forward flag indicating the search direction
+        @type bool
         """
         self.hideFindIndicator()
         line, index = self.getCursorPosition()
@@ -8992,7 +9368,7 @@
             eol = self.getLineSeparator()
             lastWithEol = True
             newLines = []
-            for txt in sorted(selText.keys(), key=keyFun, reverse=reverse):
+            for txt in sorted(selText, key=keyFun, reverse=reverse):
                 for line in selText[txt]:
                     txt = txtLines[line]
                     if not txt.endswith(eol):
@@ -9135,7 +9511,7 @@
         @param name name of the plug-in
         @type str
         """
-        for key in list(self.__mouseClickHandlers.keys()):
+        for key in list(self.__mouseClickHandlers):
             if self.__mouseClickHandlers[key][0] == name:
                 del self.__mouseClickHandlers[key]
 
@@ -9225,7 +9601,7 @@
         """
         editorConfig = {}
 
-        if fileName and self.isLocalFile():
+        if fileName and FileSystemUtilities.isPlainFileName(self.fileName):
             try:
                 editorConfig = editorconfig.get_properties(fileName)
             except editorconfig.EditorConfigError:
@@ -9258,7 +9634,7 @@
         @type dict
         @return value of requested setting or None if nothing was found and
             nodefault parameter was True
-        @rtype any
+        @rtype Any
         """
         if config is None:
             config = self.__editorConfig
@@ -9319,7 +9695,7 @@
         @param option Preferences option key
         @type str
         @return value of requested setting
-        @rtype any
+        @rtype Any
         """
         return self.__getEditorConfig(option)
 
@@ -9330,7 +9706,7 @@
         @param option Preferences option key
         @type str
         @return override value; None in case nothing is defined
-        @rtype any
+        @rtype Any
         """
         if option in ("TabWidth", "IndentWidth"):
             overrides = Preferences.getEditor("TabIndentOverride")

eric ide

mercurial