src/eric7/QScintilla/Editor.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9214
bd28e56047d7
child 9264
18a7312cfdb3
child 9331
1f8780a59a0d
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
16 import re 16 import re
17 17
18 import editorconfig 18 import editorconfig
19 19
20 from PyQt6.QtCore import ( 20 from PyQt6.QtCore import (
21 pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QCryptographicHash, 21 pyqtSignal,
22 QEvent, QDateTime, QPoint, QSize 22 pyqtSlot,
23 Qt,
24 QDir,
25 QTimer,
26 QModelIndex,
27 QCryptographicHash,
28 QEvent,
29 QDateTime,
30 QPoint,
31 QSize,
23 ) 32 )
24 from PyQt6.QtGui import QPalette, QFont, QPixmap, QPainter, QActionGroup 33 from PyQt6.QtGui import QPalette, QFont, QPixmap, QPainter, QActionGroup
25 from PyQt6.QtWidgets import ( 34 from PyQt6.QtWidgets import QLineEdit, QDialog, QInputDialog, QApplication, QMenu
26 QLineEdit, QDialog, QInputDialog, QApplication, QMenu
27 )
28 from PyQt6.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog 35 from PyQt6.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog
29 from PyQt6.Qsci import QsciScintilla, QsciMacro, QsciStyledText 36 from PyQt6.Qsci import QsciScintilla, QsciMacro, QsciStyledText
30 37
31 from EricWidgets.EricApplication import ericApp 38 from EricWidgets.EricApplication import ericApp
32 from EricWidgets import EricFileDialog, EricMessageBox 39 from EricWidgets import EricFileDialog, EricMessageBox
53 EditorAutoCompletionListID = 1 60 EditorAutoCompletionListID = 1
54 TemplateCompletionListID = 2 61 TemplateCompletionListID = 2
55 ReferencesListID = 3 62 ReferencesListID = 3
56 63
57 ReferenceItem = collections.namedtuple( 64 ReferenceItem = collections.namedtuple(
58 "ReferenceItem", ["modulePath", "codeLine", "line", "column"]) 65 "ReferenceItem", ["modulePath", "codeLine", "line", "column"]
66 )
59 67
60 68
61 class Editor(QsciScintillaCompat): 69 class Editor(QsciScintillaCompat):
62 """ 70 """
63 Class implementing the editor component of the eric IDE. 71 Class implementing the editor component of the eric IDE.
64 72
65 @signal modificationStatusChanged(bool, QsciScintillaCompat) emitted when 73 @signal modificationStatusChanged(bool, QsciScintillaCompat) emitted when
66 the modification status has changed 74 the modification status has changed
67 @signal undoAvailable(bool) emitted to signal the undo availability 75 @signal undoAvailable(bool) emitted to signal the undo availability
68 @signal redoAvailable(bool) emitted to signal the redo availability 76 @signal redoAvailable(bool) emitted to signal the redo availability
69 @signal cursorChanged(str, int, int) emitted when the cursor position 77 @signal cursorChanged(str, int, int) emitted when the cursor position
106 @signal settingsRead() emitted to signal, that the settings have been read 114 @signal settingsRead() emitted to signal, that the settings have been read
107 and set 115 and set
108 @signal mouseDoubleClick(position, buttons) emitted to signal a mouse 116 @signal mouseDoubleClick(position, buttons) emitted to signal a mouse
109 double click somewhere in the editor area 117 double click somewhere in the editor area
110 """ 118 """
119
111 modificationStatusChanged = pyqtSignal(bool, QsciScintillaCompat) 120 modificationStatusChanged = pyqtSignal(bool, QsciScintillaCompat)
112 undoAvailable = pyqtSignal(bool) 121 undoAvailable = pyqtSignal(bool)
113 redoAvailable = pyqtSignal(bool) 122 redoAvailable = pyqtSignal(bool)
114 cursorChanged = pyqtSignal(str, int, int) 123 cursorChanged = pyqtSignal(str, int, int)
115 cursorLineChanged = pyqtSignal(int) 124 cursorLineChanged = pyqtSignal(int)
131 spellLanguageChanged = pyqtSignal(str) 140 spellLanguageChanged = pyqtSignal(str)
132 lastEditPositionAvailable = pyqtSignal() 141 lastEditPositionAvailable = pyqtSignal()
133 refreshed = pyqtSignal() 142 refreshed = pyqtSignal()
134 settingsRead = pyqtSignal() 143 settingsRead = pyqtSignal()
135 mouseDoubleClick = pyqtSignal(QPoint, int) 144 mouseDoubleClick = pyqtSignal(QPoint, int)
136 145
137 WarningCode = 1 146 WarningCode = 1
138 WarningStyle = 2 147 WarningStyle = 2
139 148
140 # Autocompletion icon definitions 149 # Autocompletion icon definitions
141 ClassID = 1 150 ClassID = 1
142 ClassProtectedID = 2 151 ClassProtectedID = 2
143 ClassPrivateID = 3 152 ClassPrivateID = 3
144 MethodID = 4 153 MethodID = 4
148 AttributeProtectedID = 8 157 AttributeProtectedID = 8
149 AttributePrivateID = 9 158 AttributePrivateID = 9
150 EnumID = 10 159 EnumID = 10
151 KeywordsID = 11 160 KeywordsID = 11
152 ModuleID = 12 161 ModuleID = 12
153 162
154 FromDocumentID = 99 163 FromDocumentID = 99
155 164
156 TemplateImageID = 100 165 TemplateImageID = 100
157 166
158 # Cooperation related definitions 167 # Cooperation related definitions
159 Separator = "@@@" 168 Separator = "@@@"
160 169
161 StartEditToken = "START_EDIT" 170 StartEditToken = "START_EDIT"
162 EndEditToken = "END_EDIT" 171 EndEditToken = "END_EDIT"
163 CancelEditToken = "CANCEL_EDIT" 172 CancelEditToken = "CANCEL_EDIT"
164 RequestSyncToken = "REQUEST_SYNC" 173 RequestSyncToken = "REQUEST_SYNC"
165 SyncToken = "SYNC" 174 SyncToken = "SYNC"
166 175
167 VcsConflictMarkerLineRegExpList = ( 176 VcsConflictMarkerLineRegExpList = (
168 r"""^<<<<<<< .*?$""", 177 r"""^<<<<<<< .*?$""",
169 r"""^\|\|\|\|\|\|\| .*?$""", 178 r"""^\|\|\|\|\|\|\| .*?$""",
170 r"""^=======.*?$""", 179 r"""^=======.*?$""",
171 r"""^>>>>>>> .*?$""", 180 r"""^>>>>>>> .*?$""",
172 ) 181 )
173 182
174 EncloseChars = { 183 EncloseChars = {
175 '"': '"', 184 '"': '"',
176 "'": "'", 185 "'": "'",
177 "(": "()", 186 "(": "()",
178 ")": "()", 187 ")": "()",
179 "{": "{}", # __IGNORE_WARNING_M613__ 188 "{": "{}", # __IGNORE_WARNING_M613__
180 "}": "{}", # __IGNORE_WARNING_M613__ 189 "}": "{}", # __IGNORE_WARNING_M613__
181 "[": "[]", 190 "[": "[]",
182 "]": "[]", 191 "]": "[]",
183 "<": "<>", 192 "<": "<>",
184 ">": "<>", 193 ">": "<>",
185 } 194 }
186 195
187 def __init__(self, dbs, fn="", vm=None, 196 def __init__(
188 filetype="", editor=None, tv=None, 197 self, dbs, fn="", vm=None, filetype="", editor=None, tv=None, parent=None
189 parent=None): 198 ):
190 """ 199 """
191 Constructor 200 Constructor
192 201
193 @param dbs reference to the debug server object 202 @param dbs reference to the debug server object
194 @type DebugServer 203 @type DebugServer
195 @param fn name of the file to be opened. If it is None, a new (empty) 204 @param fn name of the file to be opened. If it is None, a new (empty)
196 editor is opened. 205 editor is opened.
197 @type str 206 @type str
208 @exception OSError raised to indicate an issue accessing the file 217 @exception OSError raised to indicate an issue accessing the file
209 """ 218 """
210 super().__init__(parent) 219 super().__init__(parent)
211 self.setAttribute(Qt.WidgetAttribute.WA_KeyCompression) 220 self.setAttribute(Qt.WidgetAttribute.WA_KeyCompression)
212 self.setUtf8(True) 221 self.setUtf8(True)
213 222
214 self.enableMultiCursorSupport() 223 self.enableMultiCursorSupport()
215 224
216 self.dbs = dbs 225 self.dbs = dbs
217 self.taskViewer = tv 226 self.taskViewer = tv
218 self.__setFileName(fn) 227 self.__setFileName(fn)
219 self.vm = vm 228 self.vm = vm
220 self.filetype = filetype 229 self.filetype = filetype
221 self.filetypeByFlag = False 230 self.filetypeByFlag = False
222 self.noName = "" 231 self.noName = ""
223 self.project = ericApp().getObject("Project") 232 self.project = ericApp().getObject("Project")
224 233
225 # clear some variables 234 # clear some variables
226 self.lastHighlight = None # remember the last highlighted line 235 self.lastHighlight = None # remember the last highlighted line
227 self.lastErrorMarker = None # remember the last error line 236 self.lastErrorMarker = None # remember the last error line
228 self.lastCurrMarker = None # remember the last current line 237 self.lastCurrMarker = None # remember the last current line
229 238
230 self.breaks = {} 239 self.breaks = {}
231 # key: marker handle, 240 # key: marker handle,
232 # value: (lineno, condition, temporary, 241 # value: (lineno, condition, temporary,
233 # enabled, ignorecount) 242 # enabled, ignorecount)
234 self.bookmarks = [] 243 self.bookmarks = []
240 self.warnings = {} 249 self.warnings = {}
241 # key: marker handle 250 # key: marker handle
242 # value: list of (warning message, warning type) 251 # value: list of (warning message, warning type)
243 self.notcoveredMarkers = [] # just a list of marker handles 252 self.notcoveredMarkers = [] # just a list of marker handles
244 self.showingNotcoveredMarkers = False 253 self.showingNotcoveredMarkers = False
245 254
246 self.lexer_ = None 255 self.lexer_ = None
247 self.apiLanguage = '' 256 self.apiLanguage = ""
248 257
249 self.__loadEditorConfig() 258 self.__loadEditorConfig()
250 259
251 self.__lexerReset = False 260 self.__lexerReset = False
252 self.completer = None 261 self.completer = None
253 self.encoding = self.__getEditorConfig("DefaultEncoding") 262 self.encoding = self.__getEditorConfig("DefaultEncoding")
254 self.lastModified = 0 263 self.lastModified = 0
255 self.line = -1 264 self.line = -1
267 # true if we are in drop mode 276 # true if we are in drop mode
268 self.inLinesChanged = False 277 self.inLinesChanged = False
269 # true if we are propagating a lines changed event 278 # true if we are propagating a lines changed event
270 self.__hasTaskMarkers = False 279 self.__hasTaskMarkers = False
271 # no task markers present 280 # no task markers present
272 281
273 self.macros = {} # list of defined macros 282 self.macros = {} # list of defined macros
274 self.curMacro = None 283 self.curMacro = None
275 self.recording = False 284 self.recording = False
276 285
277 self.acAPI = False 286 self.acAPI = False
278 287
279 self.__lastEditPosition = None 288 self.__lastEditPosition = None
280 self.__annotationLines = 0 289 self.__annotationLines = 0
281 290
282 self.__docstringGenerator = None 291 self.__docstringGenerator = None
283 292
284 # list of clones 293 # list of clones
285 self.__clones = [] 294 self.__clones = []
286 295
287 # clear QScintilla defined keyboard commands 296 # clear QScintilla defined keyboard commands
288 # we do our own handling through the view manager 297 # we do our own handling through the view manager
289 self.clearAlternateKeys() 298 self.clearAlternateKeys()
290 self.clearKeys() 299 self.clearKeys()
291 300
292 self.__markerMap = EditorMarkerMap(self) 301 self.__markerMap = EditorMarkerMap(self)
293 302
294 # initialize the mark occurrences timer 303 # initialize the mark occurrences timer
295 self.__markOccurrencesTimer = QTimer(self) 304 self.__markOccurrencesTimer = QTimer(self)
296 self.__markOccurrencesTimer.setSingleShot(True) 305 self.__markOccurrencesTimer.setSingleShot(True)
297 self.__markOccurrencesTimer.setInterval( 306 self.__markOccurrencesTimer.setInterval(
298 Preferences.getEditor("MarkOccurrencesTimeout")) 307 Preferences.getEditor("MarkOccurrencesTimeout")
308 )
299 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences) 309 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences)
300 self.__markedText = "" 310 self.__markedText = ""
301 self.__searchIndicatorLines = [] 311 self.__searchIndicatorLines = []
302 312
303 # initialize some spellchecking stuff 313 # initialize some spellchecking stuff
304 self.spell = None 314 self.spell = None
305 self.lastLine = 0 315 self.lastLine = 0
306 self.lastIndex = 0 316 self.lastIndex = 0
307 self.__inSpellLanguageChanged = False 317 self.__inSpellLanguageChanged = False
308 318
309 # initialize some cooperation stuff 319 # initialize some cooperation stuff
310 self.__isSyncing = False 320 self.__isSyncing = False
311 self.__receivedWhileSyncing = [] 321 self.__receivedWhileSyncing = []
312 self.__savedText = "" 322 self.__savedText = ""
313 self.__inSharedEdit = False 323 self.__inSharedEdit = False
314 self.__isShared = False 324 self.__isShared = False
315 self.__inRemoteSharedEdit = False 325 self.__inRemoteSharedEdit = False
316 326
317 # connect signals before loading the text 327 # connect signals before loading the text
318 self.modificationChanged.connect(self.__modificationChanged) 328 self.modificationChanged.connect(self.__modificationChanged)
319 self.cursorPositionChanged.connect(self.__cursorPositionChanged) 329 self.cursorPositionChanged.connect(self.__cursorPositionChanged)
320 self.modificationAttempted.connect(self.__modificationReadOnly) 330 self.modificationAttempted.connect(self.__modificationReadOnly)
321 331
322 # define the margins markers 332 # define the margins markers
323 self.__changeMarkerSaved = self.markerDefine( 333 self.__changeMarkerSaved = self.markerDefine(
324 self.__createChangeMarkerPixmap( 334 self.__createChangeMarkerPixmap("OnlineChangeTraceMarkerSaved")
325 "OnlineChangeTraceMarkerSaved")) 335 )
326 self.__changeMarkerUnsaved = self.markerDefine( 336 self.__changeMarkerUnsaved = self.markerDefine(
327 self.__createChangeMarkerPixmap( 337 self.__createChangeMarkerPixmap("OnlineChangeTraceMarkerUnsaved")
328 "OnlineChangeTraceMarkerUnsaved")) 338 )
329 self.breakpoint = self.markerDefine( 339 self.breakpoint = self.markerDefine(UI.PixmapCache.getPixmap("break"))
330 UI.PixmapCache.getPixmap("break")) 340 self.cbreakpoint = self.markerDefine(UI.PixmapCache.getPixmap("cBreak"))
331 self.cbreakpoint = self.markerDefine( 341 self.tbreakpoint = self.markerDefine(UI.PixmapCache.getPixmap("tBreak"))
332 UI.PixmapCache.getPixmap("cBreak")) 342 self.tcbreakpoint = self.markerDefine(UI.PixmapCache.getPixmap("tCBreak"))
333 self.tbreakpoint = self.markerDefine( 343 self.dbreakpoint = self.markerDefine(UI.PixmapCache.getPixmap("breakDisabled"))
334 UI.PixmapCache.getPixmap("tBreak")) 344 self.bookmark = self.markerDefine(UI.PixmapCache.getPixmap("bookmark16"))
335 self.tcbreakpoint = self.markerDefine( 345 self.syntaxerror = self.markerDefine(UI.PixmapCache.getPixmap("syntaxError"))
336 UI.PixmapCache.getPixmap("tCBreak")) 346 self.notcovered = self.markerDefine(UI.PixmapCache.getPixmap("notcovered"))
337 self.dbreakpoint = self.markerDefine( 347 self.taskmarker = self.markerDefine(UI.PixmapCache.getPixmap("task"))
338 UI.PixmapCache.getPixmap("breakDisabled")) 348 self.warning = self.markerDefine(UI.PixmapCache.getPixmap("warning"))
339 self.bookmark = self.markerDefine( 349
340 UI.PixmapCache.getPixmap("bookmark16"))
341 self.syntaxerror = self.markerDefine(
342 UI.PixmapCache.getPixmap("syntaxError"))
343 self.notcovered = self.markerDefine(
344 UI.PixmapCache.getPixmap("notcovered"))
345 self.taskmarker = self.markerDefine(
346 UI.PixmapCache.getPixmap("task"))
347 self.warning = self.markerDefine(
348 UI.PixmapCache.getPixmap("warning"))
349
350 # define the line markers 350 # define the line markers
351 if Preferences.getEditor("LineMarkersBackground"): 351 if Preferences.getEditor("LineMarkersBackground"):
352 self.currentline = self.markerDefine(QsciScintilla.MarkerSymbol.Background)
353 self.errorline = self.markerDefine(QsciScintilla.MarkerSymbol.Background)
354 self.__setLineMarkerColours()
355 else:
352 self.currentline = self.markerDefine( 356 self.currentline = self.markerDefine(
353 QsciScintilla.MarkerSymbol.Background) 357 UI.PixmapCache.getPixmap("currentLineMarker")
358 )
354 self.errorline = self.markerDefine( 359 self.errorline = self.markerDefine(
355 QsciScintilla.MarkerSymbol.Background) 360 UI.PixmapCache.getPixmap("errorLineMarker")
356 self.__setLineMarkerColours() 361 )
357 else: 362
358 self.currentline = self.markerDefine(
359 UI.PixmapCache.getPixmap("currentLineMarker"))
360 self.errorline = self.markerDefine(
361 UI.PixmapCache.getPixmap("errorLineMarker"))
362
363 self.breakpointMask = ( 363 self.breakpointMask = (
364 (1 << self.breakpoint) | 364 (1 << self.breakpoint)
365 (1 << self.cbreakpoint) | 365 | (1 << self.cbreakpoint)
366 (1 << self.tbreakpoint) | 366 | (1 << self.tbreakpoint)
367 (1 << self.tcbreakpoint) | 367 | (1 << self.tcbreakpoint)
368 (1 << self.dbreakpoint) 368 | (1 << self.dbreakpoint)
369 ) 369 )
370 370
371 self.changeMarkersMask = ( 371 self.changeMarkersMask = (1 << self.__changeMarkerSaved) | (
372 (1 << self.__changeMarkerSaved) | 372 1 << self.__changeMarkerUnsaved
373 (1 << self.__changeMarkerUnsaved) 373 )
374 ) 374
375
376 # configure the margins 375 # configure the margins
377 self.__setMarginsDisplay() 376 self.__setMarginsDisplay()
378 self.linesChanged.connect(self.__resizeLinenoMargin) 377 self.linesChanged.connect(self.__resizeLinenoMargin)
379 378
380 self.marginClicked.connect(self.__marginClicked) 379 self.marginClicked.connect(self.__marginClicked)
381 380
382 # set the eol mode 381 # set the eol mode
383 self.__setEolMode() 382 self.__setEolMode()
384 383
385 # set the text display 384 # set the text display
386 self.__setTextDisplay() 385 self.__setTextDisplay()
387 386
388 # initialize the online syntax check timer 387 # initialize the online syntax check timer
389 try: 388 try:
390 self.syntaxCheckService = ericApp().getObject('SyntaxCheckService') 389 self.syntaxCheckService = ericApp().getObject("SyntaxCheckService")
391 self.syntaxCheckService.syntaxChecked.connect( 390 self.syntaxCheckService.syntaxChecked.connect(
392 self.__processSyntaxCheckResult) 391 self.__processSyntaxCheckResult
393 self.syntaxCheckService.error.connect( 392 )
394 self.__processSyntaxCheckError) 393 self.syntaxCheckService.error.connect(self.__processSyntaxCheckError)
395 self.__initOnlineSyntaxCheck() 394 self.__initOnlineSyntaxCheck()
396 except KeyError: 395 except KeyError:
397 self.syntaxCheckService = None 396 self.syntaxCheckService = None
398 397
399 self.isResourcesFile = False 398 self.isResourcesFile = False
400 if editor is None: 399 if editor is None:
401 if self.fileName: 400 if self.fileName:
402 if ( 401 if (
403 (pathlib.Path(self.fileName).stat().st_size // 1024) > 402 pathlib.Path(self.fileName).stat().st_size // 1024
404 Preferences.getEditor("WarnFilesize") 403 ) > Preferences.getEditor("WarnFilesize"):
405 ):
406 res = EricMessageBox.yesNo( 404 res = EricMessageBox.yesNo(
407 self, 405 self,
408 self.tr("Open File"), 406 self.tr("Open File"),
409 self.tr("""<p>The size of the file <b>{0}</b>""" 407 self.tr(
410 """ is <b>{1} KB</b>.""" 408 """<p>The size of the file <b>{0}</b>"""
411 """ Do you really want to load it?</p>""") 409 """ is <b>{1} KB</b>."""
412 .format( 410 """ Do you really want to load it?</p>"""
411 ).format(
413 self.fileName, 412 self.fileName,
414 pathlib.Path(self.fileName).stat().st_size // 1024 413 pathlib.Path(self.fileName).stat().st_size // 1024,
415 ), 414 ),
416 icon=EricMessageBox.Warning) 415 icon=EricMessageBox.Warning,
416 )
417 if not res: 417 if not res:
418 raise OSError() 418 raise OSError()
419 self.readFile(self.fileName, True) 419 self.readFile(self.fileName, True)
420 self.__bindLexer(self.fileName) 420 self.__bindLexer(self.fileName)
421 self.__bindCompleter(self.fileName) 421 self.__bindCompleter(self.fileName)
422 self.checkSyntax() 422 self.checkSyntax()
423 self.isResourcesFile = self.fileName.endswith(".qrc") 423 self.isResourcesFile = self.fileName.endswith(".qrc")
424 424
425 self.__convertTabs() 425 self.__convertTabs()
426 426
427 self.recolor() 427 self.recolor()
428 else: 428 else:
429 # clone the given editor 429 # clone the given editor
430 self.setDocument(editor.document()) 430 self.setDocument(editor.document())
431 self.breaks = editor.breaks 431 self.breaks = editor.breaks
433 self.syntaxerrors = editor.syntaxerrors 433 self.syntaxerrors = editor.syntaxerrors
434 self.notcoveredMarkers = editor.notcoveredMarkers 434 self.notcoveredMarkers = editor.notcoveredMarkers
435 self.showingNotcoveredMarkers = editor.showingNotcoveredMarkers 435 self.showingNotcoveredMarkers = editor.showingNotcoveredMarkers
436 self.isResourcesFile = editor.isResourcesFile 436 self.isResourcesFile = editor.isResourcesFile
437 self.lastModified = editor.lastModified 437 self.lastModified = editor.lastModified
438 438
439 self.addClone(editor) 439 self.addClone(editor)
440 editor.addClone(self) 440 editor.addClone(self)
441 441
442 self.gotoLine(1) 442 self.gotoLine(1)
443 443
444 # connect the mouse hover signals 444 # connect the mouse hover signals
445 self.SCN_DWELLSTART.connect(self.__showMouseHoverHelp) 445 self.SCN_DWELLSTART.connect(self.__showMouseHoverHelp)
446 self.SCN_DWELLEND.connect(self.__cancelMouseHoverHelp) 446 self.SCN_DWELLEND.connect(self.__cancelMouseHoverHelp)
447 self.__mouseHoverHelp = None 447 self.__mouseHoverHelp = None
448 self.__showingMouseHoverHelp = False 448 self.__showingMouseHoverHelp = False
449 449
450 # set the text display again 450 # set the text display again
451 self.__setTextDisplay() 451 self.__setTextDisplay()
452 452
453 # set the auto-completion function 453 # set the auto-completion function
454 self.__acContext = True 454 self.__acContext = True
455 self.__acText = "" 455 self.__acText = ""
456 self.__acCompletions = set() 456 self.__acCompletions = set()
457 self.__acCompletionsFinished = 0 457 self.__acCompletionsFinished = 0
458 self.__acCache = EricCache( 458 self.__acCache = EricCache(
459 size=Preferences.getEditor("AutoCompletionCacheSize")) 459 size=Preferences.getEditor("AutoCompletionCacheSize")
460 )
460 self.__acCache.setMaximumCacheTime( 461 self.__acCache.setMaximumCacheTime(
461 Preferences.getEditor("AutoCompletionCacheTime")) 462 Preferences.getEditor("AutoCompletionCacheTime")
462 self.__acCacheEnabled = Preferences.getEditor( 463 )
463 "AutoCompletionCacheEnabled") 464 self.__acCacheEnabled = Preferences.getEditor("AutoCompletionCacheEnabled")
464 self.__acTimer = QTimer(self) 465 self.__acTimer = QTimer(self)
465 self.__acTimer.setSingleShot(True) 466 self.__acTimer.setSingleShot(True)
466 self.__acTimer.setInterval( 467 self.__acTimer.setInterval(Preferences.getEditor("AutoCompletionTimeout"))
467 Preferences.getEditor("AutoCompletionTimeout"))
468 self.__acTimer.timeout.connect(self.__autoComplete) 468 self.__acTimer.timeout.connect(self.__autoComplete)
469 469
470 self.__acWatchdog = QTimer(self) 470 self.__acWatchdog = QTimer(self)
471 self.__acWatchdog.setSingleShot(True) 471 self.__acWatchdog.setSingleShot(True)
472 self.__acWatchdog.setInterval( 472 self.__acWatchdog.setInterval(
473 Preferences.getEditor("AutoCompletionWatchdogTime")) 473 Preferences.getEditor("AutoCompletionWatchdogTime")
474 )
474 self.__acWatchdog.timeout.connect(self.autoCompleteQScintilla) 475 self.__acWatchdog.timeout.connect(self.autoCompleteQScintilla)
475 476
476 self.userListActivated.connect(self.__completionListSelected) 477 self.userListActivated.connect(self.__completionListSelected)
477 self.SCN_CHARADDED.connect(self.__charAdded) 478 self.SCN_CHARADDED.connect(self.__charAdded)
478 self.SCN_AUTOCCANCELLED.connect(self.__autocompletionCancelled) 479 self.SCN_AUTOCCANCELLED.connect(self.__autocompletionCancelled)
479 480
480 self.__completionListHookFunctions = {} 481 self.__completionListHookFunctions = {}
481 self.__completionListAsyncHookFunctions = {} 482 self.__completionListAsyncHookFunctions = {}
482 self.__setAutoCompletion() 483 self.__setAutoCompletion()
483 484
484 # set the call-tips function 485 # set the call-tips function
485 self.__ctHookFunctions = {} 486 self.__ctHookFunctions = {}
486 self.__setCallTips() 487 self.__setCallTips()
487 488
488 # set the mouse click handlers (fired on mouse release) 489 # set the mouse click handlers (fired on mouse release)
489 self.__mouseClickHandlers = {} 490 self.__mouseClickHandlers = {}
490 # dictionary with tuple of keyboard modifier and mouse button as key 491 # dictionary with tuple of keyboard modifier and mouse button as key
491 # and tuple of plug-in name and function as value 492 # and tuple of plug-in name and function as value
492 493
493 sh = self.sizeHint() 494 sh = self.sizeHint()
494 if sh.height() < 300: 495 if sh.height() < 300:
495 sh.setHeight(300) 496 sh.setHeight(300)
496 self.resize(sh) 497 self.resize(sh)
497 498
498 # Make sure tabbing through a QWorkspace works. 499 # Make sure tabbing through a QWorkspace works.
499 self.setFocusPolicy(Qt.FocusPolicy.StrongFocus) 500 self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
500 501
501 self.__updateReadOnly(True) 502 self.__updateReadOnly(True)
502 503
503 self.setWhatsThis(self.tr( 504 self.setWhatsThis(
504 """<b>A Source Editor Window</b>""" 505 self.tr(
505 """<p>This window is used to display and edit a source file.""" 506 """<b>A Source Editor Window</b>"""
506 """ You can open as many of these as you like. The name of the""" 507 """<p>This window is used to display and edit a source file."""
507 """ file is displayed in the window's titlebar.</p>""" 508 """ You can open as many of these as you like. The name of the"""
508 """<p>In order to set breakpoints just click in the space""" 509 """ file is displayed in the window's titlebar.</p>"""
509 """ between the line numbers and the fold markers. Via the""" 510 """<p>In order to set breakpoints just click in the space"""
510 """ context menu of the margins they may be edited.</p>""" 511 """ between the line numbers and the fold markers. Via the"""
511 """<p>In order to set bookmarks just Shift click in the space""" 512 """ context menu of the margins they may be edited.</p>"""
512 """ between the line numbers and the fold markers.</p>""" 513 """<p>In order to set bookmarks just Shift click in the space"""
513 """<p>These actions can be reversed via the context menu.</p>""" 514 """ between the line numbers and the fold markers.</p>"""
514 """<p>Ctrl clicking on a syntax error marker shows some info""" 515 """<p>These actions can be reversed via the context menu.</p>"""
515 """ about this error.</p>""" 516 """<p>Ctrl clicking on a syntax error marker shows some info"""
516 )) 517 """ about this error.</p>"""
517 518 )
519 )
520
518 # Set the editors size, if it is too big for the view manager. 521 # Set the editors size, if it is too big for the view manager.
519 if self.vm is not None: 522 if self.vm is not None:
520 req = self.size() 523 req = self.size()
521 bnd = req.boundedTo(self.vm.size()) 524 bnd = req.boundedTo(self.vm.size())
522 525
523 if bnd.width() < req.width() or bnd.height() < req.height(): 526 if bnd.width() < req.width() or bnd.height() < req.height():
524 self.resize(bnd) 527 self.resize(bnd)
525 528
526 # set the autosave flag 529 # set the autosave flag
527 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0 530 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0
528 self.autosaveManuallyDisabled = False 531 self.autosaveManuallyDisabled = False
529 532
530 # code coverage related attributes 533 # code coverage related attributes
531 self.__coverageFile = "" 534 self.__coverageFile = ""
532 535
533 self.__initContextMenu() 536 self.__initContextMenu()
534 self.__initContextMenuMargins() 537 self.__initContextMenuMargins()
535 538
536 self.__checkEol() 539 self.__checkEol()
537 if editor is None: 540 if editor is None:
538 self.__checkLanguage() 541 self.__checkLanguage()
539 self.__checkEncoding() 542 self.__checkEncoding()
540 self.__checkSpellLanguage() 543 self.__checkSpellLanguage()
541 else: 544 else:
542 # it's a clone 545 # it's a clone
543 self.__languageChanged(editor.apiLanguage, propagate=False) 546 self.__languageChanged(editor.apiLanguage, propagate=False)
544 self.__encodingChanged(editor.encoding, propagate=False) 547 self.__encodingChanged(editor.encoding, propagate=False)
545 self.__spellLanguageChanged(editor.getSpellingLanguage(), 548 self.__spellLanguageChanged(editor.getSpellingLanguage(), propagate=False)
546 propagate=False)
547 # link the warnings to the original editor 549 # link the warnings to the original editor
548 self.warnings = editor.warnings 550 self.warnings = editor.warnings
549 551
550 self.setAcceptDrops(True) 552 self.setAcceptDrops(True)
551 553
552 # breakpoint handling 554 # breakpoint handling
553 self.breakpointModel = self.dbs.getBreakPointModel() 555 self.breakpointModel = self.dbs.getBreakPointModel()
554 self.__restoreBreakpoints() 556 self.__restoreBreakpoints()
555 self.breakpointModel.rowsAboutToBeRemoved.connect( 557 self.breakpointModel.rowsAboutToBeRemoved.connect(self.__deleteBreakPoints)
556 self.__deleteBreakPoints)
557 self.breakpointModel.dataAboutToBeChanged.connect( 558 self.breakpointModel.dataAboutToBeChanged.connect(
558 self.__breakPointDataAboutToBeChanged) 559 self.__breakPointDataAboutToBeChanged
559 self.breakpointModel.dataChanged.connect( 560 )
560 self.__changeBreakPoints) 561 self.breakpointModel.dataChanged.connect(self.__changeBreakPoints)
561 self.breakpointModel.rowsInserted.connect( 562 self.breakpointModel.rowsInserted.connect(self.__addBreakPoints)
562 self.__addBreakPoints)
563 self.SCN_MODIFIED.connect(self.__modified) 563 self.SCN_MODIFIED.connect(self.__modified)
564 564
565 # establish connection to some ViewManager action groups 565 # establish connection to some ViewManager action groups
566 self.addActions(self.vm.editorActGrp.actions()) 566 self.addActions(self.vm.editorActGrp.actions())
567 self.addActions(self.vm.editActGrp.actions()) 567 self.addActions(self.vm.editActGrp.actions())
568 self.addActions(self.vm.copyActGrp.actions()) 568 self.addActions(self.vm.copyActGrp.actions())
569 self.addActions(self.vm.viewActGrp.actions()) 569 self.addActions(self.vm.viewActGrp.actions())
570 570
571 # register images to be shown in autocompletion lists 571 # register images to be shown in autocompletion lists
572 self.__registerImages() 572 self.__registerImages()
573 573
574 # connect signals after loading the text 574 # connect signals after loading the text
575 self.textChanged.connect(self.__textChanged) 575 self.textChanged.connect(self.__textChanged)
576 576
577 # initialize the online change trace timer 577 # initialize the online change trace timer
578 self.__initOnlineChangeTrace() 578 self.__initOnlineChangeTrace()
579 579
580 if ( 580 if (
581 self.fileName and 581 self.fileName
582 self.project.isOpen() and 582 and self.project.isOpen()
583 self.project.isProjectSource(self.fileName) 583 and self.project.isProjectSource(self.fileName)
584 ): 584 ):
585 self.project.projectPropertiesChanged.connect( 585 self.project.projectPropertiesChanged.connect(
586 self.__projectPropertiesChanged) 586 self.__projectPropertiesChanged
587 587 )
588
588 self.grabGesture(Qt.GestureType.PinchGesture) 589 self.grabGesture(Qt.GestureType.PinchGesture)
589 590
590 self.SCN_ZOOM.connect(self.__markerMap.update) 591 self.SCN_ZOOM.connect(self.__markerMap.update)
591 self.__markerMap.update() 592 self.__markerMap.update()
592 593
593 def __setFileName(self, name): 594 def __setFileName(self, name):
594 """ 595 """
595 Private method to set the file name of the current file. 596 Private method to set the file name of the current file.
596 597
597 @param name name of the current file 598 @param name name of the current file
598 @type str 599 @type str
599 """ 600 """
600 self.fileName = name 601 self.fileName = name
601 602
602 if self.fileName: 603 if self.fileName:
603 self.__fileNameExtension = ( 604 self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower()
604 os.path.splitext(self.fileName)[1][1:].lower()
605 )
606 else: 605 else:
607 self.__fileNameExtension = "" 606 self.__fileNameExtension = ""
608 607
609 def __registerImages(self): 608 def __registerImages(self):
610 """ 609 """
611 Private method to register images for autocompletion lists. 610 Private method to register images for autocompletion lists.
612 """ 611 """
613 # finale size of the completion images 612 # finale size of the completion images
614 imageSize = QSize(22, 22) 613 imageSize = QSize(22, 22)
615 614
616 self.registerImage( 615 self.registerImage(self.ClassID, UI.PixmapCache.getPixmap("class", imageSize))
617 self.ClassID,
618 UI.PixmapCache.getPixmap("class", imageSize))
619 self.registerImage( 616 self.registerImage(
620 self.ClassProtectedID, 617 self.ClassProtectedID,
621 UI.PixmapCache.getPixmap("class_protected", imageSize)) 618 UI.PixmapCache.getPixmap("class_protected", imageSize),
619 )
622 self.registerImage( 620 self.registerImage(
623 self.ClassPrivateID, 621 self.ClassPrivateID, UI.PixmapCache.getPixmap("class_private", imageSize)
624 UI.PixmapCache.getPixmap("class_private", imageSize)) 622 )
625 self.registerImage( 623 self.registerImage(self.MethodID, UI.PixmapCache.getPixmap("method", imageSize))
626 self.MethodID,
627 UI.PixmapCache.getPixmap("method", imageSize))
628 self.registerImage( 624 self.registerImage(
629 self.MethodProtectedID, 625 self.MethodProtectedID,
630 UI.PixmapCache.getPixmap("method_protected", imageSize)) 626 UI.PixmapCache.getPixmap("method_protected", imageSize),
627 )
631 self.registerImage( 628 self.registerImage(
632 self.MethodPrivateID, 629 self.MethodPrivateID, UI.PixmapCache.getPixmap("method_private", imageSize)
633 UI.PixmapCache.getPixmap("method_private", imageSize)) 630 )
634 self.registerImage( 631 self.registerImage(
635 self.AttributeID, 632 self.AttributeID, UI.PixmapCache.getPixmap("attribute", imageSize)
636 UI.PixmapCache.getPixmap("attribute", imageSize)) 633 )
637 self.registerImage( 634 self.registerImage(
638 self.AttributeProtectedID, 635 self.AttributeProtectedID,
639 UI.PixmapCache.getPixmap("attribute_protected", imageSize)) 636 UI.PixmapCache.getPixmap("attribute_protected", imageSize),
637 )
640 self.registerImage( 638 self.registerImage(
641 self.AttributePrivateID, 639 self.AttributePrivateID,
642 UI.PixmapCache.getPixmap("attribute_private", imageSize)) 640 UI.PixmapCache.getPixmap("attribute_private", imageSize),
641 )
642 self.registerImage(self.EnumID, UI.PixmapCache.getPixmap("enum", imageSize))
643 self.registerImage( 643 self.registerImage(
644 self.EnumID, 644 self.KeywordsID, UI.PixmapCache.getPixmap("keywords", imageSize)
645 UI.PixmapCache.getPixmap("enum", imageSize)) 645 )
646 self.registerImage(self.ModuleID, UI.PixmapCache.getPixmap("module", imageSize))
647
646 self.registerImage( 648 self.registerImage(
647 self.KeywordsID, 649 self.FromDocumentID, UI.PixmapCache.getPixmap("editor", imageSize)
648 UI.PixmapCache.getPixmap("keywords", imageSize)) 650 )
651
649 self.registerImage( 652 self.registerImage(
650 self.ModuleID, 653 self.TemplateImageID, UI.PixmapCache.getPixmap("templateViewer", imageSize)
651 UI.PixmapCache.getPixmap("module", imageSize)) 654 )
652 655
653 self.registerImage(
654 self.FromDocumentID,
655 UI.PixmapCache.getPixmap("editor", imageSize))
656
657 self.registerImage(
658 self.TemplateImageID,
659 UI.PixmapCache.getPixmap("templateViewer", imageSize))
660
661 def addClone(self, editor): 656 def addClone(self, editor):
662 """ 657 """
663 Public method to add a clone to our list. 658 Public method to add a clone to our list.
664 659
665 @param editor reference to the cloned editor 660 @param editor reference to the cloned editor
666 @type Editor 661 @type Editor
667 """ 662 """
668 self.__clones.append(editor) 663 self.__clones.append(editor)
669 664
670 editor.editorRenamed.connect(self.fileRenamed) 665 editor.editorRenamed.connect(self.fileRenamed)
671 editor.languageChanged.connect(self.languageChanged) 666 editor.languageChanged.connect(self.languageChanged)
672 editor.eolChanged.connect(self.__eolChanged) 667 editor.eolChanged.connect(self.__eolChanged)
673 editor.encodingChanged.connect(self.__encodingChanged) 668 editor.encodingChanged.connect(self.__encodingChanged)
674 editor.spellLanguageChanged.connect(self.__spellLanguageChanged) 669 editor.spellLanguageChanged.connect(self.__spellLanguageChanged)
675 670
676 def removeClone(self, editor): 671 def removeClone(self, editor):
677 """ 672 """
678 Public method to remove a clone from our list. 673 Public method to remove a clone from our list.
679 674
680 @param editor reference to the cloned editor 675 @param editor reference to the cloned editor
681 @type Editor 676 @type Editor
682 """ 677 """
683 if editor in self.__clones: 678 if editor in self.__clones:
684 editor.editorRenamed.disconnect(self.fileRenamed) 679 editor.editorRenamed.disconnect(self.fileRenamed)
685 editor.languageChanged.disconnect(self.languageChanged) 680 editor.languageChanged.disconnect(self.languageChanged)
686 editor.eolChanged.disconnect(self.__eolChanged) 681 editor.eolChanged.disconnect(self.__eolChanged)
687 editor.encodingChanged.disconnect(self.__encodingChanged) 682 editor.encodingChanged.disconnect(self.__encodingChanged)
688 editor.spellLanguageChanged.disconnect(self.__spellLanguageChanged) 683 editor.spellLanguageChanged.disconnect(self.__spellLanguageChanged)
689 self.__clones.remove(editor) 684 self.__clones.remove(editor)
690 685
691 def isClone(self, editor): 686 def isClone(self, editor):
692 """ 687 """
693 Public method to test, if the given editor is a clone. 688 Public method to test, if the given editor is a clone.
694 689
695 @param editor reference to the cloned editor 690 @param editor reference to the cloned editor
696 @type Editor 691 @type Editor
697 @return flag indicating a clone 692 @return flag indicating a clone
698 @rtype bool 693 @rtype bool
699 """ 694 """
700 return editor in self.__clones 695 return editor in self.__clones
701 696
702 def __bindName(self, line0): 697 def __bindName(self, line0):
703 """ 698 """
704 Private method to generate a dummy filename for binding a lexer. 699 Private method to generate a dummy filename for binding a lexer.
705 700
706 @param line0 first line of text to use in the generation process 701 @param line0 first line of text to use in the generation process
707 (string) 702 (string)
708 @return dummy file name to be used for binding a lexer (string) 703 @return dummy file name to be used for binding a lexer (string)
709 """ 704 """
710 bindName = "" 705 bindName = ""
711 line0 = line0.lower() 706 line0 = line0.lower()
712 707
713 # check first line if it does not start with #! 708 # check first line if it does not start with #!
714 if line0.startswith(("<html", "<!doctype html", "<?php")): 709 if line0.startswith(("<html", "<!doctype html", "<?php")):
715 bindName = "dummy.html" 710 bindName = "dummy.html"
716 elif line0.startswith(("<?xml", "<!doctype")): 711 elif line0.startswith(("<?xml", "<!doctype")):
717 bindName = "dummy.xml" 712 bindName = "dummy.xml"
718 elif line0.startswith("index: "): 713 elif line0.startswith("index: "):
719 bindName = "dummy.diff" 714 bindName = "dummy.diff"
720 elif line0.startswith("\\documentclass"): 715 elif line0.startswith("\\documentclass"):
721 bindName = "dummy.tex" 716 bindName = "dummy.tex"
722 717
723 if not bindName and self.filetype: 718 if not bindName and self.filetype:
724 # check filetype 719 # check filetype
725 from . import Lexers 720 from . import Lexers
721
726 supportedLanguages = Lexers.getSupportedLanguages() 722 supportedLanguages = Lexers.getSupportedLanguages()
727 if self.filetype in supportedLanguages: 723 if self.filetype in supportedLanguages:
728 bindName = supportedLanguages[self.filetype][1] 724 bindName = supportedLanguages[self.filetype][1]
729 elif self.filetype in ["Python", "Python3", "MicroPython"]: 725 elif self.filetype in ["Python", "Python3", "MicroPython"]:
730 bindName = "dummy.py" 726 bindName = "dummy.py"
731 727
732 if not bindName and line0.startswith("#!"): 728 if not bindName and line0.startswith("#!"):
733 # #! marker detection 729 # #! marker detection
734 if ( 730 if (
735 "python3" in line0 or 731 "python3" in line0
736 "python" in line0 or 732 or "python" in line0
737 "pypy3" in line0 or 733 or "pypy3" in line0
738 "pypy" in line0 734 or "pypy" in line0
739 ): 735 ):
740 bindName = "dummy.py" 736 bindName = "dummy.py"
741 self.filetype = "Python3" 737 self.filetype = "Python3"
742 elif ("/bash" in line0 or "/sh" in line0): 738 elif "/bash" in line0 or "/sh" in line0:
743 bindName = "dummy.sh" 739 bindName = "dummy.sh"
744 elif "ruby" in line0: 740 elif "ruby" in line0:
745 bindName = "dummy.rb" 741 bindName = "dummy.rb"
746 self.filetype = "Ruby" 742 self.filetype = "Ruby"
747 elif "perl" in line0: 743 elif "perl" in line0:
749 elif "lua" in line0: 745 elif "lua" in line0:
750 bindName = "dummy.lua" 746 bindName = "dummy.lua"
751 elif "dmd" in line0: 747 elif "dmd" in line0:
752 bindName = "dummy.d" 748 bindName = "dummy.d"
753 self.filetype = "D" 749 self.filetype = "D"
754 750
755 if not bindName: 751 if not bindName:
756 # mode line detection: -*- mode: python -*- 752 # mode line detection: -*- mode: python -*-
757 match = re.search(r"mode[:=]\s*([-\w_.]+)", line0) 753 match = re.search(r"mode[:=]\s*([-\w_.]+)", line0)
758 if match: 754 if match:
759 mode = match.group(1).lower() 755 mode = match.group(1).lower()
768 elif mode == "lua": 764 elif mode == "lua":
769 bindName = "dummy.lua" 765 bindName = "dummy.lua"
770 elif mode in ["dmd", "d"]: 766 elif mode in ["dmd", "d"]:
771 bindName = "dummy.d" 767 bindName = "dummy.d"
772 self.filetype = "D" 768 self.filetype = "D"
773 769
774 if not bindName: 770 if not bindName:
775 bindName = self.fileName 771 bindName = self.fileName
776 772
777 return bindName 773 return bindName
778 774
779 def getMenu(self, menuName): 775 def getMenu(self, menuName):
780 """ 776 """
781 Public method to get a reference to the main context menu or a submenu. 777 Public method to get a reference to the main context menu or a submenu.
782 778
783 @param menuName name of the menu (string) 779 @param menuName name of the menu (string)
784 @return reference to the requested menu (QMenu) or None 780 @return reference to the requested menu (QMenu) or None
785 """ 781 """
786 try: 782 try:
787 return self.__menus[menuName] 783 return self.__menus[menuName]
788 except KeyError: 784 except KeyError:
789 return None 785 return None
790 786
791 def hasMiniMenu(self): 787 def hasMiniMenu(self):
792 """ 788 """
793 Public method to check the miniMenu flag. 789 Public method to check the miniMenu flag.
794 790
795 @return flag indicating a minimized context menu (boolean) 791 @return flag indicating a minimized context menu (boolean)
796 """ 792 """
797 return self.miniMenu 793 return self.miniMenu
798 794
799 def __initContextMenu(self): 795 def __initContextMenu(self):
800 """ 796 """
801 Private method used to setup the context menu. 797 Private method used to setup the context menu.
802 """ 798 """
803 self.miniMenu = Preferences.getEditor("MiniContextMenu") 799 self.miniMenu = Preferences.getEditor("MiniContextMenu")
804 800
805 self.menuActs = {} 801 self.menuActs = {}
806 self.menu = QMenu() 802 self.menu = QMenu()
807 self.__menus = { 803 self.__menus = {
808 "Main": self.menu, 804 "Main": self.menu,
809 } 805 }
810 806
811 self.languagesMenu = self.__initContextMenuLanguages() 807 self.languagesMenu = self.__initContextMenuLanguages()
812 self.__menus["Languages"] = self.languagesMenu 808 self.__menus["Languages"] = self.languagesMenu
813 if self.isResourcesFile: 809 if self.isResourcesFile:
814 self.resourcesMenu = self.__initContextMenuResources() 810 self.resourcesMenu = self.__initContextMenuResources()
815 self.__menus["Resources"] = self.resourcesMenu 811 self.__menus["Resources"] = self.resourcesMenu
830 self.__menus["Eol"] = self.eolMenu 826 self.__menus["Eol"] = self.eolMenu
831 self.encodingsMenu = self.__initContextMenuEncodings() 827 self.encodingsMenu = self.__initContextMenuEncodings()
832 self.__menus["Encodings"] = self.encodingsMenu 828 self.__menus["Encodings"] = self.encodingsMenu
833 self.spellCheckMenu = self.__initContextMenuSpellCheck() 829 self.spellCheckMenu = self.__initContextMenuSpellCheck()
834 self.__menus["SpellCheck"] = self.spellCheckMenu 830 self.__menus["SpellCheck"] = self.spellCheckMenu
835 831
836 self.menuActs["Undo"] = self.menu.addAction( 832 self.menuActs["Undo"] = self.menu.addAction(
837 UI.PixmapCache.getIcon("editUndo"), 833 UI.PixmapCache.getIcon("editUndo"), self.tr("Undo"), self.undo
838 self.tr('Undo'), self.undo) 834 )
839 self.menuActs["Redo"] = self.menu.addAction( 835 self.menuActs["Redo"] = self.menu.addAction(
840 UI.PixmapCache.getIcon("editRedo"), 836 UI.PixmapCache.getIcon("editRedo"), self.tr("Redo"), self.redo
841 self.tr('Redo'), self.redo) 837 )
842 self.menuActs["Revert"] = self.menu.addAction( 838 self.menuActs["Revert"] = self.menu.addAction(
843 self.tr("Revert to last saved state"), 839 self.tr("Revert to last saved state"), self.revertToUnmodified
844 self.revertToUnmodified) 840 )
845 self.menu.addSeparator() 841 self.menu.addSeparator()
846 self.menuActs["Cut"] = self.menu.addAction( 842 self.menuActs["Cut"] = self.menu.addAction(
847 UI.PixmapCache.getIcon("editCut"), 843 UI.PixmapCache.getIcon("editCut"), self.tr("Cut"), self.cut
848 self.tr('Cut'), self.cut) 844 )
849 self.menuActs["Copy"] = self.menu.addAction( 845 self.menuActs["Copy"] = self.menu.addAction(
850 UI.PixmapCache.getIcon("editCopy"), 846 UI.PixmapCache.getIcon("editCopy"), self.tr("Copy"), self.copy
851 self.tr('Copy'), self.copy) 847 )
852 self.menuActs["Paste"] = self.menu.addAction( 848 self.menuActs["Paste"] = self.menu.addAction(
853 UI.PixmapCache.getIcon("editPaste"), 849 UI.PixmapCache.getIcon("editPaste"), self.tr("Paste"), self.paste
854 self.tr('Paste'), self.paste) 850 )
855 if not self.miniMenu: 851 if not self.miniMenu:
856 self.menu.addSeparator() 852 self.menu.addSeparator()
857 self.menu.addAction( 853 self.menu.addAction(
858 UI.PixmapCache.getIcon("editIndent"), 854 UI.PixmapCache.getIcon("editIndent"),
859 self.tr('Indent'), self.indentLineOrSelection) 855 self.tr("Indent"),
856 self.indentLineOrSelection,
857 )
860 self.menu.addAction( 858 self.menu.addAction(
861 UI.PixmapCache.getIcon("editUnindent"), 859 UI.PixmapCache.getIcon("editUnindent"),
862 self.tr('Unindent'), self.unindentLineOrSelection) 860 self.tr("Unindent"),
861 self.unindentLineOrSelection,
862 )
863 self.menuActs["Comment"] = self.menu.addAction( 863 self.menuActs["Comment"] = self.menu.addAction(
864 UI.PixmapCache.getIcon("editComment"), 864 UI.PixmapCache.getIcon("editComment"),
865 self.tr('Comment'), self.commentLineOrSelection) 865 self.tr("Comment"),
866 self.commentLineOrSelection,
867 )
866 self.menuActs["Uncomment"] = self.menu.addAction( 868 self.menuActs["Uncomment"] = self.menu.addAction(
867 UI.PixmapCache.getIcon("editUncomment"), 869 UI.PixmapCache.getIcon("editUncomment"),
868 self.tr('Uncomment'), self.uncommentLineOrSelection) 870 self.tr("Uncomment"),
871 self.uncommentLineOrSelection,
872 )
869 self.menu.addSeparator() 873 self.menu.addSeparator()
870 self.menuActs["Docstring"] = self.menu.addAction( 874 self.menuActs["Docstring"] = self.menu.addAction(
871 self.tr("Generate Docstring"), 875 self.tr("Generate Docstring"), self.__insertDocstring
872 self.__insertDocstring) 876 )
873 self.menu.addSeparator() 877 self.menu.addSeparator()
874 self.menu.addAction( 878 self.menu.addAction(self.tr("Select to brace"), self.selectToMatchingBrace)
875 self.tr('Select to brace'), self.selectToMatchingBrace) 879 self.menu.addAction(self.tr("Select all"), self.__selectAll)
876 self.menu.addAction(self.tr('Select all'), self.__selectAll) 880 self.menu.addAction(self.tr("Deselect all"), self.__deselectAll)
877 self.menu.addAction(
878 self.tr('Deselect all'), self.__deselectAll)
879 self.menuActs["ExecuteSelection"] = self.menu.addAction( 881 self.menuActs["ExecuteSelection"] = self.menu.addAction(
880 self.tr("Execute Selection In Console"), 882 self.tr("Execute Selection In Console"), self.__executeSelection
881 self.__executeSelection) 883 )
882 else: 884 else:
883 self.menuActs["ExecuteSelection"] = None 885 self.menuActs["ExecuteSelection"] = None
884 self.menu.addSeparator() 886 self.menu.addSeparator()
885 self.menu.addMenu(self.spellCheckMenu) 887 self.menu.addMenu(self.spellCheckMenu)
886 self.menu.addSeparator() 888 self.menu.addSeparator()
887 self.menuActs["Languages"] = self.menu.addMenu(self.languagesMenu) 889 self.menuActs["Languages"] = self.menu.addMenu(self.languagesMenu)
888 self.menuActs["Encodings"] = self.menu.addMenu(self.encodingsMenu) 890 self.menuActs["Encodings"] = self.menu.addMenu(self.encodingsMenu)
889 self.menuActs["Eol"] = self.menu.addMenu(self.eolMenu) 891 self.menuActs["Eol"] = self.menu.addMenu(self.eolMenu)
890 self.menu.addSeparator() 892 self.menu.addSeparator()
891 self.menuActs["MonospacedFont"] = self.menu.addAction( 893 self.menuActs["MonospacedFont"] = self.menu.addAction(
892 self.tr("Use Monospaced Font"), 894 self.tr("Use Monospaced Font"), self.handleMonospacedEnable
893 self.handleMonospacedEnable) 895 )
894 self.menuActs["MonospacedFont"].setCheckable(True) 896 self.menuActs["MonospacedFont"].setCheckable(True)
895 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) 897 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced)
896 self.menuActs["AutosaveEnable"] = self.menu.addAction( 898 self.menuActs["AutosaveEnable"] = self.menu.addAction(
897 self.tr("Autosave enabled"), self.__autosaveEnable) 899 self.tr("Autosave enabled"), self.__autosaveEnable
900 )
898 self.menuActs["AutosaveEnable"].setCheckable(True) 901 self.menuActs["AutosaveEnable"].setCheckable(True)
899 self.menuActs["AutosaveEnable"].setChecked(self.autosaveEnabled) 902 self.menuActs["AutosaveEnable"].setChecked(self.autosaveEnabled)
900 self.menuActs["TypingAidsEnabled"] = self.menu.addAction( 903 self.menuActs["TypingAidsEnabled"] = self.menu.addAction(
901 self.tr("Typing aids enabled"), self.__toggleTypingAids) 904 self.tr("Typing aids enabled"), self.__toggleTypingAids
905 )
902 self.menuActs["TypingAidsEnabled"].setCheckable(True) 906 self.menuActs["TypingAidsEnabled"].setCheckable(True)
903 self.menuActs["TypingAidsEnabled"].setEnabled( 907 self.menuActs["TypingAidsEnabled"].setEnabled(self.completer is not None)
904 self.completer is not None)
905 self.menuActs["TypingAidsEnabled"].setChecked( 908 self.menuActs["TypingAidsEnabled"].setChecked(
906 self.completer is not None and self.completer.isEnabled()) 909 self.completer is not None and self.completer.isEnabled()
910 )
907 self.menuActs["AutoCompletionEnable"] = self.menu.addAction( 911 self.menuActs["AutoCompletionEnable"] = self.menu.addAction(
908 self.tr("Automatic Completion enabled"), 912 self.tr("Automatic Completion enabled"), self.__toggleAutoCompletionEnable
909 self.__toggleAutoCompletionEnable) 913 )
910 self.menuActs["AutoCompletionEnable"].setCheckable(True) 914 self.menuActs["AutoCompletionEnable"].setCheckable(True)
911 self.menuActs["AutoCompletionEnable"].setChecked( 915 self.menuActs["AutoCompletionEnable"].setChecked(
912 self.autoCompletionThreshold() != -1) 916 self.autoCompletionThreshold() != -1
917 )
913 if not self.isResourcesFile: 918 if not self.isResourcesFile:
914 self.menu.addMenu(self.autocompletionMenu) 919 self.menu.addMenu(self.autocompletionMenu)
915 self.menuActs["calltip"] = self.menu.addAction( 920 self.menuActs["calltip"] = self.menu.addAction(
916 self.tr('Calltip'), self.callTip) 921 self.tr("Calltip"), self.callTip
922 )
917 self.menuActs["codeInfo"] = self.menu.addAction( 923 self.menuActs["codeInfo"] = self.menu.addAction(
918 self.tr('Code Info'), self.__showCodeInfo) 924 self.tr("Code Info"), self.__showCodeInfo
925 )
919 self.menu.addSeparator() 926 self.menu.addSeparator()
920 if self.isResourcesFile: 927 if self.isResourcesFile:
921 self.menu.addMenu(self.resourcesMenu) 928 self.menu.addMenu(self.resourcesMenu)
922 else: 929 else:
923 self.menuActs["Check"] = self.menu.addMenu(self.checksMenu) 930 self.menuActs["Check"] = self.menu.addMenu(self.checksMenu)
927 self.menu.addSeparator() 934 self.menu.addSeparator()
928 self.menuActs["Tools"] = self.menu.addMenu(self.toolsMenu) 935 self.menuActs["Tools"] = self.menu.addMenu(self.toolsMenu)
929 self.menu.addSeparator() 936 self.menu.addSeparator()
930 self.menu.addAction( 937 self.menu.addAction(
931 UI.PixmapCache.getIcon("documentNewView"), 938 UI.PixmapCache.getIcon("documentNewView"),
932 self.tr('New Document View'), self.__newView) 939 self.tr("New Document View"),
940 self.__newView,
941 )
933 self.menuActs["NewSplit"] = self.menu.addAction( 942 self.menuActs["NewSplit"] = self.menu.addAction(
934 UI.PixmapCache.getIcon("splitVertical"), 943 UI.PixmapCache.getIcon("splitVertical"),
935 self.tr('New Document View (with new split)'), 944 self.tr("New Document View (with new split)"),
936 self.__newViewNewSplit) 945 self.__newViewNewSplit,
946 )
937 self.menuActs["NewSplit"].setEnabled(self.vm.canSplit()) 947 self.menuActs["NewSplit"].setEnabled(self.vm.canSplit())
938 self.menu.addSeparator() 948 self.menu.addSeparator()
939 self.reopenEncodingMenu = self.__initContextMenuReopenWithEncoding() 949 self.reopenEncodingMenu = self.__initContextMenuReopenWithEncoding()
940 self.menuActs["Reopen"] = self.menu.addMenu(self.reopenEncodingMenu) 950 self.menuActs["Reopen"] = self.menu.addMenu(self.reopenEncodingMenu)
941 self.menuActs["Save"] = self.menu.addAction( 951 self.menuActs["Save"] = self.menu.addAction(
942 UI.PixmapCache.getIcon("fileSave"), 952 UI.PixmapCache.getIcon("fileSave"), self.tr("Save"), self.__contextSave
943 self.tr('Save'), self.__contextSave) 953 )
944 self.menu.addAction( 954 self.menu.addAction(
945 UI.PixmapCache.getIcon("fileSaveAs"), 955 UI.PixmapCache.getIcon("fileSaveAs"),
946 self.tr('Save As...'), self.__contextSaveAs) 956 self.tr("Save As..."),
957 self.__contextSaveAs,
958 )
947 self.menu.addAction( 959 self.menu.addAction(
948 UI.PixmapCache.getIcon("fileSaveCopy"), 960 UI.PixmapCache.getIcon("fileSaveCopy"),
949 self.tr('Save Copy...'), self.__contextSaveCopy) 961 self.tr("Save Copy..."),
950 962 self.__contextSaveCopy,
963 )
964
951 self.menu.aboutToShow.connect(self.__showContextMenu) 965 self.menu.aboutToShow.connect(self.__showContextMenu)
952 966
953 self.spellingMenu = QMenu() 967 self.spellingMenu = QMenu()
954 self.__menus["Spelling"] = self.spellingMenu 968 self.__menus["Spelling"] = self.spellingMenu
955 969
956 self.spellingMenu.aboutToShow.connect(self.__showContextMenuSpelling) 970 self.spellingMenu.aboutToShow.connect(self.__showContextMenuSpelling)
957 self.spellingMenu.triggered.connect( 971 self.spellingMenu.triggered.connect(self.__contextMenuSpellingTriggered)
958 self.__contextMenuSpellingTriggered)
959 972
960 def __initContextMenuAutocompletion(self): 973 def __initContextMenuAutocompletion(self):
961 """ 974 """
962 Private method used to setup the Checks context sub menu. 975 Private method used to setup the Checks context sub menu.
963 976
964 @return reference to the generated menu 977 @return reference to the generated menu
965 @rtype QMenu 978 @rtype QMenu
966 """ 979 """
967 menu = QMenu(self.tr('Complete')) 980 menu = QMenu(self.tr("Complete"))
968 981
969 self.menuActs["acDynamic"] = menu.addAction( 982 self.menuActs["acDynamic"] = menu.addAction(
970 self.tr('Complete'), self.autoComplete) 983 self.tr("Complete"), self.autoComplete
984 )
971 menu.addSeparator() 985 menu.addSeparator()
972 self.menuActs["acClearCache"] = menu.addAction( 986 self.menuActs["acClearCache"] = menu.addAction(
973 self.tr("Clear Completions Cache"), self.__clearCompletionsCache) 987 self.tr("Clear Completions Cache"), self.__clearCompletionsCache
988 )
974 menu.addSeparator() 989 menu.addSeparator()
975 menu.addAction( 990 menu.addAction(self.tr("Complete from Document"), self.autoCompleteFromDocument)
976 self.tr('Complete from Document'), self.autoCompleteFromDocument)
977 self.menuActs["acAPI"] = menu.addAction( 991 self.menuActs["acAPI"] = menu.addAction(
978 self.tr('Complete from APIs'), self.autoCompleteFromAPIs) 992 self.tr("Complete from APIs"), self.autoCompleteFromAPIs
993 )
979 self.menuActs["acAPIDocument"] = menu.addAction( 994 self.menuActs["acAPIDocument"] = menu.addAction(
980 self.tr('Complete from Document and APIs'), 995 self.tr("Complete from Document and APIs"), self.autoCompleteFromAll
981 self.autoCompleteFromAll) 996 )
982 997
983 menu.aboutToShow.connect(self.__showContextMenuAutocompletion) 998 menu.aboutToShow.connect(self.__showContextMenuAutocompletion)
984 999
985 return menu 1000 return menu
986 1001
987 def __initContextMenuChecks(self): 1002 def __initContextMenuChecks(self):
988 """ 1003 """
989 Private method used to setup the Checks context sub menu. 1004 Private method used to setup the Checks context sub menu.
990 1005
991 @return reference to the generated menu 1006 @return reference to the generated menu
992 @rtype QMenu 1007 @rtype QMenu
993 """ 1008 """
994 menu = QMenu(self.tr('Check')) 1009 menu = QMenu(self.tr("Check"))
995 menu.aboutToShow.connect(self.__showContextMenuChecks) 1010 menu.aboutToShow.connect(self.__showContextMenuChecks)
996 return menu 1011 return menu
997 1012
998 def __initContextMenuFormatting(self): 1013 def __initContextMenuFormatting(self):
999 """ 1014 """
1000 Private method used to setup the Code Formatting context sub menu. 1015 Private method used to setup the Code Formatting context sub menu.
1001 1016
1002 @return reference to the generated menu 1017 @return reference to the generated menu
1003 @rtype QMenu 1018 @rtype QMenu
1004 """ 1019 """
1005 menu = QMenu(self.tr("Code Formatting")) 1020 menu = QMenu(self.tr("Code Formatting"))
1006 1021
1007 menu.addAction( 1022 menu.addAction(
1008 self.tr("Format Code"), 1023 self.tr("Format Code"),
1009 lambda: self.__performFormatWithBlack(BlackFormattingAction.Format) 1024 lambda: self.__performFormatWithBlack(BlackFormattingAction.Format),
1010 ) 1025 )
1011 menu.addAction( 1026 menu.addAction(
1012 self.tr("Check Formatting"), 1027 self.tr("Check Formatting"),
1013 lambda: self.__performFormatWithBlack(BlackFormattingAction.Check) 1028 lambda: self.__performFormatWithBlack(BlackFormattingAction.Check),
1014 ) 1029 )
1015 menu.addAction( 1030 menu.addAction(
1016 self.tr("Formatting Diff"), 1031 self.tr("Formatting Diff"),
1017 lambda: self.__performFormatWithBlack(BlackFormattingAction.Diff) 1032 lambda: self.__performFormatWithBlack(BlackFormattingAction.Diff),
1018 ) 1033 )
1019 1034
1020 menu.aboutToShow.connect(self.__showContextMenuFormatting) 1035 menu.aboutToShow.connect(self.__showContextMenuFormatting)
1021 1036
1022 return menu 1037 return menu
1023 1038
1024 def __initContextMenuTools(self): 1039 def __initContextMenuTools(self):
1025 """ 1040 """
1026 Private method used to setup the Tools context sub menu. 1041 Private method used to setup the Tools context sub menu.
1027 1042
1028 @return reference to the generated menu 1043 @return reference to the generated menu
1029 @rtype QMenu 1044 @rtype QMenu
1030 """ 1045 """
1031 menu = QMenu(self.tr('Tools')) 1046 menu = QMenu(self.tr("Tools"))
1032 menu.aboutToShow.connect(self.__showContextMenuTools) 1047 menu.aboutToShow.connect(self.__showContextMenuTools)
1033 return menu 1048 return menu
1034 1049
1035 def __initContextMenuShow(self): 1050 def __initContextMenuShow(self):
1036 """ 1051 """
1037 Private method used to setup the Show context sub menu. 1052 Private method used to setup the Show context sub menu.
1038 1053
1039 @return reference to the generated menu 1054 @return reference to the generated menu
1040 @rtype QMenu 1055 @rtype QMenu
1041 """ 1056 """
1042 menu = QMenu(self.tr('Show')) 1057 menu = QMenu(self.tr("Show"))
1043 1058
1044 menu.addAction(self.tr('Code metrics...'), self.__showCodeMetrics) 1059 menu.addAction(self.tr("Code metrics..."), self.__showCodeMetrics)
1045 self.coverageMenuAct = menu.addAction( 1060 self.coverageMenuAct = menu.addAction(
1046 self.tr('Code coverage...'), self.__showCodeCoverage) 1061 self.tr("Code coverage..."), self.__showCodeCoverage
1062 )
1047 self.coverageShowAnnotationMenuAct = menu.addAction( 1063 self.coverageShowAnnotationMenuAct = menu.addAction(
1048 self.tr('Show code coverage annotations'), 1064 self.tr("Show code coverage annotations"), self.codeCoverageShowAnnotations
1049 self.codeCoverageShowAnnotations) 1065 )
1050 self.coverageHideAnnotationMenuAct = menu.addAction( 1066 self.coverageHideAnnotationMenuAct = menu.addAction(
1051 self.tr('Hide code coverage annotations'), 1067 self.tr("Hide code coverage annotations"),
1052 self.__codeCoverageHideAnnotations) 1068 self.__codeCoverageHideAnnotations,
1069 )
1053 self.profileMenuAct = menu.addAction( 1070 self.profileMenuAct = menu.addAction(
1054 self.tr('Profile data...'), self.__showProfileData) 1071 self.tr("Profile data..."), self.__showProfileData
1055 1072 )
1073
1056 menu.aboutToShow.connect(self.__showContextMenuShow) 1074 menu.aboutToShow.connect(self.__showContextMenuShow)
1057 1075
1058 return menu 1076 return menu
1059 1077
1060 def __initContextMenuGraphics(self): 1078 def __initContextMenuGraphics(self):
1061 """ 1079 """
1062 Private method used to setup the diagrams context sub menu. 1080 Private method used to setup the diagrams context sub menu.
1063 1081
1064 @return reference to the generated menu 1082 @return reference to the generated menu
1065 @rtype QMenu 1083 @rtype QMenu
1066 """ 1084 """
1067 menu = QMenu(self.tr('Diagrams')) 1085 menu = QMenu(self.tr("Diagrams"))
1068 1086
1069 menu.addAction( 1087 menu.addAction(self.tr("Class Diagram..."), self.__showClassDiagram)
1070 self.tr('Class Diagram...'), self.__showClassDiagram) 1088 menu.addAction(self.tr("Package Diagram..."), self.__showPackageDiagram)
1071 menu.addAction( 1089 menu.addAction(self.tr("Imports Diagram..."), self.__showImportsDiagram)
1072 self.tr('Package Diagram...'), self.__showPackageDiagram)
1073 menu.addAction(
1074 self.tr('Imports Diagram...'), self.__showImportsDiagram)
1075 self.applicationDiagramMenuAct = menu.addAction( 1090 self.applicationDiagramMenuAct = menu.addAction(
1076 self.tr('Application Diagram...'), 1091 self.tr("Application Diagram..."), self.__showApplicationDiagram
1077 self.__showApplicationDiagram) 1092 )
1078 menu.addSeparator() 1093 menu.addSeparator()
1079 menu.addAction( 1094 menu.addAction(
1080 UI.PixmapCache.getIcon("open"), 1095 UI.PixmapCache.getIcon("open"),
1081 self.tr("Load Diagram..."), self.__loadDiagram) 1096 self.tr("Load Diagram..."),
1082 1097 self.__loadDiagram,
1098 )
1099
1083 menu.aboutToShow.connect(self.__showContextMenuGraphics) 1100 menu.aboutToShow.connect(self.__showContextMenuGraphics)
1084 1101
1085 return menu 1102 return menu
1086 1103
1087 def __initContextMenuLanguages(self): 1104 def __initContextMenuLanguages(self):
1088 """ 1105 """
1089 Private method used to setup the Languages context sub menu. 1106 Private method used to setup the Languages context sub menu.
1090 1107
1091 @return reference to the generated menu 1108 @return reference to the generated menu
1092 @rtype QMenu 1109 @rtype QMenu
1093 """ 1110 """
1094 menu = QMenu(self.tr("Languages")) 1111 menu = QMenu(self.tr("Languages"))
1095 1112
1096 self.languagesActGrp = QActionGroup(self) 1113 self.languagesActGrp = QActionGroup(self)
1097 self.noLanguageAct = menu.addAction( 1114 self.noLanguageAct = menu.addAction(
1098 UI.PixmapCache.getIcon("fileText"), 1115 UI.PixmapCache.getIcon("fileText"), self.tr("Text")
1099 self.tr("Text")) 1116 )
1100 self.noLanguageAct.setCheckable(True) 1117 self.noLanguageAct.setCheckable(True)
1101 self.noLanguageAct.setData("None") 1118 self.noLanguageAct.setData("None")
1102 self.languagesActGrp.addAction(self.noLanguageAct) 1119 self.languagesActGrp.addAction(self.noLanguageAct)
1103 menu.addSeparator() 1120 menu.addSeparator()
1104 1121
1105 from . import Lexers 1122 from . import Lexers
1123
1106 self.supportedLanguages = {} 1124 self.supportedLanguages = {}
1107 supportedLanguages = Lexers.getSupportedLanguages() 1125 supportedLanguages = Lexers.getSupportedLanguages()
1108 languages = sorted(supportedLanguages.keys()) 1126 languages = sorted(supportedLanguages.keys())
1109 for language in languages: 1127 for language in languages:
1110 if language != "Guessed": 1128 if language != "Guessed":
1111 self.supportedLanguages[language] = ( 1129 self.supportedLanguages[language] = supportedLanguages[language][:2]
1112 supportedLanguages[language][:2]
1113 )
1114 act = menu.addAction( 1130 act = menu.addAction(
1115 UI.PixmapCache.getIcon(supportedLanguages[language][2]), 1131 UI.PixmapCache.getIcon(supportedLanguages[language][2]),
1116 self.supportedLanguages[language][0]) 1132 self.supportedLanguages[language][0],
1133 )
1117 act.setCheckable(True) 1134 act.setCheckable(True)
1118 act.setData(language) 1135 act.setData(language)
1119 self.supportedLanguages[language].append(act) 1136 self.supportedLanguages[language].append(act)
1120 self.languagesActGrp.addAction(act) 1137 self.languagesActGrp.addAction(act)
1121 1138
1122 menu.addSeparator() 1139 menu.addSeparator()
1123 self.pygmentsAct = menu.addAction(self.tr("Guessed")) 1140 self.pygmentsAct = menu.addAction(self.tr("Guessed"))
1124 self.pygmentsAct.setCheckable(True) 1141 self.pygmentsAct.setCheckable(True)
1125 self.pygmentsAct.setData("Guessed") 1142 self.pygmentsAct.setData("Guessed")
1126 self.languagesActGrp.addAction(self.pygmentsAct) 1143 self.languagesActGrp.addAction(self.pygmentsAct)
1127 self.pygmentsSelAct = menu.addAction(self.tr("Alternatives")) 1144 self.pygmentsSelAct = menu.addAction(self.tr("Alternatives"))
1128 self.pygmentsSelAct.setData("Alternatives") 1145 self.pygmentsSelAct.setData("Alternatives")
1129 1146
1130 menu.triggered.connect(self.__languageMenuTriggered) 1147 menu.triggered.connect(self.__languageMenuTriggered)
1131 menu.aboutToShow.connect(self.__showContextMenuLanguages) 1148 menu.aboutToShow.connect(self.__showContextMenuLanguages)
1132 1149
1133 return menu 1150 return menu
1134 1151
1135 def __initContextMenuEncodings(self): 1152 def __initContextMenuEncodings(self):
1136 """ 1153 """
1137 Private method used to setup the Encodings context sub menu. 1154 Private method used to setup the Encodings context sub menu.
1138 1155
1139 @return reference to the generated menu 1156 @return reference to the generated menu
1140 @rtype QMenu 1157 @rtype QMenu
1141 """ 1158 """
1142 self.supportedEncodings = {} 1159 self.supportedEncodings = {}
1143 1160
1144 menu = QMenu(self.tr("Encodings")) 1161 menu = QMenu(self.tr("Encodings"))
1145 1162
1146 self.encodingsActGrp = QActionGroup(self) 1163 self.encodingsActGrp = QActionGroup(self)
1147 1164
1148 for encoding in sorted(Utilities.supportedCodecs): 1165 for encoding in sorted(Utilities.supportedCodecs):
1149 act = menu.addAction(encoding) 1166 act = menu.addAction(encoding)
1150 act.setCheckable(True) 1167 act.setCheckable(True)
1151 act.setData(encoding) 1168 act.setData(encoding)
1152 self.supportedEncodings[encoding] = act 1169 self.supportedEncodings[encoding] = act
1153 self.encodingsActGrp.addAction(act) 1170 self.encodingsActGrp.addAction(act)
1154 1171
1155 menu.triggered.connect(self.__encodingsMenuTriggered) 1172 menu.triggered.connect(self.__encodingsMenuTriggered)
1156 menu.aboutToShow.connect(self.__showContextMenuEncodings) 1173 menu.aboutToShow.connect(self.__showContextMenuEncodings)
1157 1174
1158 return menu 1175 return menu
1159 1176
1160 def __initContextMenuReopenWithEncoding(self): 1177 def __initContextMenuReopenWithEncoding(self):
1161 """ 1178 """
1162 Private method used to setup the Reopen With Encoding context sub menu. 1179 Private method used to setup the Reopen With Encoding context sub menu.
1163 1180
1164 @return reference to the generated menu 1181 @return reference to the generated menu
1165 @rtype QMenu 1182 @rtype QMenu
1166 """ 1183 """
1167 menu = QMenu(self.tr("Re-Open With Encoding")) 1184 menu = QMenu(self.tr("Re-Open With Encoding"))
1168 menu.setIcon(UI.PixmapCache.getIcon("open")) 1185 menu.setIcon(UI.PixmapCache.getIcon("open"))
1169 1186
1170 for encoding in sorted(Utilities.supportedCodecs): 1187 for encoding in sorted(Utilities.supportedCodecs):
1171 act = menu.addAction(encoding) 1188 act = menu.addAction(encoding)
1172 act.setData(encoding) 1189 act.setData(encoding)
1173 1190
1174 menu.triggered.connect(self.__reopenWithEncodingMenuTriggered) 1191 menu.triggered.connect(self.__reopenWithEncodingMenuTriggered)
1175 1192
1176 return menu 1193 return menu
1177 1194
1178 def __initContextMenuEol(self): 1195 def __initContextMenuEol(self):
1179 """ 1196 """
1180 Private method to setup the eol context sub menu. 1197 Private method to setup the eol context sub menu.
1181 1198
1182 @return reference to the generated menu 1199 @return reference to the generated menu
1183 @rtype QMenu 1200 @rtype QMenu
1184 """ 1201 """
1185 self.supportedEols = {} 1202 self.supportedEols = {}
1186 1203
1187 menu = QMenu(self.tr("End-of-Line Type")) 1204 menu = QMenu(self.tr("End-of-Line Type"))
1188 1205
1189 self.eolActGrp = QActionGroup(self) 1206 self.eolActGrp = QActionGroup(self)
1190 1207
1191 act = menu.addAction(UI.PixmapCache.getIcon("eolLinux"), 1208 act = menu.addAction(UI.PixmapCache.getIcon("eolLinux"), self.tr("Unix"))
1192 self.tr("Unix"))
1193 act.setCheckable(True) 1209 act.setCheckable(True)
1194 act.setData('\n') 1210 act.setData("\n")
1195 self.supportedEols['\n'] = act 1211 self.supportedEols["\n"] = act
1196 self.eolActGrp.addAction(act) 1212 self.eolActGrp.addAction(act)
1197 1213
1198 act = menu.addAction(UI.PixmapCache.getIcon("eolWindows"), 1214 act = menu.addAction(UI.PixmapCache.getIcon("eolWindows"), self.tr("Windows"))
1199 self.tr("Windows"))
1200 act.setCheckable(True) 1215 act.setCheckable(True)
1201 act.setData('\r\n') 1216 act.setData("\r\n")
1202 self.supportedEols['\r\n'] = act 1217 self.supportedEols["\r\n"] = act
1203 self.eolActGrp.addAction(act) 1218 self.eolActGrp.addAction(act)
1204 1219
1205 act = menu.addAction(UI.PixmapCache.getIcon("eolMac"), 1220 act = menu.addAction(UI.PixmapCache.getIcon("eolMac"), self.tr("Macintosh"))
1206 self.tr("Macintosh"))
1207 act.setCheckable(True) 1221 act.setCheckable(True)
1208 act.setData('\r') 1222 act.setData("\r")
1209 self.supportedEols['\r'] = act 1223 self.supportedEols["\r"] = act
1210 self.eolActGrp.addAction(act) 1224 self.eolActGrp.addAction(act)
1211 1225
1212 menu.triggered.connect(self.__eolMenuTriggered) 1226 menu.triggered.connect(self.__eolMenuTriggered)
1213 menu.aboutToShow.connect(self.__showContextMenuEol) 1227 menu.aboutToShow.connect(self.__showContextMenuEol)
1214 1228
1215 return menu 1229 return menu
1216 1230
1217 def __initContextMenuSpellCheck(self): 1231 def __initContextMenuSpellCheck(self):
1218 """ 1232 """
1219 Private method used to setup the spell checking context sub menu. 1233 Private method used to setup the spell checking context sub menu.
1220 1234
1221 @return reference to the generated menu 1235 @return reference to the generated menu
1222 @rtype QMenu 1236 @rtype QMenu
1223 """ 1237 """
1224 menu = QMenu(self.tr("Spelling")) 1238 menu = QMenu(self.tr("Spelling"))
1225 menu.setIcon(UI.PixmapCache.getIcon("spellchecking")) 1239 menu.setIcon(UI.PixmapCache.getIcon("spellchecking"))
1226 1240
1227 self.spellLanguagesMenu = self.__initContextMenuSpellLanguages() 1241 self.spellLanguagesMenu = self.__initContextMenuSpellLanguages()
1228 self.__menus["SpellLanguages"] = self.spellLanguagesMenu 1242 self.__menus["SpellLanguages"] = self.spellLanguagesMenu
1229 1243
1230 self.menuActs["SpellCheck"] = menu.addAction( 1244 self.menuActs["SpellCheck"] = menu.addAction(
1231 UI.PixmapCache.getIcon("spellchecking"), 1245 UI.PixmapCache.getIcon("spellchecking"),
1232 self.tr('Check spelling...'), self.checkSpelling) 1246 self.tr("Check spelling..."),
1247 self.checkSpelling,
1248 )
1233 self.menuActs["SpellCheckSelection"] = menu.addAction( 1249 self.menuActs["SpellCheckSelection"] = menu.addAction(
1234 UI.PixmapCache.getIcon("spellchecking"), 1250 UI.PixmapCache.getIcon("spellchecking"),
1235 self.tr('Check spelling of selection...'), 1251 self.tr("Check spelling of selection..."),
1236 self.__checkSpellingSelection) 1252 self.__checkSpellingSelection,
1253 )
1237 self.menuActs["SpellCheckRemove"] = menu.addAction( 1254 self.menuActs["SpellCheckRemove"] = menu.addAction(
1238 self.tr("Remove from dictionary"), 1255 self.tr("Remove from dictionary"), self.__removeFromSpellingDictionary
1239 self.__removeFromSpellingDictionary) 1256 )
1240 self.menuActs["SpellCheckLanguages"] = menu.addMenu( 1257 self.menuActs["SpellCheckLanguages"] = menu.addMenu(self.spellLanguagesMenu)
1241 self.spellLanguagesMenu) 1258
1242
1243 menu.aboutToShow.connect(self.__showContextMenuSpellCheck) 1259 menu.aboutToShow.connect(self.__showContextMenuSpellCheck)
1244 1260
1245 return menu 1261 return menu
1246 1262
1247 def __initContextMenuSpellLanguages(self): 1263 def __initContextMenuSpellLanguages(self):
1248 """ 1264 """
1249 Private method to setup the spell checking languages context sub menu. 1265 Private method to setup the spell checking languages context sub menu.
1250 1266
1251 @return reference to the generated menu 1267 @return reference to the generated menu
1252 @rtype QMenu 1268 @rtype QMenu
1253 """ 1269 """
1254 self.supportedSpellLanguages = {} 1270 self.supportedSpellLanguages = {}
1255 1271
1256 menu = QMenu(self.tr("Spell Check Languages")) 1272 menu = QMenu(self.tr("Spell Check Languages"))
1257 1273
1258 self.spellLanguagesActGrp = QActionGroup(self) 1274 self.spellLanguagesActGrp = QActionGroup(self)
1259 1275
1260 self.noSpellLanguageAct = menu.addAction( 1276 self.noSpellLanguageAct = menu.addAction(self.tr("No Language"))
1261 self.tr("No Language"))
1262 self.noSpellLanguageAct.setCheckable(True) 1277 self.noSpellLanguageAct.setCheckable(True)
1263 self.noSpellLanguageAct.setData("") 1278 self.noSpellLanguageAct.setData("")
1264 self.spellLanguagesActGrp.addAction(self.noSpellLanguageAct) 1279 self.spellLanguagesActGrp.addAction(self.noSpellLanguageAct)
1265 menu.addSeparator() 1280 menu.addSeparator()
1266 1281
1267 for language in sorted(SpellChecker.getAvailableLanguages()): 1282 for language in sorted(SpellChecker.getAvailableLanguages()):
1268 act = menu.addAction(language) 1283 act = menu.addAction(language)
1269 act.setCheckable(True) 1284 act.setCheckable(True)
1270 act.setData(language) 1285 act.setData(language)
1271 self.supportedSpellLanguages[language] = act 1286 self.supportedSpellLanguages[language] = act
1272 self.spellLanguagesActGrp.addAction(act) 1287 self.spellLanguagesActGrp.addAction(act)
1273 1288
1274 menu.triggered.connect(self.__spellLanguagesMenuTriggered) 1289 menu.triggered.connect(self.__spellLanguagesMenuTriggered)
1275 menu.aboutToShow.connect(self.__showContextMenuSpellLanguages) 1290 menu.aboutToShow.connect(self.__showContextMenuSpellLanguages)
1276 1291
1277 return menu 1292 return menu
1278 1293
1279 def __initContextMenuMargins(self): 1294 def __initContextMenuMargins(self):
1280 """ 1295 """
1281 Private method used to setup the context menu for the margins. 1296 Private method used to setup the context menu for the margins.
1282 """ 1297 """
1283 self.marginMenuActs = {} 1298 self.marginMenuActs = {}
1284 1299
1285 # bookmark margin 1300 # bookmark margin
1286 self.bmMarginMenu = QMenu() 1301 self.bmMarginMenu = QMenu()
1287 1302
1288 self.bmMarginMenu.addAction( 1303 self.bmMarginMenu.addAction(self.tr("Toggle bookmark"), self.menuToggleBookmark)
1289 self.tr('Toggle bookmark'), self.menuToggleBookmark)
1290 self.marginMenuActs["NextBookmark"] = self.bmMarginMenu.addAction( 1304 self.marginMenuActs["NextBookmark"] = self.bmMarginMenu.addAction(
1291 self.tr('Next bookmark'), self.nextBookmark) 1305 self.tr("Next bookmark"), self.nextBookmark
1306 )
1292 self.marginMenuActs["PreviousBookmark"] = self.bmMarginMenu.addAction( 1307 self.marginMenuActs["PreviousBookmark"] = self.bmMarginMenu.addAction(
1293 self.tr('Previous bookmark'), self.previousBookmark) 1308 self.tr("Previous bookmark"), self.previousBookmark
1309 )
1294 self.marginMenuActs["ClearBookmark"] = self.bmMarginMenu.addAction( 1310 self.marginMenuActs["ClearBookmark"] = self.bmMarginMenu.addAction(
1295 self.tr('Clear all bookmarks'), self.clearBookmarks) 1311 self.tr("Clear all bookmarks"), self.clearBookmarks
1296 1312 )
1313
1297 self.bmMarginMenu.aboutToShow.connect( 1314 self.bmMarginMenu.aboutToShow.connect(
1298 lambda: self.__showContextMenuMargin(self.bmMarginMenu)) 1315 lambda: self.__showContextMenuMargin(self.bmMarginMenu)
1299 1316 )
1317
1300 # breakpoint margin 1318 # breakpoint margin
1301 self.bpMarginMenu = QMenu() 1319 self.bpMarginMenu = QMenu()
1302 1320
1303 self.marginMenuActs["Breakpoint"] = self.bpMarginMenu.addAction( 1321 self.marginMenuActs["Breakpoint"] = self.bpMarginMenu.addAction(
1304 self.tr('Toggle breakpoint'), self.menuToggleBreakpoint) 1322 self.tr("Toggle breakpoint"), self.menuToggleBreakpoint
1323 )
1305 self.marginMenuActs["TempBreakpoint"] = self.bpMarginMenu.addAction( 1324 self.marginMenuActs["TempBreakpoint"] = self.bpMarginMenu.addAction(
1306 self.tr('Toggle temporary breakpoint'), 1325 self.tr("Toggle temporary breakpoint"), self.__menuToggleTemporaryBreakpoint
1307 self.__menuToggleTemporaryBreakpoint) 1326 )
1308 self.marginMenuActs["EditBreakpoint"] = self.bpMarginMenu.addAction( 1327 self.marginMenuActs["EditBreakpoint"] = self.bpMarginMenu.addAction(
1309 self.tr('Edit breakpoint...'), self.menuEditBreakpoint) 1328 self.tr("Edit breakpoint..."), self.menuEditBreakpoint
1329 )
1310 self.marginMenuActs["EnableBreakpoint"] = self.bpMarginMenu.addAction( 1330 self.marginMenuActs["EnableBreakpoint"] = self.bpMarginMenu.addAction(
1311 self.tr('Enable breakpoint'), 1331 self.tr("Enable breakpoint"), self.__menuToggleBreakpointEnabled
1312 self.__menuToggleBreakpointEnabled) 1332 )
1313 self.marginMenuActs["NextBreakpoint"] = self.bpMarginMenu.addAction( 1333 self.marginMenuActs["NextBreakpoint"] = self.bpMarginMenu.addAction(
1314 self.tr('Next breakpoint'), self.menuNextBreakpoint) 1334 self.tr("Next breakpoint"), self.menuNextBreakpoint
1315 self.marginMenuActs["PreviousBreakpoint"] = ( 1335 )
1316 self.bpMarginMenu.addAction( 1336 self.marginMenuActs["PreviousBreakpoint"] = self.bpMarginMenu.addAction(
1317 self.tr('Previous breakpoint'), 1337 self.tr("Previous breakpoint"), self.menuPreviousBreakpoint
1318 self.menuPreviousBreakpoint)
1319 ) 1338 )
1320 self.marginMenuActs["ClearBreakpoint"] = self.bpMarginMenu.addAction( 1339 self.marginMenuActs["ClearBreakpoint"] = self.bpMarginMenu.addAction(
1321 self.tr('Clear all breakpoints'), self.__menuClearBreakpoints) 1340 self.tr("Clear all breakpoints"), self.__menuClearBreakpoints
1322 1341 )
1342
1323 self.bpMarginMenu.aboutToShow.connect( 1343 self.bpMarginMenu.aboutToShow.connect(
1324 lambda: self.__showContextMenuMargin(self.bpMarginMenu)) 1344 lambda: self.__showContextMenuMargin(self.bpMarginMenu)
1325 1345 )
1346
1326 # fold margin 1347 # fold margin
1327 self.foldMarginMenu = QMenu() 1348 self.foldMarginMenu = QMenu()
1328 1349
1329 self.marginMenuActs["ToggleAllFolds"] = ( 1350 self.marginMenuActs["ToggleAllFolds"] = self.foldMarginMenu.addAction(
1330 self.foldMarginMenu.addAction( 1351 self.tr("Toggle all folds"), self.foldAll
1331 self.tr("Toggle all folds"), 1352 )
1332 self.foldAll) 1353 self.marginMenuActs[
1333 ) 1354 "ToggleAllFoldsAndChildren"
1334 self.marginMenuActs["ToggleAllFoldsAndChildren"] = ( 1355 ] = self.foldMarginMenu.addAction(
1335 self.foldMarginMenu.addAction( 1356 self.tr("Toggle all folds (including children)"), lambda: self.foldAll(True)
1336 self.tr("Toggle all folds (including children)"), 1357 )
1337 lambda: self.foldAll(True)) 1358 self.marginMenuActs["ToggleCurrentFold"] = self.foldMarginMenu.addAction(
1338 ) 1359 self.tr("Toggle current fold"), self.toggleCurrentFold
1339 self.marginMenuActs["ToggleCurrentFold"] = (
1340 self.foldMarginMenu.addAction(
1341 self.tr("Toggle current fold"),
1342 self.toggleCurrentFold)
1343 ) 1360 )
1344 self.foldMarginMenu.addSeparator() 1361 self.foldMarginMenu.addSeparator()
1345 self.marginMenuActs["ExpandChildren"] = ( 1362 self.marginMenuActs["ExpandChildren"] = self.foldMarginMenu.addAction(
1346 self.foldMarginMenu.addAction( 1363 self.tr("Expand (including children)"),
1347 self.tr("Expand (including children)"), 1364 self.__contextMenuExpandFoldWithChildren,
1348 self.__contextMenuExpandFoldWithChildren) 1365 )
1349 ) 1366 self.marginMenuActs["CollapseChildren"] = self.foldMarginMenu.addAction(
1350 self.marginMenuActs["CollapseChildren"] = ( 1367 self.tr("Collapse (including children)"),
1351 self.foldMarginMenu.addAction( 1368 self.__contextMenuCollapseFoldWithChildren,
1352 self.tr("Collapse (including children)"),
1353 self.__contextMenuCollapseFoldWithChildren)
1354 ) 1369 )
1355 self.foldMarginMenu.addSeparator() 1370 self.foldMarginMenu.addSeparator()
1356 self.marginMenuActs["ClearAllFolds"] = ( 1371 self.marginMenuActs["ClearAllFolds"] = self.foldMarginMenu.addAction(
1357 self.foldMarginMenu.addAction( 1372 self.tr("Clear all folds"), self.clearFolds
1358 self.tr("Clear all folds"), 1373 )
1359 self.clearFolds) 1374
1360 )
1361
1362 self.foldMarginMenu.aboutToShow.connect( 1375 self.foldMarginMenu.aboutToShow.connect(
1363 lambda: self.__showContextMenuMargin(self.foldMarginMenu)) 1376 lambda: self.__showContextMenuMargin(self.foldMarginMenu)
1364 1377 )
1378
1365 # indicator margin 1379 # indicator margin
1366 self.indicMarginMenu = QMenu() 1380 self.indicMarginMenu = QMenu()
1367 1381
1368 self.marginMenuActs["GotoSyntaxError"] = ( 1382 self.marginMenuActs["GotoSyntaxError"] = self.indicMarginMenu.addAction(
1369 self.indicMarginMenu.addAction( 1383 self.tr("Goto syntax error"), self.gotoSyntaxError
1370 self.tr('Goto syntax error'), self.gotoSyntaxError) 1384 )
1371 ) 1385 self.marginMenuActs["ShowSyntaxError"] = self.indicMarginMenu.addAction(
1372 self.marginMenuActs["ShowSyntaxError"] = ( 1386 self.tr("Show syntax error message"), self.__showSyntaxError
1373 self.indicMarginMenu.addAction( 1387 )
1374 self.tr('Show syntax error message'), 1388 self.marginMenuActs["ClearSyntaxError"] = self.indicMarginMenu.addAction(
1375 self.__showSyntaxError) 1389 self.tr("Clear syntax error"), self.clearSyntaxError
1376 )
1377 self.marginMenuActs["ClearSyntaxError"] = (
1378 self.indicMarginMenu.addAction(
1379 self.tr('Clear syntax error'), self.clearSyntaxError)
1380 ) 1390 )
1381 self.indicMarginMenu.addSeparator() 1391 self.indicMarginMenu.addSeparator()
1382 self.marginMenuActs["NextWarningMarker"] = ( 1392 self.marginMenuActs["NextWarningMarker"] = self.indicMarginMenu.addAction(
1383 self.indicMarginMenu.addAction( 1393 self.tr("Next warning"), self.nextWarning
1384 self.tr("Next warning"), self.nextWarning) 1394 )
1385 ) 1395 self.marginMenuActs["PreviousWarningMarker"] = self.indicMarginMenu.addAction(
1386 self.marginMenuActs["PreviousWarningMarker"] = ( 1396 self.tr("Previous warning"), self.previousWarning
1387 self.indicMarginMenu.addAction( 1397 )
1388 self.tr("Previous warning"), self.previousWarning) 1398 self.marginMenuActs["ShowWarning"] = self.indicMarginMenu.addAction(
1389 ) 1399 self.tr("Show warning message"), self.__showWarning
1390 self.marginMenuActs["ShowWarning"] = ( 1400 )
1391 self.indicMarginMenu.addAction( 1401 self.marginMenuActs["ClearWarnings"] = self.indicMarginMenu.addAction(
1392 self.tr('Show warning message'), self.__showWarning) 1402 self.tr("Clear warnings"), self.clearWarnings
1393 )
1394 self.marginMenuActs["ClearWarnings"] = (
1395 self.indicMarginMenu.addAction(
1396 self.tr('Clear warnings'), self.clearWarnings)
1397 ) 1403 )
1398 self.indicMarginMenu.addSeparator() 1404 self.indicMarginMenu.addSeparator()
1399 self.marginMenuActs["NextCoverageMarker"] = ( 1405 self.marginMenuActs["NextCoverageMarker"] = self.indicMarginMenu.addAction(
1400 self.indicMarginMenu.addAction( 1406 self.tr("Next uncovered line"), self.nextUncovered
1401 self.tr('Next uncovered line'), self.nextUncovered) 1407 )
1402 ) 1408 self.marginMenuActs["PreviousCoverageMarker"] = self.indicMarginMenu.addAction(
1403 self.marginMenuActs["PreviousCoverageMarker"] = ( 1409 self.tr("Previous uncovered line"), self.previousUncovered
1404 self.indicMarginMenu.addAction(
1405 self.tr('Previous uncovered line'), self.previousUncovered)
1406 ) 1410 )
1407 self.indicMarginMenu.addSeparator() 1411 self.indicMarginMenu.addSeparator()
1408 self.marginMenuActs["NextTaskMarker"] = ( 1412 self.marginMenuActs["NextTaskMarker"] = self.indicMarginMenu.addAction(
1409 self.indicMarginMenu.addAction( 1413 self.tr("Next task"), self.nextTask
1410 self.tr('Next task'), self.nextTask) 1414 )
1411 ) 1415 self.marginMenuActs["PreviousTaskMarker"] = self.indicMarginMenu.addAction(
1412 self.marginMenuActs["PreviousTaskMarker"] = ( 1416 self.tr("Previous task"), self.previousTask
1413 self.indicMarginMenu.addAction(
1414 self.tr('Previous task'), self.previousTask)
1415 ) 1417 )
1416 self.indicMarginMenu.addSeparator() 1418 self.indicMarginMenu.addSeparator()
1417 self.marginMenuActs["NextChangeMarker"] = ( 1419 self.marginMenuActs["NextChangeMarker"] = self.indicMarginMenu.addAction(
1418 self.indicMarginMenu.addAction( 1420 self.tr("Next change"), self.nextChange
1419 self.tr('Next change'), self.nextChange) 1421 )
1420 ) 1422 self.marginMenuActs["PreviousChangeMarker"] = self.indicMarginMenu.addAction(
1421 self.marginMenuActs["PreviousChangeMarker"] = ( 1423 self.tr("Previous change"), self.previousChange
1422 self.indicMarginMenu.addAction( 1424 )
1423 self.tr('Previous change'), self.previousChange) 1425 self.marginMenuActs["ClearChangeMarkers"] = self.indicMarginMenu.addAction(
1424 ) 1426 self.tr("Clear changes"), self.__reinitOnlineChangeTrace
1425 self.marginMenuActs["ClearChangeMarkers"] = ( 1427 )
1426 self.indicMarginMenu.addAction( 1428
1427 self.tr('Clear changes'), self.__reinitOnlineChangeTrace)
1428 )
1429
1430 self.indicMarginMenu.aboutToShow.connect( 1429 self.indicMarginMenu.aboutToShow.connect(
1431 lambda: self.__showContextMenuMargin(self.indicMarginMenu)) 1430 lambda: self.__showContextMenuMargin(self.indicMarginMenu)
1432 1431 )
1432
1433 def exportFile(self, exporterFormat): 1433 def exportFile(self, exporterFormat):
1434 """ 1434 """
1435 Public method to export the file. 1435 Public method to export the file.
1436 1436
1437 @param exporterFormat format the file should be exported into (string) 1437 @param exporterFormat format the file should be exported into (string)
1438 """ 1438 """
1439 if exporterFormat: 1439 if exporterFormat:
1440 from . import Exporters 1440 from . import Exporters
1441
1441 exporter = Exporters.getExporter(exporterFormat, self) 1442 exporter = Exporters.getExporter(exporterFormat, self)
1442 if exporter: 1443 if exporter:
1443 exporter.exportSource() 1444 exporter.exportSource()
1444 else: 1445 else:
1445 EricMessageBox.critical( 1446 EricMessageBox.critical(
1446 self, 1447 self,
1447 self.tr("Export source"), 1448 self.tr("Export source"),
1448 self.tr( 1449 self.tr(
1449 """<p>No exporter available for the """ 1450 """<p>No exporter available for the """
1450 """export format <b>{0}</b>. Aborting...</p>""") 1451 """export format <b>{0}</b>. Aborting...</p>"""
1451 .format(exporterFormat)) 1452 ).format(exporterFormat),
1453 )
1452 else: 1454 else:
1453 EricMessageBox.critical( 1455 EricMessageBox.critical(
1454 self, 1456 self,
1455 self.tr("Export source"), 1457 self.tr("Export source"),
1456 self.tr("""No export format given. Aborting...""")) 1458 self.tr("""No export format given. Aborting..."""),
1457 1459 )
1460
1458 def __showContextMenuLanguages(self): 1461 def __showContextMenuLanguages(self):
1459 """ 1462 """
1460 Private slot handling the aboutToShow signal of the languages context 1463 Private slot handling the aboutToShow signal of the languages context
1461 menu. 1464 menu.
1462 """ 1465 """
1463 if self.apiLanguage.startswith("Pygments|"): 1466 if self.apiLanguage.startswith("Pygments|"):
1464 self.pygmentsSelAct.setText( 1467 self.pygmentsSelAct.setText(
1465 self.tr("Alternatives ({0})").format( 1468 self.tr("Alternatives ({0})").format(self.getLanguage(normalized=False))
1466 self.getLanguage(normalized=False))) 1469 )
1467 else: 1470 else:
1468 self.pygmentsSelAct.setText(self.tr("Alternatives")) 1471 self.pygmentsSelAct.setText(self.tr("Alternatives"))
1469 self.showMenu.emit("Languages", self.languagesMenu, self) 1472 self.showMenu.emit("Languages", self.languagesMenu, self)
1470 1473
1471 def __selectPygmentsLexer(self): 1474 def __selectPygmentsLexer(self):
1472 """ 1475 """
1473 Private method to select a specific pygments lexer. 1476 Private method to select a specific pygments lexer.
1474 1477
1475 @return name of the selected pygments lexer (string) 1478 @return name of the selected pygments lexer (string)
1476 """ 1479 """
1477 from pygments.lexers import get_all_lexers 1480 from pygments.lexers import get_all_lexers
1481
1478 lexerList = sorted(lex[0] for lex in get_all_lexers()) 1482 lexerList = sorted(lex[0] for lex in get_all_lexers())
1479 try: 1483 try:
1480 lexerSel = lexerList.index( 1484 lexerSel = lexerList.index(
1481 self.getLanguage(normalized=False, forPygments=True)) 1485 self.getLanguage(normalized=False, forPygments=True)
1486 )
1482 except ValueError: 1487 except ValueError:
1483 lexerSel = 0 1488 lexerSel = 0
1484 lexerName, ok = QInputDialog.getItem( 1489 lexerName, ok = QInputDialog.getItem(
1485 self, 1490 self,
1486 self.tr("Pygments Lexer"), 1491 self.tr("Pygments Lexer"),
1487 self.tr("Select the Pygments lexer to apply."), 1492 self.tr("Select the Pygments lexer to apply."),
1488 lexerList, 1493 lexerList,
1489 lexerSel, 1494 lexerSel,
1490 False) 1495 False,
1496 )
1491 if ok and lexerName: 1497 if ok and lexerName:
1492 return lexerName 1498 return lexerName
1493 else: 1499 else:
1494 return "" 1500 return ""
1495 1501
1496 def __languageMenuTriggered(self, act): 1502 def __languageMenuTriggered(self, act):
1497 """ 1503 """
1498 Private method to handle the selection of a lexer language. 1504 Private method to handle the selection of a lexer language.
1499 1505
1500 @param act reference to the action that was triggered (QAction) 1506 @param act reference to the action that was triggered (QAction)
1501 """ 1507 """
1502 if act == self.noLanguageAct: 1508 if act == self.noLanguageAct:
1503 self.__resetLanguage() 1509 self.__resetLanguage()
1504 elif act == self.pygmentsAct: 1510 elif act == self.pygmentsAct:
1511 language = act.data() 1517 language = act.data()
1512 if language: 1518 if language:
1513 self.filetype = language 1519 self.filetype = language
1514 self.setLanguage(self.supportedLanguages[language][1]) 1520 self.setLanguage(self.supportedLanguages[language][1])
1515 self.checkSyntax() 1521 self.checkSyntax()
1516 1522
1517 self.__docstringGenerator = None 1523 self.__docstringGenerator = None
1518 1524
1519 def __languageChanged(self, language, propagate=True): 1525 def __languageChanged(self, language, propagate=True):
1520 """ 1526 """
1521 Private slot handling a change of a connected editor's language. 1527 Private slot handling a change of a connected editor's language.
1522 1528
1523 @param language language to be set (string) 1529 @param language language to be set (string)
1524 @param propagate flag indicating to propagate the change (boolean) 1530 @param propagate flag indicating to propagate the change (boolean)
1525 """ 1531 """
1526 if language == '': 1532 if language == "":
1527 self.__resetLanguage(propagate=propagate) 1533 self.__resetLanguage(propagate=propagate)
1528 elif language == "Guessed": 1534 elif language == "Guessed":
1529 self.setLanguage("dummy.pygments", 1535 self.setLanguage("dummy.pygments", propagate=propagate)
1530 propagate=propagate)
1531 elif language.startswith("Pygments|"): 1536 elif language.startswith("Pygments|"):
1532 pyname = language.split("|", 1)[1] 1537 pyname = language.split("|", 1)[1]
1533 self.setLanguage("dummy.pygments", pyname=pyname, 1538 self.setLanguage("dummy.pygments", pyname=pyname, propagate=propagate)
1534 propagate=propagate)
1535 else: 1539 else:
1536 self.filetype = language 1540 self.filetype = language
1537 self.setLanguage(self.supportedLanguages[language][1], 1541 self.setLanguage(self.supportedLanguages[language][1], propagate=propagate)
1538 propagate=propagate)
1539 self.checkSyntax() 1542 self.checkSyntax()
1540 1543
1541 self.__docstringGenerator = None 1544 self.__docstringGenerator = None
1542 1545
1543 def __resetLanguage(self, propagate=True): 1546 def __resetLanguage(self, propagate=True):
1544 """ 1547 """
1545 Private method used to reset the language selection. 1548 Private method used to reset the language selection.
1546 1549
1547 @param propagate flag indicating to propagate the change (boolean) 1550 @param propagate flag indicating to propagate the change (boolean)
1548 """ 1551 """
1549 if ( 1552 if self.lexer_ is not None and (
1550 self.lexer_ is not None and 1553 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None
1551 (self.lexer_.lexer() == "container" or
1552 self.lexer_.lexer() is None)
1553 ): 1554 ):
1554 with contextlib.suppress(TypeError): 1555 with contextlib.suppress(TypeError):
1555 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) 1556 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded)
1556 1557
1557 self.apiLanguage = "" 1558 self.apiLanguage = ""
1558 self.lexer_ = None 1559 self.lexer_ = None
1559 self.__lexerReset = True 1560 self.__lexerReset = True
1560 self.setLexer() 1561 self.setLexer()
1561 if self.completer is not None: 1562 if self.completer is not None:
1565 self.__setTextDisplay() 1566 self.__setTextDisplay()
1566 self.__setMarginsDisplay() 1567 self.__setMarginsDisplay()
1567 self.setMonospaced(useMonospaced) 1568 self.setMonospaced(useMonospaced)
1568 with contextlib.suppress(AttributeError): 1569 with contextlib.suppress(AttributeError):
1569 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) 1570 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced)
1570 1571
1571 self.__docstringGenerator = None 1572 self.__docstringGenerator = None
1572 1573
1573 if not self.inLanguageChanged and propagate: 1574 if not self.inLanguageChanged and propagate:
1574 self.inLanguageChanged = True 1575 self.inLanguageChanged = True
1575 self.languageChanged.emit(self.apiLanguage) 1576 self.languageChanged.emit(self.apiLanguage)
1576 self.inLanguageChanged = False 1577 self.inLanguageChanged = False
1577 1578
1578 def setLanguage(self, filename, initTextDisplay=True, propagate=True, 1579 def setLanguage(self, filename, initTextDisplay=True, propagate=True, pyname=""):
1579 pyname=""):
1580 """ 1580 """
1581 Public method to set a lexer language. 1581 Public method to set a lexer language.
1582 1582
1583 @param filename filename used to determine the associated lexer 1583 @param filename filename used to determine the associated lexer
1584 language (string) 1584 language (string)
1585 @param initTextDisplay flag indicating an initialization of the text 1585 @param initTextDisplay flag indicating an initialization of the text
1586 display is required as well (boolean) 1586 display is required as well (boolean)
1587 @param propagate flag indicating to propagate the change (boolean) 1587 @param propagate flag indicating to propagate the change (boolean)
1588 @param pyname name of the pygments lexer to use (string) 1588 @param pyname name of the pygments lexer to use (string)
1589 """ 1589 """
1590 # clear all warning and syntax error markers 1590 # clear all warning and syntax error markers
1591 self.clearSyntaxError() 1591 self.clearSyntaxError()
1592 self.clearWarnings() 1592 self.clearWarnings()
1593 1593
1594 self.menuActs["MonospacedFont"].setChecked(False) 1594 self.menuActs["MonospacedFont"].setChecked(False)
1595 1595
1596 self.__lexerReset = False 1596 self.__lexerReset = False
1597 self.__bindLexer(filename, pyname=pyname) 1597 self.__bindLexer(filename, pyname=pyname)
1598 self.__bindCompleter(filename) 1598 self.__bindCompleter(filename)
1599 self.recolor() 1599 self.recolor()
1600 self.__checkLanguage() 1600 self.__checkLanguage()
1601 1601
1602 self.__docstringGenerator = None 1602 self.__docstringGenerator = None
1603 1603
1604 # set the text display 1604 # set the text display
1605 if initTextDisplay: 1605 if initTextDisplay:
1606 self.__setTextDisplay() 1606 self.__setTextDisplay()
1607 1607
1608 # set the auto-completion and call-tips function 1608 # set the auto-completion and call-tips function
1609 self.__setAutoCompletion() 1609 self.__setAutoCompletion()
1610 self.__setCallTips() 1610 self.__setCallTips()
1611 1611
1612 if not self.inLanguageChanged and propagate: 1612 if not self.inLanguageChanged and propagate:
1613 self.inLanguageChanged = True 1613 self.inLanguageChanged = True
1614 self.languageChanged.emit(self.apiLanguage) 1614 self.languageChanged.emit(self.apiLanguage)
1615 self.inLanguageChanged = False 1615 self.inLanguageChanged = False
1616 1616
1617 def __checkLanguage(self): 1617 def __checkLanguage(self):
1618 """ 1618 """
1619 Private method to check the selected language of the language submenu. 1619 Private method to check the selected language of the language submenu.
1620 """ 1620 """
1621 if self.apiLanguage == "": 1621 if self.apiLanguage == "":
1626 act = self.languagesActGrp.checkedAction() 1626 act = self.languagesActGrp.checkedAction()
1627 if act: 1627 if act:
1628 act.setChecked(False) 1628 act.setChecked(False)
1629 else: 1629 else:
1630 self.supportedLanguages[self.apiLanguage][2].setChecked(True) 1630 self.supportedLanguages[self.apiLanguage][2].setChecked(True)
1631 1631
1632 def projectLexerAssociationsChanged(self): 1632 def projectLexerAssociationsChanged(self):
1633 """ 1633 """
1634 Public slot to handle changes of the project lexer associations. 1634 Public slot to handle changes of the project lexer associations.
1635 """ 1635 """
1636 self.setLanguage(self.fileName) 1636 self.setLanguage(self.fileName)
1637 1637
1638 def __showContextMenuEncodings(self): 1638 def __showContextMenuEncodings(self):
1639 """ 1639 """
1640 Private slot handling the aboutToShow signal of the encodings context 1640 Private slot handling the aboutToShow signal of the encodings context
1641 menu. 1641 menu.
1642 """ 1642 """
1643 self.showMenu.emit("Encodings", self.encodingsMenu, self) 1643 self.showMenu.emit("Encodings", self.encodingsMenu, self)
1644 1644
1645 def __encodingsMenuTriggered(self, act): 1645 def __encodingsMenuTriggered(self, act):
1646 """ 1646 """
1647 Private method to handle the selection of an encoding. 1647 Private method to handle the selection of an encoding.
1648 1648
1649 @param act reference to the action that was triggered (QAction) 1649 @param act reference to the action that was triggered (QAction)
1650 """ 1650 """
1651 encoding = act.data() 1651 encoding = act.data()
1652 self.setModified(True) 1652 self.setModified(True)
1653 self.__encodingChanged("{0}-selected".format(encoding)) 1653 self.__encodingChanged("{0}-selected".format(encoding))
1654 1654
1655 def __checkEncoding(self): 1655 def __checkEncoding(self):
1656 """ 1656 """
1657 Private method to check the selected encoding of the encodings submenu. 1657 Private method to check the selected encoding of the encodings submenu.
1658 """ 1658 """
1659 with contextlib.suppress(AttributeError, KeyError): 1659 with contextlib.suppress(AttributeError, KeyError):
1660 (self.supportedEncodings[self.__normalizedEncoding()] 1660 (self.supportedEncodings[self.__normalizedEncoding()].setChecked(True))
1661 .setChecked(True)) 1661
1662
1663 def __encodingChanged(self, encoding, propagate=True): 1662 def __encodingChanged(self, encoding, propagate=True):
1664 """ 1663 """
1665 Private slot to handle a change of the encoding. 1664 Private slot to handle a change of the encoding.
1666 1665
1667 @param encoding changed encoding (string) 1666 @param encoding changed encoding (string)
1668 @param propagate flag indicating to propagate the change (boolean) 1667 @param propagate flag indicating to propagate the change (boolean)
1669 """ 1668 """
1670 self.encoding = encoding 1669 self.encoding = encoding
1671 self.__checkEncoding() 1670 self.__checkEncoding()
1672 1671
1673 if not self.inEncodingChanged and propagate: 1672 if not self.inEncodingChanged and propagate:
1674 self.inEncodingChanged = True 1673 self.inEncodingChanged = True
1675 self.encodingChanged.emit(self.encoding) 1674 self.encodingChanged.emit(self.encoding)
1676 self.inEncodingChanged = False 1675 self.inEncodingChanged = False
1677 1676
1678 def __normalizedEncoding(self, encoding=""): 1677 def __normalizedEncoding(self, encoding=""):
1679 """ 1678 """
1680 Private method to calculate the normalized encoding string. 1679 Private method to calculate the normalized encoding string.
1681 1680
1682 @param encoding encoding to be normalized (string) 1681 @param encoding encoding to be normalized (string)
1683 @return normalized encoding (string) 1682 @return normalized encoding (string)
1684 """ 1683 """
1685 if not encoding: 1684 if not encoding:
1686 encoding = self.encoding 1685 encoding = self.encoding
1687 return ( 1686 return (
1688 encoding 1687 encoding.replace("-default", "")
1689 .replace("-default", "")
1690 .replace("-guessed", "") 1688 .replace("-guessed", "")
1691 .replace("-selected", "") 1689 .replace("-selected", "")
1692 ) 1690 )
1693 1691
1694 def __showContextMenuEol(self): 1692 def __showContextMenuEol(self):
1695 """ 1693 """
1696 Private slot handling the aboutToShow signal of the eol context menu. 1694 Private slot handling the aboutToShow signal of the eol context menu.
1697 """ 1695 """
1698 self.showMenu.emit("Eol", self.eolMenu, self) 1696 self.showMenu.emit("Eol", self.eolMenu, self)
1699 1697
1700 def __eolMenuTriggered(self, act): 1698 def __eolMenuTriggered(self, act):
1701 """ 1699 """
1702 Private method to handle the selection of an eol type. 1700 Private method to handle the selection of an eol type.
1703 1701
1704 @param act reference to the action that was triggered (QAction) 1702 @param act reference to the action that was triggered (QAction)
1705 """ 1703 """
1706 eol = act.data() 1704 eol = act.data()
1707 self.setEolModeByEolString(eol) 1705 self.setEolModeByEolString(eol)
1708 self.convertEols(self.eolMode()) 1706 self.convertEols(self.eolMode())
1709 1707
1710 def __checkEol(self): 1708 def __checkEol(self):
1711 """ 1709 """
1712 Private method to check the selected eol type of the eol submenu. 1710 Private method to check the selected eol type of the eol submenu.
1713 """ 1711 """
1714 with contextlib.suppress(AttributeError, TypeError): 1712 with contextlib.suppress(AttributeError, TypeError):
1715 self.supportedEols[self.getLineSeparator()].setChecked(True) 1713 self.supportedEols[self.getLineSeparator()].setChecked(True)
1716 1714
1717 def __eolChanged(self): 1715 def __eolChanged(self):
1718 """ 1716 """
1719 Private slot to handle a change of the eol mode. 1717 Private slot to handle a change of the eol mode.
1720 """ 1718 """
1721 self.__checkEol() 1719 self.__checkEol()
1722 1720
1723 if not self.inEolChanged: 1721 if not self.inEolChanged:
1724 self.inEolChanged = True 1722 self.inEolChanged = True
1725 eol = self.getLineSeparator() 1723 eol = self.getLineSeparator()
1726 self.eolChanged.emit(eol) 1724 self.eolChanged.emit(eol)
1727 self.inEolChanged = False 1725 self.inEolChanged = False
1728 1726
1729 def __showContextMenuSpellCheck(self): 1727 def __showContextMenuSpellCheck(self):
1730 """ 1728 """
1731 Private slot handling the aboutToShow signal of the spell check 1729 Private slot handling the aboutToShow signal of the spell check
1732 context menu. 1730 context menu.
1733 """ 1731 """
1734 spellingAvailable = SpellChecker.isAvailable() 1732 spellingAvailable = SpellChecker.isAvailable()
1735 self.menuActs["SpellCheck"].setEnabled(spellingAvailable) 1733 self.menuActs["SpellCheck"].setEnabled(spellingAvailable)
1736 self.menuActs["SpellCheckSelection"].setEnabled( 1734 self.menuActs["SpellCheckSelection"].setEnabled(
1737 spellingAvailable and self.hasSelectedText()) 1735 spellingAvailable and self.hasSelectedText()
1736 )
1738 self.menuActs["SpellCheckRemove"].setEnabled( 1737 self.menuActs["SpellCheckRemove"].setEnabled(
1739 spellingAvailable and self.spellingMenuPos >= 0) 1738 spellingAvailable and self.spellingMenuPos >= 0
1739 )
1740 self.menuActs["SpellCheckLanguages"].setEnabled(spellingAvailable) 1740 self.menuActs["SpellCheckLanguages"].setEnabled(spellingAvailable)
1741 1741
1742 self.showMenu.emit("SpellCheck", self.spellCheckMenu, self) 1742 self.showMenu.emit("SpellCheck", self.spellCheckMenu, self)
1743 1743
1744 def __showContextMenuSpellLanguages(self): 1744 def __showContextMenuSpellLanguages(self):
1745 """ 1745 """
1746 Private slot handling the aboutToShow signal of the spell check 1746 Private slot handling the aboutToShow signal of the spell check
1747 languages context menu. 1747 languages context menu.
1748 """ 1748 """
1749 self.showMenu.emit("SpellLanguage", self.spellLanguagesMenu, self) 1749 self.showMenu.emit("SpellLanguage", self.spellLanguagesMenu, self)
1750 1750
1751 def __spellLanguagesMenuTriggered(self, act): 1751 def __spellLanguagesMenuTriggered(self, act):
1752 """ 1752 """
1753 Private method to handle the selection of a spell check language. 1753 Private method to handle the selection of a spell check language.
1754 1754
1755 @param act reference to the action that was triggered 1755 @param act reference to the action that was triggered
1756 @type QAction 1756 @type QAction
1757 """ 1757 """
1758 language = act.data() 1758 language = act.data()
1759 self.__setSpellingLanguage(language) 1759 self.__setSpellingLanguage(language)
1760 self.spellLanguageChanged.emit(language) 1760 self.spellLanguageChanged.emit(language)
1761 1761
1762 def __checkSpellLanguage(self): 1762 def __checkSpellLanguage(self):
1763 """ 1763 """
1764 Private slot to check the selected spell check language action. 1764 Private slot to check the selected spell check language action.
1765 """ 1765 """
1766 language = self.getSpellingLanguage() 1766 language = self.getSpellingLanguage()
1767 with contextlib.suppress(AttributeError, KeyError): 1767 with contextlib.suppress(AttributeError, KeyError):
1768 self.supportedSpellLanguages[language].setChecked(True) 1768 self.supportedSpellLanguages[language].setChecked(True)
1769 1769
1770 def __spellLanguageChanged(self, language, propagate=True): 1770 def __spellLanguageChanged(self, language, propagate=True):
1771 """ 1771 """
1772 Private slot to handle a change of the spell check language. 1772 Private slot to handle a change of the spell check language.
1773 1773
1774 @param language new spell check language 1774 @param language new spell check language
1775 @type str 1775 @type str
1776 @param propagate flag indicating to propagate the change 1776 @param propagate flag indicating to propagate the change
1777 @type bool 1777 @type bool
1778 """ 1778 """
1779 self.__setSpellingLanguage(language) 1779 self.__setSpellingLanguage(language)
1780 self.__checkSpellLanguage() 1780 self.__checkSpellLanguage()
1781 1781
1782 if not self.__inSpellLanguageChanged and propagate: 1782 if not self.__inSpellLanguageChanged and propagate:
1783 self.__inSpellLanguageChanged = True 1783 self.__inSpellLanguageChanged = True
1784 self.spellLanguageChanged.emit(language) 1784 self.spellLanguageChanged.emit(language)
1785 self.__inSpellLanguageChanged = False 1785 self.__inSpellLanguageChanged = False
1786 1786
1787 def __bindLexer(self, filename, pyname=""): 1787 def __bindLexer(self, filename, pyname=""):
1788 """ 1788 """
1789 Private slot to set the correct lexer depending on language. 1789 Private slot to set the correct lexer depending on language.
1790 1790
1791 @param filename filename used to determine the associated lexer 1791 @param filename filename used to determine the associated lexer
1792 language (string) 1792 language (string)
1793 @param pyname name of the pygments lexer to use (string) 1793 @param pyname name of the pygments lexer to use (string)
1794 """ 1794 """
1795 if ( 1795 if self.lexer_ is not None and (
1796 self.lexer_ is not None and 1796 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None
1797 (self.lexer_.lexer() == "container" or
1798 self.lexer_.lexer() is None)
1799 ): 1797 ):
1800 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) 1798 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded)
1801 1799
1802 language = "" 1800 language = ""
1803 if not self.filetype: 1801 if not self.filetype:
1804 if filename: 1802 if filename:
1805 basename = os.path.basename(filename) 1803 basename = os.path.basename(filename)
1806 if ( 1804 if self.project.isOpen() and self.project.isProjectFile(filename):
1807 self.project.isOpen() and
1808 self.project.isProjectFile(filename)
1809 ):
1810 language = self.project.getEditorLexerAssoc(basename) 1805 language = self.project.getEditorLexerAssoc(basename)
1811 if not language: 1806 if not language:
1812 language = Preferences.getEditorLexerAssoc(basename) 1807 language = Preferences.getEditorLexerAssoc(basename)
1813 if language == "Text": 1808 if language == "Text":
1814 # no highlighting for plain text files 1809 # no highlighting for plain text files
1815 self.__resetLanguage() 1810 self.__resetLanguage()
1816 return 1811 return
1817 1812
1818 if not language: 1813 if not language:
1819 bindName = self.__bindName(self.text(0)) 1814 bindName = self.__bindName(self.text(0))
1820 if bindName: 1815 if bindName:
1821 language = Preferences.getEditorLexerAssoc(bindName) 1816 language = Preferences.getEditorLexerAssoc(bindName)
1822 if language == "Python": 1817 if language == "Python":
1823 # correction for Python 1818 # correction for Python
1824 pyVer = Utilities.determinePythonVersion( 1819 pyVer = Utilities.determinePythonVersion(filename, self.text(0), self)
1825 filename, self.text(0), self)
1826 language = "Python{0}".format(pyVer) 1820 language = "Python{0}".format(pyVer)
1827 if language in ['Python3', 'MicroPython', 'Cython', 'Ruby', 1821 if language in [
1828 'JavaScript', 'YAML', 'JSON']: 1822 "Python3",
1823 "MicroPython",
1824 "Cython",
1825 "Ruby",
1826 "JavaScript",
1827 "YAML",
1828 "JSON",
1829 ]:
1829 self.filetype = language 1830 self.filetype = language
1830 else: 1831 else:
1831 self.filetype = "" 1832 self.filetype = ""
1832 else: 1833 else:
1833 language = self.filetype 1834 language = self.filetype
1834 1835
1835 if language.startswith("Pygments|"): 1836 if language.startswith("Pygments|"):
1836 pyname = language 1837 pyname = language
1837 self.filetype = language.split("|")[-1] 1838 self.filetype = language.split("|")[-1]
1838 language = "" 1839 language = ""
1839 1840
1840 from . import Lexers 1841 from . import Lexers
1842
1841 self.lexer_ = Lexers.getLexer(language, self, pyname=pyname) 1843 self.lexer_ = Lexers.getLexer(language, self, pyname=pyname)
1842 if self.lexer_ is None: 1844 if self.lexer_ is None:
1843 self.setLexer() 1845 self.setLexer()
1844 self.apiLanguage = "" 1846 self.apiLanguage = ""
1845 return 1847 return
1846 1848
1847 if pyname: 1849 if pyname:
1848 if pyname.startswith("Pygments|"): 1850 if pyname.startswith("Pygments|"):
1849 self.apiLanguage = pyname 1851 self.apiLanguage = pyname
1850 else: 1852 else:
1851 self.apiLanguage = "Pygments|{0}".format(pyname) 1853 self.apiLanguage = "Pygments|{0}".format(pyname)
1862 self.apiLanguage = "Gettext" 1864 self.apiLanguage = "Gettext"
1863 self.setLexer(self.lexer_) 1865 self.setLexer(self.lexer_)
1864 self.__setMarginsDisplay() 1866 self.__setMarginsDisplay()
1865 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None: 1867 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None:
1866 self.SCN_STYLENEEDED.connect(self.__styleNeeded) 1868 self.SCN_STYLENEEDED.connect(self.__styleNeeded)
1867 1869
1868 # get the font for style 0 and set it as the default font 1870 # get the font for style 0 and set it as the default font
1869 key = ( 1871 key = (
1870 'Scintilla/Guessed/style0/font' 1872 "Scintilla/Guessed/style0/font"
1871 if pyname and pyname.startswith("Pygments|") else 1873 if pyname and pyname.startswith("Pygments|")
1872 'Scintilla/{0}/style0/font'.format(self.lexer_.language()) 1874 else "Scintilla/{0}/style0/font".format(self.lexer_.language())
1873 ) 1875 )
1874 fdesc = Preferences.getSettings().value(key) 1876 fdesc = Preferences.getSettings().value(key)
1875 if fdesc is not None: 1877 if fdesc is not None:
1876 font = QFont([fdesc[0]], int(fdesc[1])) 1878 font = QFont([fdesc[0]], int(fdesc[1]))
1877 self.lexer_.setDefaultFont(font) 1879 self.lexer_.setDefaultFont(font)
1878 self.lexer_.readSettings(Preferences.getSettings(), "Scintilla") 1880 self.lexer_.readSettings(Preferences.getSettings(), "Scintilla")
1879 if self.lexer_.hasSubstyles(): 1881 if self.lexer_.hasSubstyles():
1880 self.lexer_.readSubstyles(self) 1882 self.lexer_.readSubstyles(self)
1881 1883
1882 # now set the lexer properties 1884 # now set the lexer properties
1883 self.lexer_.initProperties() 1885 self.lexer_.initProperties()
1884 1886
1885 # initialize the lexer APIs settings 1887 # initialize the lexer APIs settings
1886 projectType = ( 1888 projectType = (
1887 self.project.getProjectType() 1889 self.project.getProjectType()
1888 if self.project.isOpen() and self.project.isProjectFile(filename) 1890 if self.project.isOpen() and self.project.isProjectFile(filename)
1889 else "" 1891 else ""
1890 ) 1892 )
1891 api = self.vm.getAPIsManager().getAPIs(self.apiLanguage, 1893 api = self.vm.getAPIsManager().getAPIs(
1892 projectType=projectType) 1894 self.apiLanguage, projectType=projectType
1895 )
1893 if api is not None and not api.isEmpty(): 1896 if api is not None and not api.isEmpty():
1894 self.lexer_.setAPIs(api.getQsciAPIs()) 1897 self.lexer_.setAPIs(api.getQsciAPIs())
1895 self.acAPI = True 1898 self.acAPI = True
1896 else: 1899 else:
1897 self.acAPI = False 1900 self.acAPI = False
1898 self.autoCompletionAPIsAvailable.emit(self.acAPI) 1901 self.autoCompletionAPIsAvailable.emit(self.acAPI)
1899 1902
1900 self.__setAnnotationStyles() 1903 self.__setAnnotationStyles()
1901 1904
1902 self.lexer_.setDefaultColor(self.lexer_.color(0)) 1905 self.lexer_.setDefaultColor(self.lexer_.color(0))
1903 self.lexer_.setDefaultPaper(self.lexer_.paper(0)) 1906 self.lexer_.setDefaultPaper(self.lexer_.paper(0))
1904 1907
1905 def __styleNeeded(self, position): 1908 def __styleNeeded(self, position):
1906 """ 1909 """
1907 Private slot to handle the need for more styling. 1910 Private slot to handle the need for more styling.
1908 1911
1909 @param position end position, that needs styling (integer) 1912 @param position end position, that needs styling (integer)
1910 """ 1913 """
1911 self.lexer_.styleText(self.getEndStyled(), position) 1914 self.lexer_.styleText(self.getEndStyled(), position)
1912 1915
1913 def getLexer(self): 1916 def getLexer(self):
1914 """ 1917 """
1915 Public method to retrieve a reference to the lexer object. 1918 Public method to retrieve a reference to the lexer object.
1916 1919
1917 @return the lexer object (Lexer) 1920 @return the lexer object (Lexer)
1918 """ 1921 """
1919 return self.lexer_ 1922 return self.lexer_
1920 1923
1921 def getLanguage(self, normalized=True, forPygments=False): 1924 def getLanguage(self, normalized=True, forPygments=False):
1922 """ 1925 """
1923 Public method to retrieve the language of the editor. 1926 Public method to retrieve the language of the editor.
1924 1927
1925 @param normalized flag indicating to normalize some Pygments 1928 @param normalized flag indicating to normalize some Pygments
1926 lexer names (boolean) 1929 lexer names (boolean)
1927 @param forPygments flag indicating to normalize some lexer 1930 @param forPygments flag indicating to normalize some lexer
1928 names for Pygments (boolean) 1931 names for Pygments (boolean)
1929 @return language of the editor (string) 1932 @return language of the editor (string)
1930 """ 1933 """
1931 if ( 1934 if self.apiLanguage == "Guessed" or self.apiLanguage.startswith("Pygments|"):
1932 self.apiLanguage == "Guessed" or
1933 self.apiLanguage.startswith("Pygments|")
1934 ):
1935 lang = self.lexer_.name() 1935 lang = self.lexer_.name()
1936 if normalized: 1936 if normalized:
1937 # adjust some Pygments lexer names 1937 # adjust some Pygments lexer names
1938 if lang in ("Python 2.x", "Python"): 1938 if lang in ("Python 2.x", "Python"):
1939 lang = "Python3" 1939 lang = "Python3"
1940 elif lang == "Protocol Buffer": 1940 elif lang == "Protocol Buffer":
1941 lang = "Protocol" 1941 lang = "Protocol"
1942 1942
1943 else: 1943 else:
1944 lang = self.apiLanguage 1944 lang = self.apiLanguage
1945 if forPygments: 1945 if forPygments:
1946 # adjust some names to Pygments lexer names 1946 # adjust some names to Pygments lexer names
1947 if lang == "Python3": 1947 if lang == "Python3":
1948 lang = "Python" 1948 lang = "Python"
1949 elif lang == "Protocol": 1949 elif lang == "Protocol":
1950 lang = "Protocol Buffer" 1950 lang = "Protocol Buffer"
1951 return lang 1951 return lang
1952 1952
1953 def getApiLanguage(self): 1953 def getApiLanguage(self):
1954 """ 1954 """
1955 Public method to get the API language of the editor. 1955 Public method to get the API language of the editor.
1956 1956
1957 @return API language 1957 @return API language
1958 @rtype str 1958 @rtype str
1959 """ 1959 """
1960 return self.apiLanguage 1960 return self.apiLanguage
1961 1961
1962 def __bindCompleter(self, filename): 1962 def __bindCompleter(self, filename):
1963 """ 1963 """
1964 Private slot to set the correct typing completer depending on language. 1964 Private slot to set the correct typing completer depending on language.
1965 1965
1966 @param filename filename used to determine the associated typing 1966 @param filename filename used to determine the associated typing
1967 completer language (string) 1967 completer language (string)
1968 """ 1968 """
1969 if self.completer is not None: 1969 if self.completer is not None:
1970 self.completer.setEnabled(False) 1970 self.completer.setEnabled(False)
1971 self.completer = None 1971 self.completer = None
1972 1972
1973 filename = os.path.basename(filename) 1973 filename = os.path.basename(filename)
1974 apiLanguage = Preferences.getEditorLexerAssoc(filename) 1974 apiLanguage = Preferences.getEditorLexerAssoc(filename)
1975 if apiLanguage == "": 1975 if apiLanguage == "":
1976 pyVer = self.__getPyVersion() 1976 pyVer = self.__getPyVersion()
1977 if pyVer: 1977 if pyVer:
1978 apiLanguage = "Python{0}".format(pyVer) 1978 apiLanguage = "Python{0}".format(pyVer)
1979 elif self.isRubyFile(): 1979 elif self.isRubyFile():
1980 apiLanguage = "Ruby" 1980 apiLanguage = "Ruby"
1981 1981
1982 from . import TypingCompleters 1982 from . import TypingCompleters
1983
1983 self.completer = TypingCompleters.getCompleter(apiLanguage, self) 1984 self.completer = TypingCompleters.getCompleter(apiLanguage, self)
1984 1985
1985 def getCompleter(self): 1986 def getCompleter(self):
1986 """ 1987 """
1987 Public method to retrieve a reference to the completer object. 1988 Public method to retrieve a reference to the completer object.
1988 1989
1989 @return the completer object (CompleterBase) 1990 @return the completer object (CompleterBase)
1990 """ 1991 """
1991 return self.completer 1992 return self.completer
1992 1993
1993 def __modificationChanged(self, m): 1994 def __modificationChanged(self, m):
1994 """ 1995 """
1995 Private slot to handle the modificationChanged signal. 1996 Private slot to handle the modificationChanged signal.
1996 1997
1997 It emits the signal modificationStatusChanged with parameters 1998 It emits the signal modificationStatusChanged with parameters
1998 m and self. 1999 m and self.
1999 2000
2000 @param m modification status 2001 @param m modification status
2001 """ 2002 """
2002 if not m and bool(self.fileName) and pathlib.Path(self.fileName).exists(): 2003 if not m and bool(self.fileName) and pathlib.Path(self.fileName).exists():
2003 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime 2004 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
2004 self.modificationStatusChanged.emit(m, self) 2005 self.modificationStatusChanged.emit(m, self)
2005 self.undoAvailable.emit(self.isUndoAvailable()) 2006 self.undoAvailable.emit(self.isUndoAvailable())
2006 self.redoAvailable.emit(self.isRedoAvailable()) 2007 self.redoAvailable.emit(self.isRedoAvailable())
2007 2008
2008 def __cursorPositionChanged(self, line, index): 2009 def __cursorPositionChanged(self, line, index):
2009 """ 2010 """
2010 Private slot to handle the cursorPositionChanged signal. 2011 Private slot to handle the cursorPositionChanged signal.
2011 2012
2012 It emits the signal cursorChanged with parameters fileName, 2013 It emits the signal cursorChanged with parameters fileName,
2013 line and pos. 2014 line and pos.
2014 2015
2015 @param line line number of the cursor 2016 @param line line number of the cursor
2016 @param index position in line of the cursor 2017 @param index position in line of the cursor
2017 """ 2018 """
2018 self.cursorChanged.emit(self.fileName, line + 1, index) 2019 self.cursorChanged.emit(self.fileName, line + 1, index)
2019 2020
2020 if Preferences.getEditor("MarkOccurrencesEnabled"): 2021 if Preferences.getEditor("MarkOccurrencesEnabled"):
2021 self.__markOccurrencesTimer.stop() 2022 self.__markOccurrencesTimer.stop()
2022 self.__markOccurrencesTimer.start() 2023 self.__markOccurrencesTimer.start()
2023 2024
2024 if self.lastLine != line: 2025 if self.lastLine != line:
2025 self.cursorLineChanged.emit(line) 2026 self.cursorLineChanged.emit(line)
2026 2027
2027 if self.spell is not None: 2028 if self.spell is not None:
2028 # do spell checking 2029 # do spell checking
2029 doSpelling = True 2030 doSpelling = True
2030 if self.lastLine == line: 2031 if self.lastLine == line:
2031 start, end = self.getWordBoundaries( 2032 start, end = self.getWordBoundaries(line, index, useWordChars=False)
2032 line, index, useWordChars=False)
2033 if start <= self.lastIndex and self.lastIndex <= end: 2033 if start <= self.lastIndex and self.lastIndex <= end:
2034 doSpelling = False 2034 doSpelling = False
2035 if doSpelling: 2035 if doSpelling:
2036 pos = self.positionFromLineIndex(self.lastLine, self.lastIndex) 2036 pos = self.positionFromLineIndex(self.lastLine, self.lastIndex)
2037 self.spell.checkWord(pos) 2037 self.spell.checkWord(pos)
2038 2038
2039 if self.lastLine != line: 2039 if self.lastLine != line:
2040 self.__markerMap.update() 2040 self.__markerMap.update()
2041 2041
2042 self.lastLine = line 2042 self.lastLine = line
2043 self.lastIndex = index 2043 self.lastIndex = index
2044 2044
2045 def __modificationReadOnly(self): 2045 def __modificationReadOnly(self):
2046 """ 2046 """
2047 Private slot to handle the modificationAttempted signal. 2047 Private slot to handle the modificationAttempted signal.
2048 """ 2048 """
2049 EricMessageBox.warning( 2049 EricMessageBox.warning(
2050 self, 2050 self,
2051 self.tr("Modification of Read Only file"), 2051 self.tr("Modification of Read Only file"),
2052 self.tr("""You are attempting to change a read only file. """ 2052 self.tr(
2053 """Please save to a different file first.""")) 2053 """You are attempting to change a read only file. """
2054 2054 """Please save to a different file first."""
2055 ),
2056 )
2057
2055 def setNoName(self, noName): 2058 def setNoName(self, noName):
2056 """ 2059 """
2057 Public method to set the display string for an unnamed editor. 2060 Public method to set the display string for an unnamed editor.
2058 2061
2059 @param noName display string for this unnamed editor (string) 2062 @param noName display string for this unnamed editor (string)
2060 """ 2063 """
2061 self.noName = noName 2064 self.noName = noName
2062 2065
2063 def getNoName(self): 2066 def getNoName(self):
2064 """ 2067 """
2065 Public method to get the display string for an unnamed editor. 2068 Public method to get the display string for an unnamed editor.
2066 2069
2067 @return display string for this unnamed editor (string) 2070 @return display string for this unnamed editor (string)
2068 """ 2071 """
2069 return self.noName 2072 return self.noName
2070 2073
2071 def getFileName(self): 2074 def getFileName(self):
2072 """ 2075 """
2073 Public method to return the name of the file being displayed. 2076 Public method to return the name of the file being displayed.
2074 2077
2075 @return filename of the displayed file (string) 2078 @return filename of the displayed file (string)
2076 """ 2079 """
2077 return self.fileName 2080 return self.fileName
2078 2081
2079 def getFileType(self): 2082 def getFileType(self):
2080 """ 2083 """
2081 Public method to return the type of the file being displayed. 2084 Public method to return the type of the file being displayed.
2082 2085
2083 @return type of the displayed file (string) 2086 @return type of the displayed file (string)
2084 """ 2087 """
2085 return self.filetype 2088 return self.filetype
2086 2089
2087 def getFileTypeByFlag(self): 2090 def getFileTypeByFlag(self):
2088 """ 2091 """
2089 Public method to return the type of the file, if it was set by an 2092 Public method to return the type of the file, if it was set by an
2090 eflag: marker. 2093 eflag: marker.
2091 2094
2092 @return type of the displayed file, if set by an eflag: marker or an 2095 @return type of the displayed file, if set by an eflag: marker or an
2093 empty string (string) 2096 empty string (string)
2094 """ 2097 """
2095 if self.filetypeByFlag: 2098 if self.filetypeByFlag:
2096 return self.filetype 2099 return self.filetype
2097 else: 2100 else:
2098 return "" 2101 return ""
2099 2102
2100 def determineFileType(self): 2103 def determineFileType(self):
2101 """ 2104 """
2102 Public method to determine the file type using various tests. 2105 Public method to determine the file type using various tests.
2103 2106
2104 @return type of the displayed file or an empty string (string) 2107 @return type of the displayed file or an empty string (string)
2105 """ 2108 """
2106 ftype = self.filetype 2109 ftype = self.filetype
2107 if not ftype: 2110 if not ftype:
2108 pyVer = self.__getPyVersion() 2111 pyVer = self.__getPyVersion()
2110 ftype = "Python{0}".format(pyVer) 2113 ftype = "Python{0}".format(pyVer)
2111 elif self.isRubyFile(): 2114 elif self.isRubyFile():
2112 ftype = "Ruby" 2115 ftype = "Ruby"
2113 else: 2116 else:
2114 ftype = "" 2117 ftype = ""
2115 2118
2116 return ftype 2119 return ftype
2117 2120
2118 def getEncoding(self): 2121 def getEncoding(self):
2119 """ 2122 """
2120 Public method to return the current encoding. 2123 Public method to return the current encoding.
2121 2124
2122 @return current encoding (string) 2125 @return current encoding (string)
2123 """ 2126 """
2124 return self.encoding 2127 return self.encoding
2125 2128
2126 def __getPyVersion(self): 2129 def __getPyVersion(self):
2127 """ 2130 """
2128 Private method to return the Python main version or 0 if it's 2131 Private method to return the Python main version or 0 if it's
2129 not a Python file at all. 2132 not a Python file at all.
2130 2133
2131 @return Python version or 0 if it's not a Python file (int) 2134 @return Python version or 0 if it's not a Python file (int)
2132 """ 2135 """
2133 return Utilities.determinePythonVersion( 2136 return Utilities.determinePythonVersion(self.fileName, self.text(0), self)
2134 self.fileName, self.text(0), self) 2137
2135
2136 def isPyFile(self): 2138 def isPyFile(self):
2137 """ 2139 """
2138 Public method to return a flag indicating a Python (2 or 3) file. 2140 Public method to return a flag indicating a Python (2 or 3) file.
2139 2141
2140 @return flag indicating a Python3 file (boolean) 2142 @return flag indicating a Python3 file (boolean)
2141 """ 2143 """
2142 return self.__getPyVersion() == 3 2144 return self.__getPyVersion() == 3
2143 2145
2144 def isPy3File(self): 2146 def isPy3File(self):
2145 """ 2147 """
2146 Public method to return a flag indicating a Python3 file. 2148 Public method to return a flag indicating a Python3 file.
2147 2149
2148 @return flag indicating a Python3 file (boolean) 2150 @return flag indicating a Python3 file (boolean)
2149 """ 2151 """
2150 return self.__getPyVersion() == 3 2152 return self.__getPyVersion() == 3
2151 2153
2152 def isMicroPythonFile(self): 2154 def isMicroPythonFile(self):
2153 """ 2155 """
2154 Public method to return a flag indicating a MicroPython file. 2156 Public method to return a flag indicating a MicroPython file.
2155 2157
2156 @return flag indicating a MicroPython file 2158 @return flag indicating a MicroPython file
2157 @rtype bool 2159 @rtype bool
2158 """ 2160 """
2159 if self.filetype == "MicroPython": 2161 if self.filetype == "MicroPython":
2160 return True 2162 return True
2161 2163
2162 return False 2164 return False
2163 2165
2164 def isCythonFile(self): 2166 def isCythonFile(self):
2165 """ 2167 """
2166 Public method to return a flag indicating a Cython file. 2168 Public method to return a flag indicating a Cython file.
2167 2169
2168 @return flag indicating a Cython file 2170 @return flag indicating a Cython file
2169 @rtype bool 2171 @rtype bool
2170 """ 2172 """
2171 if self.filetype == "Cython": 2173 if self.filetype == "Cython":
2172 return True 2174 return True
2173 2175
2174 return False 2176 return False
2175 2177
2176 def isRubyFile(self): 2178 def isRubyFile(self):
2177 """ 2179 """
2178 Public method to return a flag indicating a Ruby file. 2180 Public method to return a flag indicating a Ruby file.
2179 2181
2180 @return flag indicating a Ruby file (boolean) 2182 @return flag indicating a Ruby file (boolean)
2181 """ 2183 """
2182 if self.filetype == "Ruby": 2184 if self.filetype == "Ruby":
2183 return True 2185 return True
2184 2186
2185 if self.filetype == "": 2187 if self.filetype == "":
2186 line0 = self.text(0) 2188 line0 = self.text(0)
2187 if ( 2189 if line0.startswith("#!") and "ruby" in line0:
2188 line0.startswith("#!") and
2189 "ruby" in line0
2190 ):
2191 self.filetype = "Ruby" 2190 self.filetype = "Ruby"
2192 return True 2191 return True
2193 2192
2194 if ( 2193 if bool(self.fileName) and os.path.splitext(self.fileName)[
2195 bool(self.fileName) and 2194 1
2196 os.path.splitext(self.fileName)[1] in 2195 ] in self.dbs.getExtensions("Ruby"):
2197 self.dbs.getExtensions('Ruby')
2198 ):
2199 self.filetype = "Ruby" 2196 self.filetype = "Ruby"
2200 return True 2197 return True
2201 2198
2202 return False 2199 return False
2203 2200
2204 def isJavascriptFile(self): 2201 def isJavascriptFile(self):
2205 """ 2202 """
2206 Public method to return a flag indicating a Javascript file. 2203 Public method to return a flag indicating a Javascript file.
2207 2204
2208 @return flag indicating a Javascript file (boolean) 2205 @return flag indicating a Javascript file (boolean)
2209 """ 2206 """
2210 if self.filetype == "JavaScript": 2207 if self.filetype == "JavaScript":
2211 return True 2208 return True
2212 2209
2213 if ( 2210 if (
2214 self.filetype == "" and 2211 self.filetype == ""
2215 self.fileName and 2212 and self.fileName
2216 os.path.splitext(self.fileName)[1] == ".js" 2213 and os.path.splitext(self.fileName)[1] == ".js"
2217 ): 2214 ):
2218 self.filetype = "JavaScript" 2215 self.filetype = "JavaScript"
2219 return True 2216 return True
2220 2217
2221 return False 2218 return False
2222 2219
2223 def highlightVisible(self): 2220 def highlightVisible(self):
2224 """ 2221 """
2225 Public method to make sure that the highlight is visible. 2222 Public method to make sure that the highlight is visible.
2226 """ 2223 """
2227 if self.lastHighlight is not None: 2224 if self.lastHighlight is not None:
2228 lineno = self.markerLine(self.lastHighlight) 2225 lineno = self.markerLine(self.lastHighlight)
2229 self.ensureVisible(lineno + 1) 2226 self.ensureVisible(lineno + 1)
2230 2227
2231 def highlight(self, line=None, error=False, syntaxError=False): 2228 def highlight(self, line=None, error=False, syntaxError=False):
2232 """ 2229 """
2233 Public method to highlight [or de-highlight] a particular line. 2230 Public method to highlight [or de-highlight] a particular line.
2234 2231
2235 @param line line number to highlight (integer) 2232 @param line line number to highlight (integer)
2236 @param error flag indicating whether the error highlight should be 2233 @param error flag indicating whether the error highlight should be
2237 used (boolean) 2234 used (boolean)
2238 @param syntaxError flag indicating a syntax error (boolean) 2235 @param syntaxError flag indicating a syntax error (boolean)
2239 """ 2236 """
2252 self.lastErrorMarker = self.markerAdd(line - 1, self.errorline) 2249 self.lastErrorMarker = self.markerAdd(line - 1, self.errorline)
2253 self.lastHighlight = self.lastErrorMarker 2250 self.lastHighlight = self.lastErrorMarker
2254 else: 2251 else:
2255 if self.lastCurrMarker is not None: 2252 if self.lastCurrMarker is not None:
2256 self.markerDeleteHandle(self.lastCurrMarker) 2253 self.markerDeleteHandle(self.lastCurrMarker)
2257 self.lastCurrMarker = self.markerAdd(line - 1, 2254 self.lastCurrMarker = self.markerAdd(line - 1, self.currentline)
2258 self.currentline)
2259 self.lastHighlight = self.lastCurrMarker 2255 self.lastHighlight = self.lastCurrMarker
2260 self.setCursorPosition(line - 1, 0) 2256 self.setCursorPosition(line - 1, 0)
2261 2257
2262 def getHighlightPosition(self): 2258 def getHighlightPosition(self):
2263 """ 2259 """
2264 Public method to return the position of the highlight bar. 2260 Public method to return the position of the highlight bar.
2265 2261
2266 @return line number of the highlight bar (integer) 2262 @return line number of the highlight bar (integer)
2267 """ 2263 """
2268 if self.lastHighlight is not None: 2264 if self.lastHighlight is not None:
2269 return self.markerLine(self.lastHighlight) 2265 return self.markerLine(self.lastHighlight)
2270 else: 2266 else:
2271 return 1 2267 return 1
2272 2268
2273 ########################################################################### 2269 ###########################################################################
2274 ## Breakpoint handling methods below 2270 ## Breakpoint handling methods below
2275 ########################################################################### 2271 ###########################################################################
2276 2272
2277 def __modified(self, pos, mtype, text, length, linesAdded, line, foldNow, 2273 def __modified(
2278 foldPrev, token, annotationLinesAdded): 2274 self,
2275 pos,
2276 mtype,
2277 text,
2278 length,
2279 linesAdded,
2280 line,
2281 foldNow,
2282 foldPrev,
2283 token,
2284 annotationLinesAdded,
2285 ):
2279 """ 2286 """
2280 Private method to handle changes of the number of lines. 2287 Private method to handle changes of the number of lines.
2281 2288
2282 @param pos start position of change (integer) 2289 @param pos start position of change (integer)
2283 @param mtype flags identifying the change (integer) 2290 @param mtype flags identifying the change (integer)
2284 @param text text that is given to the Undo system (string) 2291 @param text text that is given to the Undo system (string)
2285 @param length length of the change (integer) 2292 @param length length of the change (integer)
2286 @param linesAdded number of added/deleted lines (integer) 2293 @param linesAdded number of added/deleted lines (integer)
2290 @param token ??? 2297 @param token ???
2291 @param annotationLinesAdded number of added/deleted annotation lines 2298 @param annotationLinesAdded number of added/deleted annotation lines
2292 (integer) 2299 (integer)
2293 """ 2300 """
2294 if ( 2301 if (
2295 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) and 2302 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT)
2296 linesAdded != 0 and 2303 and linesAdded != 0
2297 self.breaks 2304 and self.breaks
2298 ): 2305 ):
2299 bps = [] # list of breakpoints 2306 bps = [] # list of breakpoints
2300 for handle, (ln, cond, temp, enabled, ignorecount) in ( 2307 for handle, (ln, cond, temp, enabled, ignorecount) in self.breaks.items():
2301 self.breaks.items()
2302 ):
2303 line = self.markerLine(handle) + 1 2308 line = self.markerLine(handle) + 1
2304 if ln != line: 2309 if ln != line:
2305 bps.append((ln, line)) 2310 bps.append((ln, line))
2306 self.breaks[handle] = (line, cond, temp, enabled, 2311 self.breaks[handle] = (line, cond, temp, enabled, ignorecount)
2307 ignorecount)
2308 self.inLinesChanged = True 2312 self.inLinesChanged = True
2309 for ln, line in sorted(bps, reverse=linesAdded > 0): 2313 for ln, line in sorted(bps, reverse=linesAdded > 0):
2310 index1 = self.breakpointModel.getBreakPointIndex( 2314 index1 = self.breakpointModel.getBreakPointIndex(self.fileName, ln)
2311 self.fileName, ln)
2312 index2 = self.breakpointModel.index(index1.row(), 1) 2315 index2 = self.breakpointModel.index(index1.row(), 1)
2313 self.breakpointModel.setData(index2, line) 2316 self.breakpointModel.setData(index2, line)
2314 self.inLinesChanged = False 2317 self.inLinesChanged = False
2315 2318
2316 def __restoreBreakpoints(self): 2319 def __restoreBreakpoints(self):
2317 """ 2320 """
2318 Private method to restore the breakpoints. 2321 Private method to restore the breakpoints.
2319 """ 2322 """
2320 for handle in list(self.breaks.keys()): 2323 for handle in list(self.breaks.keys()):
2321 self.markerDeleteHandle(handle) 2324 self.markerDeleteHandle(handle)
2322 self.__addBreakPoints( 2325 self.__addBreakPoints(QModelIndex(), 0, self.breakpointModel.rowCount() - 1)
2323 QModelIndex(), 0, self.breakpointModel.rowCount() - 1)
2324 self.__markerMap.update() 2326 self.__markerMap.update()
2325 2327
2326 def __deleteBreakPoints(self, parentIndex, start, end): 2328 def __deleteBreakPoints(self, parentIndex, start, end):
2327 """ 2329 """
2328 Private slot to delete breakpoints. 2330 Private slot to delete breakpoints.
2329 2331
2330 @param parentIndex index of parent item (QModelIndex) 2332 @param parentIndex index of parent item (QModelIndex)
2331 @param start start row (integer) 2333 @param start start row (integer)
2332 @param end end row (integer) 2334 @param end end row (integer)
2333 """ 2335 """
2334 for row in range(start, end + 1): 2336 for row in range(start, end + 1):
2335 index = self.breakpointModel.index(row, 0, parentIndex) 2337 index = self.breakpointModel.index(row, 0, parentIndex)
2336 fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2] 2338 fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2]
2337 if fn == self.fileName: 2339 if fn == self.fileName:
2338 self.clearBreakpoint(lineno) 2340 self.clearBreakpoint(lineno)
2339 2341
2340 def __changeBreakPoints(self, startIndex, endIndex): 2342 def __changeBreakPoints(self, startIndex, endIndex):
2341 """ 2343 """
2342 Private slot to set changed breakpoints. 2344 Private slot to set changed breakpoints.
2343 2345
2344 @param startIndex start index of the breakpoints being changed 2346 @param startIndex start index of the breakpoints being changed
2345 (QModelIndex) 2347 (QModelIndex)
2346 @param endIndex end index of the breakpoints being changed 2348 @param endIndex end index of the breakpoints being changed
2347 (QModelIndex) 2349 (QModelIndex)
2348 """ 2350 """
2349 if not self.inLinesChanged: 2351 if not self.inLinesChanged:
2350 self.__addBreakPoints(QModelIndex(), startIndex.row(), 2352 self.__addBreakPoints(QModelIndex(), startIndex.row(), endIndex.row())
2351 endIndex.row()) 2353
2352
2353 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex): 2354 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex):
2354 """ 2355 """
2355 Private slot to handle the dataAboutToBeChanged signal of the 2356 Private slot to handle the dataAboutToBeChanged signal of the
2356 breakpoint model. 2357 breakpoint model.
2357 2358
2358 @param startIndex start index of the rows to be changed (QModelIndex) 2359 @param startIndex start index of the rows to be changed (QModelIndex)
2359 @param endIndex end index of the rows to be changed (QModelIndex) 2360 @param endIndex end index of the rows to be changed (QModelIndex)
2360 """ 2361 """
2361 self.__deleteBreakPoints(QModelIndex(), startIndex.row(), 2362 self.__deleteBreakPoints(QModelIndex(), startIndex.row(), endIndex.row())
2362 endIndex.row()) 2363
2363
2364 def __addBreakPoints(self, parentIndex, start, end): 2364 def __addBreakPoints(self, parentIndex, start, end):
2365 """ 2365 """
2366 Private slot to add breakpoints. 2366 Private slot to add breakpoints.
2367 2367
2368 @param parentIndex index of parent item (QModelIndex) 2368 @param parentIndex index of parent item (QModelIndex)
2369 @param start start row (integer) 2369 @param start start row (integer)
2370 @param end end row (integer) 2370 @param end end row (integer)
2371 """ 2371 """
2372 for row in range(start, end + 1): 2372 for row in range(start, end + 1):
2373 index = self.breakpointModel.index(row, 0, parentIndex) 2373 index = self.breakpointModel.index(row, 0, parentIndex)
2374 fn, line, cond, temp, enabled, ignorecount = ( 2374 (
2375 self.breakpointModel.getBreakPointByIndex(index)[:6] 2375 fn,
2376 ) 2376 line,
2377 cond,
2378 temp,
2379 enabled,
2380 ignorecount,
2381 ) = self.breakpointModel.getBreakPointByIndex(index)[:6]
2377 if fn == self.fileName: 2382 if fn == self.fileName:
2378 self.newBreakpointWithProperties( 2383 self.newBreakpointWithProperties(
2379 line, (cond, temp, enabled, ignorecount)) 2384 line, (cond, temp, enabled, ignorecount)
2380 2385 )
2386
2381 def clearBreakpoint(self, line): 2387 def clearBreakpoint(self, line):
2382 """ 2388 """
2383 Public method to clear a breakpoint. 2389 Public method to clear a breakpoint.
2384 2390
2385 Note: This doesn't clear the breakpoint in the debugger, 2391 Note: This doesn't clear the breakpoint in the debugger,
2386 it just deletes it from the editor internal list of breakpoints. 2392 it just deletes it from the editor internal list of breakpoints.
2387 2393
2388 @param line line number of the breakpoint (integer) 2394 @param line line number of the breakpoint (integer)
2389 """ 2395 """
2390 if self.inLinesChanged: 2396 if self.inLinesChanged:
2391 return 2397 return
2392 2398
2393 for handle in self.breaks: 2399 for handle in self.breaks:
2394 if self.markerLine(handle) == line - 1: 2400 if self.markerLine(handle) == line - 1:
2395 break 2401 break
2396 else: 2402 else:
2397 # not found, simply ignore it 2403 # not found, simply ignore it
2398 return 2404 return
2399 2405
2400 del self.breaks[handle] 2406 del self.breaks[handle]
2401 self.markerDeleteHandle(handle) 2407 self.markerDeleteHandle(handle)
2402 self.__markerMap.update() 2408 self.__markerMap.update()
2403 2409
2404 def newBreakpointWithProperties(self, line, properties): 2410 def newBreakpointWithProperties(self, line, properties):
2405 """ 2411 """
2406 Public method to set a new breakpoint and its properties. 2412 Public method to set a new breakpoint and its properties.
2407 2413
2408 @param line line number of the breakpoint (integer) 2414 @param line line number of the breakpoint (integer)
2409 @param properties properties for the breakpoint (tuple) 2415 @param properties properties for the breakpoint (tuple)
2410 (condition, temporary flag, enabled flag, ignore count) 2416 (condition, temporary flag, enabled flag, ignore count)
2411 """ 2417 """
2412 if not properties[2]: 2418 if not properties[2]:
2413 marker = self.dbreakpoint 2419 marker = self.dbreakpoint
2414 elif properties[0]: 2420 elif properties[0]:
2415 marker = properties[1] and self.tcbreakpoint or self.cbreakpoint 2421 marker = properties[1] and self.tcbreakpoint or self.cbreakpoint
2416 else: 2422 else:
2417 marker = properties[1] and self.tbreakpoint or self.breakpoint 2423 marker = properties[1] and self.tbreakpoint or self.breakpoint
2418 2424
2419 if self.markersAtLine(line - 1) & self.breakpointMask == 0: 2425 if self.markersAtLine(line - 1) & self.breakpointMask == 0:
2420 handle = self.markerAdd(line - 1, marker) 2426 handle = self.markerAdd(line - 1, marker)
2421 self.breaks[handle] = (line,) + properties 2427 self.breaks[handle] = (line,) + properties
2422 self.breakpointToggled.emit(self) 2428 self.breakpointToggled.emit(self)
2423 self.__markerMap.update() 2429 self.__markerMap.update()
2424 2430
2425 def __toggleBreakpoint(self, line, temporary=False): 2431 def __toggleBreakpoint(self, line, temporary=False):
2426 """ 2432 """
2427 Private method to toggle a breakpoint. 2433 Private method to toggle a breakpoint.
2428 2434
2429 @param line line number of the breakpoint (integer) 2435 @param line line number of the breakpoint (integer)
2430 @param temporary flag indicating a temporary breakpoint (boolean) 2436 @param temporary flag indicating a temporary breakpoint (boolean)
2431 """ 2437 """
2432 for handle in self.breaks: 2438 for handle in self.breaks:
2433 if self.markerLine(handle) == line - 1: 2439 if self.markerLine(handle) == line - 1:
2434 # delete breakpoint or toggle it to the next state 2440 # delete breakpoint or toggle it to the next state
2435 index = self.breakpointModel.getBreakPointIndex( 2441 index = self.breakpointModel.getBreakPointIndex(self.fileName, line)
2436 self.fileName, line) 2442 if Preferences.getDebugger(
2437 if ( 2443 "ThreeStateBreakPoints"
2438 Preferences.getDebugger("ThreeStateBreakPoints") and 2444 ) and not self.breakpointModel.isBreakPointTemporaryByIndex(index):
2439 not self.breakpointModel.isBreakPointTemporaryByIndex(
2440 index)
2441 ):
2442 self.breakpointModel.deleteBreakPointByIndex(index) 2445 self.breakpointModel.deleteBreakPointByIndex(index)
2443 self.__addBreakPoint(line, True) 2446 self.__addBreakPoint(line, True)
2444 else: 2447 else:
2445 self.breakpointModel.deleteBreakPointByIndex(index) 2448 self.breakpointModel.deleteBreakPointByIndex(index)
2446 self.breakpointToggled.emit(self) 2449 self.breakpointToggled.emit(self)
2449 self.__addBreakPoint(line, temporary) 2452 self.__addBreakPoint(line, temporary)
2450 2453
2451 def __addBreakPoint(self, line, temporary): 2454 def __addBreakPoint(self, line, temporary):
2452 """ 2455 """
2453 Private method to add a new breakpoint. 2456 Private method to add a new breakpoint.
2454 2457
2455 @param line line number of the breakpoint (integer) 2458 @param line line number of the breakpoint (integer)
2456 @param temporary flag indicating a temporary breakpoint (boolean) 2459 @param temporary flag indicating a temporary breakpoint (boolean)
2457 """ 2460 """
2458 if self.fileName and self.isPyFile(): 2461 if self.fileName and self.isPyFile():
2459 linestarts = PythonDisViewer.linestarts(self.text()) 2462 linestarts = PythonDisViewer.linestarts(self.text())
2466 self.__toggleBreakpoint(line, temporary=temporary) 2469 self.__toggleBreakpoint(line, temporary=temporary)
2467 else: 2470 else:
2468 EricMessageBox.warning( 2471 EricMessageBox.warning(
2469 self, 2472 self,
2470 self.tr("Add Breakpoint"), 2473 self.tr("Add Breakpoint"),
2471 self.tr("No Python byte code will be created for the" 2474 self.tr(
2472 " selected line. No break point will be set!") 2475 "No Python byte code will be created for the"
2476 " selected line. No break point will be set!"
2477 ),
2473 ) 2478 )
2474 return 2479 return
2475 2480
2476 self.breakpointModel.addBreakPoint( 2481 self.breakpointModel.addBreakPoint(
2477 self.fileName, line, ('', temporary, True, 0)) 2482 self.fileName, line, ("", temporary, True, 0)
2483 )
2478 self.breakpointToggled.emit(self) 2484 self.breakpointToggled.emit(self)
2479 2485
2480 def __toggleBreakpointEnabled(self, line): 2486 def __toggleBreakpointEnabled(self, line):
2481 """ 2487 """
2482 Private method to toggle a breakpoints enabled status. 2488 Private method to toggle a breakpoints enabled status.
2483 2489
2484 @param line line number of the breakpoint (integer) 2490 @param line line number of the breakpoint (integer)
2485 """ 2491 """
2486 for handle in self.breaks: 2492 for handle in self.breaks:
2487 if self.markerLine(handle) == line - 1: 2493 if self.markerLine(handle) == line - 1:
2488 index = self.breakpointModel.getBreakPointIndex( 2494 index = self.breakpointModel.getBreakPointIndex(self.fileName, line)
2489 self.fileName, line)
2490 self.breakpointModel.setBreakPointEnabledByIndex( 2495 self.breakpointModel.setBreakPointEnabledByIndex(
2491 index, not self.breaks[handle][3]) 2496 index, not self.breaks[handle][3]
2497 )
2492 break 2498 break
2493 2499
2494 def curLineHasBreakpoint(self): 2500 def curLineHasBreakpoint(self):
2495 """ 2501 """
2496 Public method to check for the presence of a breakpoint at the current 2502 Public method to check for the presence of a breakpoint at the current
2497 line. 2503 line.
2498 2504
2499 @return flag indicating the presence of a breakpoint (boolean) 2505 @return flag indicating the presence of a breakpoint (boolean)
2500 """ 2506 """
2501 line, _ = self.getCursorPosition() 2507 line, _ = self.getCursorPosition()
2502 return self.markersAtLine(line) & self.breakpointMask != 0 2508 return self.markersAtLine(line) & self.breakpointMask != 0
2503 2509
2504 def getBreakpointLines(self): 2510 def getBreakpointLines(self):
2505 """ 2511 """
2506 Public method to get the lines containing a breakpoint. 2512 Public method to get the lines containing a breakpoint.
2507 2513
2508 @return list of lines containing a breakpoint (list of integer) 2514 @return list of lines containing a breakpoint (list of integer)
2509 """ 2515 """
2510 lines = [] 2516 lines = []
2511 line = -1 2517 line = -1
2512 while True: 2518 while True:
2514 if line < 0: 2520 if line < 0:
2515 break 2521 break
2516 else: 2522 else:
2517 lines.append(line) 2523 lines.append(line)
2518 return lines 2524 return lines
2519 2525
2520 def hasBreakpoints(self): 2526 def hasBreakpoints(self):
2521 """ 2527 """
2522 Public method to check for the presence of breakpoints. 2528 Public method to check for the presence of breakpoints.
2523 2529
2524 @return flag indicating the presence of breakpoints (boolean) 2530 @return flag indicating the presence of breakpoints (boolean)
2525 """ 2531 """
2526 return len(self.breaks) > 0 2532 return len(self.breaks) > 0
2527 2533
2528 def __menuToggleTemporaryBreakpoint(self): 2534 def __menuToggleTemporaryBreakpoint(self):
2529 """ 2535 """
2530 Private slot to handle the 'Toggle temporary breakpoint' context menu 2536 Private slot to handle the 'Toggle temporary breakpoint' context menu
2531 action. 2537 action.
2532 """ 2538 """
2533 if self.line < 0: 2539 if self.line < 0:
2534 self.line, index = self.getCursorPosition() 2540 self.line, index = self.getCursorPosition()
2535 self.line += 1 2541 self.line += 1
2536 self.__toggleBreakpoint(self.line, 1) 2542 self.__toggleBreakpoint(self.line, 1)
2537 self.line = -1 2543 self.line = -1
2538 2544
2539 def menuToggleBreakpoint(self): 2545 def menuToggleBreakpoint(self):
2540 """ 2546 """
2541 Public slot to handle the 'Toggle breakpoint' context menu action. 2547 Public slot to handle the 'Toggle breakpoint' context menu action.
2542 """ 2548 """
2543 if self.line < 0: 2549 if self.line < 0:
2544 self.line, index = self.getCursorPosition() 2550 self.line, index = self.getCursorPosition()
2545 self.line += 1 2551 self.line += 1
2546 self.__toggleBreakpoint(self.line) 2552 self.__toggleBreakpoint(self.line)
2547 self.line = -1 2553 self.line = -1
2548 2554
2549 def __menuToggleBreakpointEnabled(self): 2555 def __menuToggleBreakpointEnabled(self):
2550 """ 2556 """
2551 Private slot to handle the 'Enable/Disable breakpoint' context menu 2557 Private slot to handle the 'Enable/Disable breakpoint' context menu
2552 action. 2558 action.
2553 """ 2559 """
2554 if self.line < 0: 2560 if self.line < 0:
2555 self.line, index = self.getCursorPosition() 2561 self.line, index = self.getCursorPosition()
2556 self.line += 1 2562 self.line += 1
2557 self.__toggleBreakpointEnabled(self.line) 2563 self.__toggleBreakpointEnabled(self.line)
2558 self.line = -1 2564 self.line = -1
2559 2565
2560 def menuEditBreakpoint(self, line=None): 2566 def menuEditBreakpoint(self, line=None):
2561 """ 2567 """
2562 Public slot to handle the 'Edit breakpoint' context menu action. 2568 Public slot to handle the 'Edit breakpoint' context menu action.
2563 2569
2564 @param line linenumber of the breakpoint to edit 2570 @param line linenumber of the breakpoint to edit
2565 """ 2571 """
2566 if line is not None: 2572 if line is not None:
2567 self.line = line - 1 2573 self.line = line - 1
2568 if self.line < 0: 2574 if self.line < 0:
2569 self.line, index = self.getCursorPosition() 2575 self.line, index = self.getCursorPosition()
2570 2576
2571 for handle in self.breaks: 2577 for handle in self.breaks:
2572 if self.markerLine(handle) == self.line: 2578 if self.markerLine(handle) == self.line:
2573 ln, cond, temp, enabled, ignorecount = self.breaks[handle] 2579 ln, cond, temp, enabled, ignorecount = self.breaks[handle]
2574 index = self.breakpointModel.getBreakPointIndex(self.fileName, 2580 index = self.breakpointModel.getBreakPointIndex(self.fileName, ln)
2575 ln)
2576 if not index.isValid(): 2581 if not index.isValid():
2577 return 2582 return
2578 2583
2579 # get recently used breakpoint conditions 2584 # get recently used breakpoint conditions
2580 rs = Preferences.Prefs.rsettings.value( 2585 rs = Preferences.Prefs.rsettings.value(recentNameBreakpointConditions)
2581 recentNameBreakpointConditions)
2582 condHistory = ( 2586 condHistory = (
2583 Preferences.toList(rs)[ 2587 Preferences.toList(rs)[: Preferences.getDebugger("RecentNumber")]
2584 :Preferences.getDebugger("RecentNumber")] 2588 if rs is not None
2585 if rs is not None else 2589 else []
2586 []
2587 ) 2590 )
2588 2591
2589 from Debugger.EditBreakpointDialog import EditBreakpointDialog 2592 from Debugger.EditBreakpointDialog import EditBreakpointDialog
2593
2590 dlg = EditBreakpointDialog( 2594 dlg = EditBreakpointDialog(
2591 (self.fileName, ln), 2595 (self.fileName, ln),
2592 (cond, temp, enabled, ignorecount), 2596 (cond, temp, enabled, ignorecount),
2593 condHistory, self, modal=True) 2597 condHistory,
2598 self,
2599 modal=True,
2600 )
2594 if dlg.exec() == QDialog.DialogCode.Accepted: 2601 if dlg.exec() == QDialog.DialogCode.Accepted:
2595 cond, temp, enabled, ignorecount = dlg.getData() 2602 cond, temp, enabled, ignorecount = dlg.getData()
2596 self.breakpointModel.setBreakPointByIndex( 2603 self.breakpointModel.setBreakPointByIndex(
2597 index, self.fileName, ln, 2604 index, self.fileName, ln, (cond, temp, enabled, ignorecount)
2598 (cond, temp, enabled, ignorecount)) 2605 )
2599 2606
2600 if cond: 2607 if cond:
2601 # save the recently used breakpoint condition 2608 # save the recently used breakpoint condition
2602 if cond in condHistory: 2609 if cond in condHistory:
2603 condHistory.remove(cond) 2610 condHistory.remove(cond)
2604 condHistory.insert(0, cond) 2611 condHistory.insert(0, cond)
2605 Preferences.Prefs.rsettings.setValue( 2612 Preferences.Prefs.rsettings.setValue(
2606 recentNameBreakpointConditions, condHistory) 2613 recentNameBreakpointConditions, condHistory
2614 )
2607 Preferences.Prefs.rsettings.sync() 2615 Preferences.Prefs.rsettings.sync()
2608 2616
2609 break 2617 break
2610 2618
2611 self.line = -1 2619 self.line = -1
2612 2620
2613 def menuNextBreakpoint(self): 2621 def menuNextBreakpoint(self):
2614 """ 2622 """
2615 Public slot to handle the 'Next breakpoint' context menu action. 2623 Public slot to handle the 'Next breakpoint' context menu action.
2616 """ 2624 """
2617 line, index = self.getCursorPosition() 2625 line, index = self.getCursorPosition()
2624 # wrap around 2632 # wrap around
2625 bpline = self.markerFindNext(0, self.breakpointMask) 2633 bpline = self.markerFindNext(0, self.breakpointMask)
2626 if bpline >= 0: 2634 if bpline >= 0:
2627 self.setCursorPosition(bpline, 0) 2635 self.setCursorPosition(bpline, 0)
2628 self.ensureLineVisible(bpline) 2636 self.ensureLineVisible(bpline)
2629 2637
2630 def menuPreviousBreakpoint(self): 2638 def menuPreviousBreakpoint(self):
2631 """ 2639 """
2632 Public slot to handle the 'Previous breakpoint' context menu action. 2640 Public slot to handle the 'Previous breakpoint' context menu action.
2633 """ 2641 """
2634 line, index = self.getCursorPosition() 2642 line, index = self.getCursorPosition()
2637 else: 2645 else:
2638 line -= 1 2646 line -= 1
2639 bpline = self.markerFindPrevious(line, self.breakpointMask) 2647 bpline = self.markerFindPrevious(line, self.breakpointMask)
2640 if bpline < 0: 2648 if bpline < 0:
2641 # wrap around 2649 # wrap around
2642 bpline = self.markerFindPrevious( 2650 bpline = self.markerFindPrevious(self.lines() - 1, self.breakpointMask)
2643 self.lines() - 1, self.breakpointMask)
2644 if bpline >= 0: 2651 if bpline >= 0:
2645 self.setCursorPosition(bpline, 0) 2652 self.setCursorPosition(bpline, 0)
2646 self.ensureLineVisible(bpline) 2653 self.ensureLineVisible(bpline)
2647 2654
2648 def __menuClearBreakpoints(self): 2655 def __menuClearBreakpoints(self):
2649 """ 2656 """
2650 Private slot to handle the 'Clear all breakpoints' context menu action. 2657 Private slot to handle the 'Clear all breakpoints' context menu action.
2651 """ 2658 """
2652 self.__clearBreakpoints(self.fileName) 2659 self.__clearBreakpoints(self.fileName)
2653 2660
2654 def __clearBreakpoints(self, fileName): 2661 def __clearBreakpoints(self, fileName):
2655 """ 2662 """
2656 Private slot to clear all breakpoints. 2663 Private slot to clear all breakpoints.
2657 2664
2658 @param fileName name of the file (string) 2665 @param fileName name of the file (string)
2659 """ 2666 """
2660 idxList = [] 2667 idxList = []
2661 for (ln, _, _, _, _) in self.breaks.values(): 2668 for (ln, _, _, _, _) in self.breaks.values():
2662 index = self.breakpointModel.getBreakPointIndex(fileName, ln) 2669 index = self.breakpointModel.getBreakPointIndex(fileName, ln)
2663 if index.isValid(): 2670 if index.isValid():
2664 idxList.append(index) 2671 idxList.append(index)
2665 if idxList: 2672 if idxList:
2666 self.breakpointModel.deleteBreakPoints(idxList) 2673 self.breakpointModel.deleteBreakPoints(idxList)
2667 2674
2668 ########################################################################### 2675 ###########################################################################
2669 ## Bookmark handling methods below 2676 ## Bookmark handling methods below
2670 ########################################################################### 2677 ###########################################################################
2671 2678
2672 def toggleBookmark(self, line): 2679 def toggleBookmark(self, line):
2673 """ 2680 """
2674 Public method to toggle a bookmark. 2681 Public method to toggle a bookmark.
2675 2682
2676 @param line line number of the bookmark (integer) 2683 @param line line number of the bookmark (integer)
2677 """ 2684 """
2678 for handle in self.bookmarks: 2685 for handle in self.bookmarks:
2679 if self.markerLine(handle) == line - 1: 2686 if self.markerLine(handle) == line - 1:
2680 self.bookmarks.remove(handle) 2687 self.bookmarks.remove(handle)
2684 # set a new bookmark 2691 # set a new bookmark
2685 handle = self.markerAdd(line - 1, self.bookmark) 2692 handle = self.markerAdd(line - 1, self.bookmark)
2686 self.bookmarks.append(handle) 2693 self.bookmarks.append(handle)
2687 self.bookmarkToggled.emit(self) 2694 self.bookmarkToggled.emit(self)
2688 self.__markerMap.update() 2695 self.__markerMap.update()
2689 2696
2690 def getBookmarks(self): 2697 def getBookmarks(self):
2691 """ 2698 """
2692 Public method to retrieve the bookmarks. 2699 Public method to retrieve the bookmarks.
2693 2700
2694 @return sorted list of all lines containing a bookmark 2701 @return sorted list of all lines containing a bookmark
2695 (list of integer) 2702 (list of integer)
2696 """ 2703 """
2697 bmlist = [] 2704 bmlist = []
2698 for handle in self.bookmarks: 2705 for handle in self.bookmarks:
2699 bmlist.append(self.markerLine(handle) + 1) 2706 bmlist.append(self.markerLine(handle) + 1)
2700 2707
2701 bmlist.sort() 2708 bmlist.sort()
2702 return bmlist 2709 return bmlist
2703 2710
2704 def getBookmarkLines(self): 2711 def getBookmarkLines(self):
2705 """ 2712 """
2706 Public method to get the lines containing a bookmark. 2713 Public method to get the lines containing a bookmark.
2707 2714
2708 @return list of lines containing a bookmark (list of integer) 2715 @return list of lines containing a bookmark (list of integer)
2709 """ 2716 """
2710 lines = [] 2717 lines = []
2711 line = -1 2718 line = -1
2712 while True: 2719 while True:
2714 if line < 0: 2721 if line < 0:
2715 break 2722 break
2716 else: 2723 else:
2717 lines.append(line) 2724 lines.append(line)
2718 return lines 2725 return lines
2719 2726
2720 def hasBookmarks(self): 2727 def hasBookmarks(self):
2721 """ 2728 """
2722 Public method to check for the presence of bookmarks. 2729 Public method to check for the presence of bookmarks.
2723 2730
2724 @return flag indicating the presence of bookmarks (boolean) 2731 @return flag indicating the presence of bookmarks (boolean)
2725 """ 2732 """
2726 return len(self.bookmarks) > 0 2733 return len(self.bookmarks) > 0
2727 2734
2728 def menuToggleBookmark(self): 2735 def menuToggleBookmark(self):
2729 """ 2736 """
2730 Public slot to handle the 'Toggle bookmark' context menu action. 2737 Public slot to handle the 'Toggle bookmark' context menu action.
2731 """ 2738 """
2732 if self.line < 0: 2739 if self.line < 0:
2733 self.line, index = self.getCursorPosition() 2740 self.line, index = self.getCursorPosition()
2734 self.line += 1 2741 self.line += 1
2735 self.toggleBookmark(self.line) 2742 self.toggleBookmark(self.line)
2736 self.line = -1 2743 self.line = -1
2737 2744
2738 def nextBookmark(self): 2745 def nextBookmark(self):
2739 """ 2746 """
2740 Public slot to handle the 'Next bookmark' context menu action. 2747 Public slot to handle the 'Next bookmark' context menu action.
2741 """ 2748 """
2742 line, index = self.getCursorPosition() 2749 line, index = self.getCursorPosition()
2749 # wrap around 2756 # wrap around
2750 bmline = self.markerFindNext(0, 1 << self.bookmark) 2757 bmline = self.markerFindNext(0, 1 << self.bookmark)
2751 if bmline >= 0: 2758 if bmline >= 0:
2752 self.setCursorPosition(bmline, 0) 2759 self.setCursorPosition(bmline, 0)
2753 self.ensureLineVisible(bmline) 2760 self.ensureLineVisible(bmline)
2754 2761
2755 def previousBookmark(self): 2762 def previousBookmark(self):
2756 """ 2763 """
2757 Public slot to handle the 'Previous bookmark' context menu action. 2764 Public slot to handle the 'Previous bookmark' context menu action.
2758 """ 2765 """
2759 line, index = self.getCursorPosition() 2766 line, index = self.getCursorPosition()
2762 else: 2769 else:
2763 line -= 1 2770 line -= 1
2764 bmline = self.markerFindPrevious(line, 1 << self.bookmark) 2771 bmline = self.markerFindPrevious(line, 1 << self.bookmark)
2765 if bmline < 0: 2772 if bmline < 0:
2766 # wrap around 2773 # wrap around
2767 bmline = self.markerFindPrevious( 2774 bmline = self.markerFindPrevious(self.lines() - 1, 1 << self.bookmark)
2768 self.lines() - 1, 1 << self.bookmark)
2769 if bmline >= 0: 2775 if bmline >= 0:
2770 self.setCursorPosition(bmline, 0) 2776 self.setCursorPosition(bmline, 0)
2771 self.ensureLineVisible(bmline) 2777 self.ensureLineVisible(bmline)
2772 2778
2773 def clearBookmarks(self): 2779 def clearBookmarks(self):
2774 """ 2780 """
2775 Public slot to handle the 'Clear all bookmarks' context menu action. 2781 Public slot to handle the 'Clear all bookmarks' context menu action.
2776 """ 2782 """
2777 for handle in self.bookmarks: 2783 for handle in self.bookmarks:
2778 self.markerDeleteHandle(handle) 2784 self.markerDeleteHandle(handle)
2779 self.bookmarks.clear() 2785 self.bookmarks.clear()
2780 self.bookmarkToggled.emit(self) 2786 self.bookmarkToggled.emit(self)
2781 self.__markerMap.update() 2787 self.__markerMap.update()
2782 2788
2783 ########################################################################### 2789 ###########################################################################
2784 ## Printing methods below 2790 ## Printing methods below
2785 ########################################################################### 2791 ###########################################################################
2786 2792
2787 def printFile(self): 2793 def printFile(self):
2788 """ 2794 """
2789 Public slot to print the text. 2795 Public slot to print the text.
2790 """ 2796 """
2791 from .Printer import Printer 2797 from .Printer import Printer
2798
2792 printer = Printer(mode=QPrinter.PrinterMode.HighResolution) 2799 printer = Printer(mode=QPrinter.PrinterMode.HighResolution)
2793 sb = ericApp().getObject("UserInterface").statusBar() 2800 sb = ericApp().getObject("UserInterface").statusBar()
2794 printDialog = QPrintDialog(printer, self) 2801 printDialog = QPrintDialog(printer, self)
2795 if self.hasSelectedText(): 2802 if self.hasSelectedText():
2796 printDialog.setOption( 2803 printDialog.setOption(
2797 QAbstractPrintDialog.PrintDialogOption.PrintSelection, 2804 QAbstractPrintDialog.PrintDialogOption.PrintSelection, True
2798 True) 2805 )
2799 if printDialog.exec() == QDialog.DialogCode.Accepted: 2806 if printDialog.exec() == QDialog.DialogCode.Accepted:
2800 sb.showMessage(self.tr('Printing...')) 2807 sb.showMessage(self.tr("Printing..."))
2801 QApplication.processEvents() 2808 QApplication.processEvents()
2802 fn = self.getFileName() 2809 fn = self.getFileName()
2803 if fn is not None: 2810 if fn is not None:
2804 printer.setDocName(os.path.basename(fn)) 2811 printer.setDocName(os.path.basename(fn))
2805 else: 2812 else:
2806 printer.setDocName(self.noName) 2813 printer.setDocName(self.noName)
2807 if ( 2814 if printDialog.printRange() == QAbstractPrintDialog.PrintRange.Selection:
2808 printDialog.printRange() ==
2809 QAbstractPrintDialog.PrintRange.Selection
2810 ):
2811 # get the selection 2815 # get the selection
2812 fromLine, fromIndex, toLine, toIndex = self.getSelection() 2816 fromLine, fromIndex, toLine, toIndex = self.getSelection()
2813 if toIndex == 0: 2817 if toIndex == 0:
2814 toLine -= 1 2818 toLine -= 1
2815 # QScintilla seems to print one line more than told 2819 # QScintilla seems to print one line more than told
2816 res = printer.printRange(self, fromLine, toLine - 1) 2820 res = printer.printRange(self, fromLine, toLine - 1)
2817 else: 2821 else:
2818 res = printer.printRange(self) 2822 res = printer.printRange(self)
2819 if res: 2823 if res:
2820 sb.showMessage(self.tr('Printing completed'), 2000) 2824 sb.showMessage(self.tr("Printing completed"), 2000)
2821 else: 2825 else:
2822 sb.showMessage(self.tr('Error while printing'), 2000) 2826 sb.showMessage(self.tr("Error while printing"), 2000)
2823 QApplication.processEvents() 2827 QApplication.processEvents()
2824 else: 2828 else:
2825 sb.showMessage(self.tr('Printing aborted'), 2000) 2829 sb.showMessage(self.tr("Printing aborted"), 2000)
2826 QApplication.processEvents() 2830 QApplication.processEvents()
2827 2831
2828 def printPreviewFile(self): 2832 def printPreviewFile(self):
2829 """ 2833 """
2830 Public slot to show a print preview of the text. 2834 Public slot to show a print preview of the text.
2831 """ 2835 """
2832 from PyQt6.QtPrintSupport import QPrintPreviewDialog 2836 from PyQt6.QtPrintSupport import QPrintPreviewDialog
2833 from .Printer import Printer 2837 from .Printer import Printer
2834 2838
2835 printer = Printer(mode=QPrinter.PrinterMode.HighResolution) 2839 printer = Printer(mode=QPrinter.PrinterMode.HighResolution)
2836 fn = self.getFileName() 2840 fn = self.getFileName()
2837 if fn is not None: 2841 if fn is not None:
2838 printer.setDocName(os.path.basename(fn)) 2842 printer.setDocName(os.path.basename(fn))
2839 else: 2843 else:
2840 printer.setDocName(self.noName) 2844 printer.setDocName(self.noName)
2841 preview = QPrintPreviewDialog(printer, self) 2845 preview = QPrintPreviewDialog(printer, self)
2842 preview.paintRequested.connect(self.__printPreview) 2846 preview.paintRequested.connect(self.__printPreview)
2843 preview.exec() 2847 preview.exec()
2844 2848
2845 def __printPreview(self, printer): 2849 def __printPreview(self, printer):
2846 """ 2850 """
2847 Private slot to generate a print preview. 2851 Private slot to generate a print preview.
2848 2852
2849 @param printer reference to the printer object 2853 @param printer reference to the printer object
2850 (QScintilla.Printer.Printer) 2854 (QScintilla.Printer.Printer)
2851 """ 2855 """
2852 printer.printRange(self) 2856 printer.printRange(self)
2853 2857
2854 ########################################################################### 2858 ###########################################################################
2855 ## Task handling methods below 2859 ## Task handling methods below
2856 ########################################################################### 2860 ###########################################################################
2857 2861
2858 def getTaskLines(self): 2862 def getTaskLines(self):
2859 """ 2863 """
2860 Public method to get the lines containing a task. 2864 Public method to get the lines containing a task.
2861 2865
2862 @return list of lines containing a task (list of integer) 2866 @return list of lines containing a task (list of integer)
2863 """ 2867 """
2864 lines = [] 2868 lines = []
2865 line = -1 2869 line = -1
2866 while True: 2870 while True:
2868 if line < 0: 2872 if line < 0:
2869 break 2873 break
2870 else: 2874 else:
2871 lines.append(line) 2875 lines.append(line)
2872 return lines 2876 return lines
2873 2877
2874 def hasTaskMarkers(self): 2878 def hasTaskMarkers(self):
2875 """ 2879 """
2876 Public method to determine, if this editor contains any task markers. 2880 Public method to determine, if this editor contains any task markers.
2877 2881
2878 @return flag indicating the presence of task markers (boolean) 2882 @return flag indicating the presence of task markers (boolean)
2879 """ 2883 """
2880 return self.__hasTaskMarkers 2884 return self.__hasTaskMarkers
2881 2885
2882 def nextTask(self): 2886 def nextTask(self):
2883 """ 2887 """
2884 Public slot to handle the 'Next task' context menu action. 2888 Public slot to handle the 'Next task' context menu action.
2885 """ 2889 """
2886 line, index = self.getCursorPosition() 2890 line, index = self.getCursorPosition()
2893 # wrap around 2897 # wrap around
2894 taskline = self.markerFindNext(0, 1 << self.taskmarker) 2898 taskline = self.markerFindNext(0, 1 << self.taskmarker)
2895 if taskline >= 0: 2899 if taskline >= 0:
2896 self.setCursorPosition(taskline, 0) 2900 self.setCursorPosition(taskline, 0)
2897 self.ensureLineVisible(taskline) 2901 self.ensureLineVisible(taskline)
2898 2902
2899 def previousTask(self): 2903 def previousTask(self):
2900 """ 2904 """
2901 Public slot to handle the 'Previous task' context menu action. 2905 Public slot to handle the 'Previous task' context menu action.
2902 """ 2906 """
2903 line, index = self.getCursorPosition() 2907 line, index = self.getCursorPosition()
2906 else: 2910 else:
2907 line -= 1 2911 line -= 1
2908 taskline = self.markerFindPrevious(line, 1 << self.taskmarker) 2912 taskline = self.markerFindPrevious(line, 1 << self.taskmarker)
2909 if taskline < 0: 2913 if taskline < 0:
2910 # wrap around 2914 # wrap around
2911 taskline = self.markerFindPrevious( 2915 taskline = self.markerFindPrevious(self.lines() - 1, 1 << self.taskmarker)
2912 self.lines() - 1, 1 << self.taskmarker)
2913 if taskline >= 0: 2916 if taskline >= 0:
2914 self.setCursorPosition(taskline, 0) 2917 self.setCursorPosition(taskline, 0)
2915 self.ensureLineVisible(taskline) 2918 self.ensureLineVisible(taskline)
2916 2919
2917 def extractTasks(self): 2920 def extractTasks(self):
2918 """ 2921 """
2919 Public slot to extract all tasks. 2922 Public slot to extract all tasks.
2920 """ 2923 """
2921 from Tasks.Task import Task 2924 from Tasks.Task import Task
2925
2922 markers = { 2926 markers = {
2923 taskType: Preferences.getTasks(markersName).split() 2927 taskType: Preferences.getTasks(markersName).split()
2924 for taskType, markersName in Task.TaskType2MarkersName.items() 2928 for taskType, markersName in Task.TaskType2MarkersName.items()
2925 } 2929 }
2926 txtList = self.text().split(self.getLineSeparator()) 2930 txtList = self.text().split(self.getLineSeparator())
2927 2931
2928 # clear all task markers and tasks 2932 # clear all task markers and tasks
2929 self.markerDeleteAll(self.taskmarker) 2933 self.markerDeleteAll(self.taskmarker)
2930 self.taskViewer.clearFileTasks(self.fileName) 2934 self.taskViewer.clearFileTasks(self.fileName)
2931 self.__hasTaskMarkers = False 2935 self.__hasTaskMarkers = False
2932 2936
2933 # now search tasks and record them 2937 # now search tasks and record them
2934 for lineIndex, line in enumerate(txtList): 2938 for lineIndex, line in enumerate(txtList):
2935 shouldBreak = False 2939 shouldBreak = False
2936 2940
2937 if line.endswith("__NO-TASK__"): 2941 if line.endswith("__NO-TASK__"):
2938 # ignore potential task marker 2942 # ignore potential task marker
2939 continue 2943 continue
2940 2944
2941 for taskType, taskMarkers in markers.items(): 2945 for taskType, taskMarkers in markers.items():
2942 for taskMarker in taskMarkers: 2946 for taskMarker in taskMarkers:
2943 index = line.find(taskMarker) 2947 index = line.find(taskMarker)
2944 if index > -1: 2948 if index > -1:
2945 task = line[index:] 2949 task = line[index:]
2946 self.markerAdd(lineIndex, self.taskmarker) 2950 self.markerAdd(lineIndex, self.taskmarker)
2947 self.taskViewer.addFileTask( 2951 self.taskViewer.addFileTask(
2948 task, self.fileName, lineIndex + 1, taskType) 2952 task, self.fileName, lineIndex + 1, taskType
2953 )
2949 self.__hasTaskMarkers = True 2954 self.__hasTaskMarkers = True
2950 shouldBreak = True 2955 shouldBreak = True
2951 break 2956 break
2952 if shouldBreak: 2957 if shouldBreak:
2953 break 2958 break
2954 self.taskMarkersUpdated.emit(self) 2959 self.taskMarkersUpdated.emit(self)
2955 self.__markerMap.update() 2960 self.__markerMap.update()
2956 2961
2957 ########################################################################### 2962 ###########################################################################
2958 ## Change tracing methods below 2963 ## Change tracing methods below
2959 ########################################################################### 2964 ###########################################################################
2960 2965
2961 def __createChangeMarkerPixmap(self, key, size=16, width=4): 2966 def __createChangeMarkerPixmap(self, key, size=16, width=4):
2962 """ 2967 """
2963 Private method to create a pixmap for the change markers. 2968 Private method to create a pixmap for the change markers.
2964 2969
2965 @param key key of the color to use (string) 2970 @param key key of the color to use (string)
2966 @param size size of the pixmap (integer) 2971 @param size size of the pixmap (integer)
2967 @param width width of the marker line (integer) 2972 @param width width of the marker line (integer)
2968 @return create pixmap (QPixmap) 2973 @return create pixmap (QPixmap)
2969 """ 2974 """
2970 pixmap = QPixmap(size, size) 2975 pixmap = QPixmap(size, size)
2971 pixmap.fill(Qt.GlobalColor.transparent) 2976 pixmap.fill(Qt.GlobalColor.transparent)
2972 painter = QPainter(pixmap) 2977 painter = QPainter(pixmap)
2973 painter.fillRect(size - 4, 0, 4, size, 2978 painter.fillRect(size - 4, 0, 4, size, Preferences.getEditorColour(key))
2974 Preferences.getEditorColour(key))
2975 painter.end() 2979 painter.end()
2976 return pixmap 2980 return pixmap
2977 2981
2978 def __initOnlineChangeTrace(self): 2982 def __initOnlineChangeTrace(self):
2979 """ 2983 """
2980 Private slot to initialize the online change trace. 2984 Private slot to initialize the online change trace.
2981 """ 2985 """
2982 self.__hasChangeMarkers = False 2986 self.__hasChangeMarkers = False
2983 self.__oldText = self.text() 2987 self.__oldText = self.text()
2984 self.__lastSavedText = self.text() 2988 self.__lastSavedText = self.text()
2985 self.__onlineChangeTraceTimer = QTimer(self) 2989 self.__onlineChangeTraceTimer = QTimer(self)
2986 self.__onlineChangeTraceTimer.setSingleShot(True) 2990 self.__onlineChangeTraceTimer.setSingleShot(True)
2987 self.__onlineChangeTraceTimer.setInterval( 2991 self.__onlineChangeTraceTimer.setInterval(
2988 Preferences.getEditor("OnlineChangeTraceInterval")) 2992 Preferences.getEditor("OnlineChangeTraceInterval")
2993 )
2989 self.__onlineChangeTraceTimer.timeout.connect( 2994 self.__onlineChangeTraceTimer.timeout.connect(
2990 self.__onlineChangeTraceTimerTimeout) 2995 self.__onlineChangeTraceTimerTimeout
2996 )
2991 self.textChanged.connect(self.__resetOnlineChangeTraceTimer) 2997 self.textChanged.connect(self.__resetOnlineChangeTraceTimer)
2992 2998
2993 def __reinitOnlineChangeTrace(self): 2999 def __reinitOnlineChangeTrace(self):
2994 """ 3000 """
2995 Private slot to re-initialize the online change trace. 3001 Private slot to re-initialize the online change trace.
2996 """ 3002 """
2997 self.__oldText = self.text() 3003 self.__oldText = self.text()
2998 self.__lastSavedText = self.text() 3004 self.__lastSavedText = self.text()
2999 self.__deleteAllChangeMarkers() 3005 self.__deleteAllChangeMarkers()
3000 3006
3001 def __resetOnlineChangeTraceTimer(self): 3007 def __resetOnlineChangeTraceTimer(self):
3002 """ 3008 """
3003 Private method to reset the online syntax check timer. 3009 Private method to reset the online syntax check timer.
3004 """ 3010 """
3005 if Preferences.getEditor("OnlineChangeTrace"): 3011 if Preferences.getEditor("OnlineChangeTrace"):
3006 self.__onlineChangeTraceTimer.stop() 3012 self.__onlineChangeTraceTimer.stop()
3007 self.__onlineChangeTraceTimer.start() 3013 self.__onlineChangeTraceTimer.start()
3008 3014
3009 def __onlineChangeTraceTimerTimeout(self): 3015 def __onlineChangeTraceTimerTimeout(self):
3010 """ 3016 """
3011 Private slot to mark added and changed lines. 3017 Private slot to mark added and changed lines.
3012 """ 3018 """
3013 self.__deleteAllChangeMarkers() 3019 self.__deleteAllChangeMarkers()
3014 3020
3015 # step 1: mark saved changes 3021 # step 1: mark saved changes
3016 oldL = self.__oldText.splitlines() 3022 oldL = self.__oldText.splitlines()
3017 newL = self.__lastSavedText.splitlines() 3023 newL = self.__lastSavedText.splitlines()
3018 matcher = difflib.SequenceMatcher(None, oldL, newL) 3024 matcher = difflib.SequenceMatcher(None, oldL, newL)
3019 3025
3020 for token, _, _, j1, j2 in matcher.get_opcodes(): 3026 for token, _, _, j1, j2 in matcher.get_opcodes():
3021 if token in ["insert", "replace"]: 3027 if token in ["insert", "replace"]:
3022 for lineNo in range(j1, j2): 3028 for lineNo in range(j1, j2):
3023 self.markerAdd(lineNo, self.__changeMarkerSaved) 3029 self.markerAdd(lineNo, self.__changeMarkerSaved)
3024 self.__hasChangeMarkers = True 3030 self.__hasChangeMarkers = True
3025 3031
3026 # step 2: mark unsaved changes 3032 # step 2: mark unsaved changes
3027 oldL = self.__lastSavedText.splitlines() 3033 oldL = self.__lastSavedText.splitlines()
3028 newL = self.text().splitlines() 3034 newL = self.text().splitlines()
3029 matcher = difflib.SequenceMatcher(None, oldL, newL) 3035 matcher = difflib.SequenceMatcher(None, oldL, newL)
3030 3036
3031 for token, _, _, j1, j2 in matcher.get_opcodes(): 3037 for token, _, _, j1, j2 in matcher.get_opcodes():
3032 if token in ["insert", "replace"]: 3038 if token in ["insert", "replace"]:
3033 for lineNo in range(j1, j2): 3039 for lineNo in range(j1, j2):
3034 self.markerAdd(lineNo, self.__changeMarkerUnsaved) 3040 self.markerAdd(lineNo, self.__changeMarkerUnsaved)
3035 self.__hasChangeMarkers = True 3041 self.__hasChangeMarkers = True
3036 3042
3037 if self.__hasChangeMarkers: 3043 if self.__hasChangeMarkers:
3038 self.changeMarkersUpdated.emit(self) 3044 self.changeMarkersUpdated.emit(self)
3039 self.__markerMap.update() 3045 self.__markerMap.update()
3040 3046
3041 def __resetOnlineChangeTraceInfo(self): 3047 def __resetOnlineChangeTraceInfo(self):
3042 """ 3048 """
3043 Private slot to reset the online change trace info. 3049 Private slot to reset the online change trace info.
3044 """ 3050 """
3045 self.__lastSavedText = self.text() 3051 self.__lastSavedText = self.text()
3046 self.__deleteAllChangeMarkers() 3052 self.__deleteAllChangeMarkers()
3047 3053
3048 # mark saved changes 3054 # mark saved changes
3049 oldL = self.__oldText.splitlines() 3055 oldL = self.__oldText.splitlines()
3050 newL = self.__lastSavedText.splitlines() 3056 newL = self.__lastSavedText.splitlines()
3051 matcher = difflib.SequenceMatcher(None, oldL, newL) 3057 matcher = difflib.SequenceMatcher(None, oldL, newL)
3052 3058
3053 for token, _, _, j1, j2 in matcher.get_opcodes(): 3059 for token, _, _, j1, j2 in matcher.get_opcodes():
3054 if token in ["insert", "replace"]: 3060 if token in ["insert", "replace"]:
3055 for lineNo in range(j1, j2): 3061 for lineNo in range(j1, j2):
3056 self.markerAdd(lineNo, self.__changeMarkerSaved) 3062 self.markerAdd(lineNo, self.__changeMarkerSaved)
3057 self.__hasChangeMarkers = True 3063 self.__hasChangeMarkers = True
3058 3064
3059 if self.__hasChangeMarkers: 3065 if self.__hasChangeMarkers:
3060 self.changeMarkersUpdated.emit(self) 3066 self.changeMarkersUpdated.emit(self)
3061 self.__markerMap.update() 3067 self.__markerMap.update()
3062 3068
3063 def __deleteAllChangeMarkers(self): 3069 def __deleteAllChangeMarkers(self):
3064 """ 3070 """
3065 Private slot to delete all change markers. 3071 Private slot to delete all change markers.
3066 """ 3072 """
3067 self.markerDeleteAll(self.__changeMarkerUnsaved) 3073 self.markerDeleteAll(self.__changeMarkerUnsaved)
3068 self.markerDeleteAll(self.__changeMarkerSaved) 3074 self.markerDeleteAll(self.__changeMarkerSaved)
3069 self.__hasChangeMarkers = False 3075 self.__hasChangeMarkers = False
3070 self.changeMarkersUpdated.emit(self) 3076 self.changeMarkersUpdated.emit(self)
3071 self.__markerMap.update() 3077 self.__markerMap.update()
3072 3078
3073 def getChangeLines(self): 3079 def getChangeLines(self):
3074 """ 3080 """
3075 Public method to get the lines containing a change. 3081 Public method to get the lines containing a change.
3076 3082
3077 @return list of lines containing a change (list of integer) 3083 @return list of lines containing a change (list of integer)
3078 """ 3084 """
3079 lines = [] 3085 lines = []
3080 line = -1 3086 line = -1
3081 while True: 3087 while True:
3083 if line < 0: 3089 if line < 0:
3084 break 3090 break
3085 else: 3091 else:
3086 lines.append(line) 3092 lines.append(line)
3087 return lines 3093 return lines
3088 3094
3089 def hasChangeMarkers(self): 3095 def hasChangeMarkers(self):
3090 """ 3096 """
3091 Public method to determine, if this editor contains any change markers. 3097 Public method to determine, if this editor contains any change markers.
3092 3098
3093 @return flag indicating the presence of change markers (boolean) 3099 @return flag indicating the presence of change markers (boolean)
3094 """ 3100 """
3095 return self.__hasChangeMarkers 3101 return self.__hasChangeMarkers
3096 3102
3097 def nextChange(self): 3103 def nextChange(self):
3098 """ 3104 """
3099 Public slot to handle the 'Next change' context menu action. 3105 Public slot to handle the 'Next change' context menu action.
3100 """ 3106 """
3101 line, index = self.getCursorPosition() 3107 line, index = self.getCursorPosition()
3108 # wrap around 3114 # wrap around
3109 changeline = self.markerFindNext(0, self.changeMarkersMask) 3115 changeline = self.markerFindNext(0, self.changeMarkersMask)
3110 if changeline >= 0: 3116 if changeline >= 0:
3111 self.setCursorPosition(changeline, 0) 3117 self.setCursorPosition(changeline, 0)
3112 self.ensureLineVisible(changeline) 3118 self.ensureLineVisible(changeline)
3113 3119
3114 def previousChange(self): 3120 def previousChange(self):
3115 """ 3121 """
3116 Public slot to handle the 'Previous change' context menu action. 3122 Public slot to handle the 'Previous change' context menu action.
3117 """ 3123 """
3118 line, index = self.getCursorPosition() 3124 line, index = self.getCursorPosition()
3122 line -= 1 3128 line -= 1
3123 changeline = self.markerFindPrevious(line, self.changeMarkersMask) 3129 changeline = self.markerFindPrevious(line, self.changeMarkersMask)
3124 if changeline < 0: 3130 if changeline < 0:
3125 # wrap around 3131 # wrap around
3126 changeline = self.markerFindPrevious( 3132 changeline = self.markerFindPrevious(
3127 self.lines() - 1, self.changeMarkersMask) 3133 self.lines() - 1, self.changeMarkersMask
3134 )
3128 if changeline >= 0: 3135 if changeline >= 0:
3129 self.setCursorPosition(changeline, 0) 3136 self.setCursorPosition(changeline, 0)
3130 self.ensureLineVisible(changeline) 3137 self.ensureLineVisible(changeline)
3131 3138
3132 ########################################################################### 3139 ###########################################################################
3133 ## Flags handling methods below 3140 ## Flags handling methods below
3134 ########################################################################### 3141 ###########################################################################
3135 3142
3136 def __processFlags(self): 3143 def __processFlags(self):
3137 """ 3144 """
3138 Private method to extract flags and process them. 3145 Private method to extract flags and process them.
3139 3146
3140 @return list of change flags (list of string) 3147 @return list of change flags (list of string)
3141 """ 3148 """
3142 txt = self.text() 3149 txt = self.text()
3143 flags = Utilities.extractFlags(txt) 3150 flags = Utilities.extractFlags(txt)
3144 3151
3145 changedFlags = [] 3152 changedFlags = []
3146 3153
3147 # Flag 1: FileType 3154 # Flag 1: FileType
3148 if "FileType" in flags: 3155 if "FileType" in flags:
3149 oldFiletype = self.filetype 3156 oldFiletype = self.filetype
3150 if isinstance(flags["FileType"], str): 3157 if isinstance(flags["FileType"], str):
3151 self.filetype = flags["FileType"] 3158 self.filetype = flags["FileType"]
3156 if self.filetype != "" and self.filetypeByFlag: 3163 if self.filetype != "" and self.filetypeByFlag:
3157 self.filetype = "" 3164 self.filetype = ""
3158 self.filetypeByFlag = False 3165 self.filetypeByFlag = False
3159 self.__bindName(txt.splitlines()[0]) 3166 self.__bindName(txt.splitlines()[0])
3160 changedFlags.append("FileType") 3167 changedFlags.append("FileType")
3161 3168
3162 return changedFlags 3169 return changedFlags
3163 3170
3164 ########################################################################### 3171 ###########################################################################
3165 ## File handling methods below 3172 ## File handling methods below
3166 ########################################################################### 3173 ###########################################################################
3167 3174
3168 def checkDirty(self): 3175 def checkDirty(self):
3169 """ 3176 """
3170 Public method to check dirty status and open a message window. 3177 Public method to check dirty status and open a message window.
3171 3178
3172 @return flag indicating successful reset of the dirty flag (boolean) 3179 @return flag indicating successful reset of the dirty flag (boolean)
3173 """ 3180 """
3174 if self.isModified(): 3181 if self.isModified():
3175 fn = self.fileName 3182 fn = self.fileName
3176 if fn is None: 3183 if fn is None:
3177 fn = self.noName 3184 fn = self.noName
3178 res = EricMessageBox.okToClearData( 3185 res = EricMessageBox.okToClearData(
3179 self, 3186 self,
3180 self.tr("File Modified"), 3187 self.tr("File Modified"),
3181 self.tr("<p>The file <b>{0}</b> has unsaved changes.</p>") 3188 self.tr("<p>The file <b>{0}</b> has unsaved changes.</p>").format(fn),
3182 .format(fn), 3189 self.saveFile,
3183 self.saveFile) 3190 )
3184 if res: 3191 if res:
3185 self.vm.setEditorName(self, self.fileName) 3192 self.vm.setEditorName(self, self.fileName)
3186 return res 3193 return res
3187 3194
3188 return True 3195 return True
3189 3196
3190 def revertToUnmodified(self): 3197 def revertToUnmodified(self):
3191 """ 3198 """
3192 Public method to revert back to the last saved state. 3199 Public method to revert back to the last saved state.
3193 """ 3200 """
3194 undo_ = True 3201 undo_ = True
3204 if self.isRedoAvailable(): 3211 if self.isRedoAvailable():
3205 self.redo() 3212 self.redo()
3206 else: 3213 else:
3207 break 3214 break
3208 # Couldn't find the unmodified state 3215 # Couldn't find the unmodified state
3209 3216
3210 def readFile(self, fn, createIt=False, encoding=""): 3217 def readFile(self, fn, createIt=False, encoding=""):
3211 """ 3218 """
3212 Public slot to read the text from a file. 3219 Public slot to read the text from a file.
3213 3220
3214 @param fn filename to read from (string) 3221 @param fn filename to read from (string)
3215 @param createIt flag indicating the creation of a new file, if the 3222 @param createIt flag indicating the creation of a new file, if the
3216 given one doesn't exist (boolean) 3223 given one doesn't exist (boolean)
3217 @param encoding encoding to be used to read the file (string) 3224 @param encoding encoding to be used to read the file (string)
3218 (Note: this parameter overrides encoding detection) 3225 (Note: this parameter overrides encoding detection)
3219 """ 3226 """
3220 self.__loadEditorConfig(fileName=fn) 3227 self.__loadEditorConfig(fileName=fn)
3221 3228
3222 try: 3229 try:
3223 with EricOverrideCursor(): 3230 with EricOverrideCursor():
3224 if createIt and not os.path.exists(fn): 3231 if createIt and not os.path.exists(fn):
3225 with open(fn, "w"): 3232 with open(fn, "w"):
3226 pass 3233 pass
3227 if encoding == "": 3234 if encoding == "":
3228 encoding = self.__getEditorConfig("DefaultEncoding", 3235 encoding = self.__getEditorConfig("DefaultEncoding", nodefault=True)
3229 nodefault=True)
3230 if encoding: 3236 if encoding:
3231 txt, self.encoding = Utilities.readEncodedFileWithEncoding( 3237 txt, self.encoding = Utilities.readEncodedFileWithEncoding(
3232 fn, encoding) 3238 fn, encoding
3239 )
3233 else: 3240 else:
3234 txt, self.encoding = Utilities.readEncodedFile(fn) 3241 txt, self.encoding = Utilities.readEncodedFile(fn)
3235 except (UnicodeDecodeError, OSError) as why: 3242 except (UnicodeDecodeError, OSError) as why:
3236 EricMessageBox.critical( 3243 EricMessageBox.critical(
3237 self.vm, 3244 self.vm,
3238 self.tr('Open File'), 3245 self.tr("Open File"),
3239 self.tr('<p>The file <b>{0}</b> could not be opened.</p>' 3246 self.tr(
3240 '<p>Reason: {1}</p>') 3247 "<p>The file <b>{0}</b> could not be opened.</p>"
3241 .format(fn, str(why))) 3248 "<p>Reason: {1}</p>"
3249 ).format(fn, str(why)),
3250 )
3242 raise 3251 raise
3243 3252
3244 with EricOverrideCursor(): 3253 with EricOverrideCursor():
3245 modified = False 3254 modified = False
3246 3255
3247 self.setText(txt) 3256 self.setText(txt)
3248 3257
3249 # get eric specific flags 3258 # get eric specific flags
3250 self.__processFlags() 3259 self.__processFlags()
3251 3260
3252 # perform automatic EOL conversion 3261 # perform automatic EOL conversion
3253 if ( 3262 if self.__getEditorConfig(
3254 self.__getEditorConfig("EOLMode", nodefault=True) or 3263 "EOLMode", nodefault=True
3255 Preferences.getEditor("AutomaticEOLConversion") 3264 ) or Preferences.getEditor("AutomaticEOLConversion"):
3256 ):
3257 self.convertEols(self.eolMode()) 3265 self.convertEols(self.eolMode())
3258 else: 3266 else:
3259 fileEol = self.detectEolString(txt) 3267 fileEol = self.detectEolString(txt)
3260 self.setEolModeByEolString(fileEol) 3268 self.setEolModeByEolString(fileEol)
3261 3269
3262 self.extractTasks() 3270 self.extractTasks()
3263 3271
3264 self.setModified(modified) 3272 self.setModified(modified)
3265 self.lastModified = pathlib.Path(fn).stat().st_mtime 3273 self.lastModified = pathlib.Path(fn).stat().st_mtime
3266 3274
3267 def __convertTabs(self): 3275 def __convertTabs(self):
3268 """ 3276 """
3269 Private slot to convert tabulators to spaces. 3277 Private slot to convert tabulators to spaces.
3270 """ 3278 """
3271 if ( 3279 if (
3272 (not self.__getEditorConfig("TabForIndentation")) and 3280 (not self.__getEditorConfig("TabForIndentation"))
3273 Preferences.getEditor("ConvertTabsOnLoad") and 3281 and Preferences.getEditor("ConvertTabsOnLoad")
3274 not (self.lexer_ and 3282 and not (self.lexer_ and self.lexer_.alwaysKeepTabs())
3275 self.lexer_.alwaysKeepTabs())
3276 ): 3283 ):
3277 txt = self.text() 3284 txt = self.text()
3278 txtExpanded = txt.expandtabs(self.__getEditorConfig("TabWidth")) 3285 txtExpanded = txt.expandtabs(self.__getEditorConfig("TabWidth"))
3279 if txtExpanded != txt: 3286 if txtExpanded != txt:
3280 self.beginUndoAction() 3287 self.beginUndoAction()
3281 self.setText(txt) 3288 self.setText(txt)
3282 self.endUndoAction() 3289 self.endUndoAction()
3283 3290
3284 self.setModified(True) 3291 self.setModified(True)
3285 3292
3286 def __removeTrailingWhitespace(self): 3293 def __removeTrailingWhitespace(self):
3287 """ 3294 """
3288 Private method to remove trailing whitespace. 3295 Private method to remove trailing whitespace.
3289 """ 3296 """
3290 searchRE = r"[ \t]+$" # whitespace at the end of a line 3297 searchRE = r"[ \t]+$" # whitespace at the end of a line
3291 3298
3292 ok = self.findFirstTarget(searchRE, True, False, False, 0, 0) 3299 ok = self.findFirstTarget(searchRE, True, False, False, 0, 0)
3293 self.beginUndoAction() 3300 self.beginUndoAction()
3294 while ok: 3301 while ok:
3295 self.replaceTarget("") 3302 self.replaceTarget("")
3296 ok = self.findNextTarget() 3303 ok = self.findNextTarget()
3297 self.endUndoAction() 3304 self.endUndoAction()
3298 3305
3299 def writeFile(self, fn, backup=True): 3306 def writeFile(self, fn, backup=True):
3300 """ 3307 """
3301 Public slot to write the text to a file. 3308 Public slot to write the text to a file.
3302 3309
3303 @param fn filename to write to (string) 3310 @param fn filename to write to (string)
3304 @param backup flag indicating to save a backup (boolean) 3311 @param backup flag indicating to save a backup (boolean)
3305 @return flag indicating success (boolean) 3312 @return flag indicating success (boolean)
3306 """ 3313 """
3307 config = self.__loadEditorConfigObject(fn) 3314 config = self.__loadEditorConfigObject(fn)
3308 3315
3309 eol = self.__getEditorConfig("EOLMode", nodefault=True, config=config) 3316 eol = self.__getEditorConfig("EOLMode", nodefault=True, config=config)
3310 if eol is not None: 3317 if eol is not None:
3311 self.convertEols(eol) 3318 self.convertEols(eol)
3312 3319
3313 if self.__getEditorConfig("StripTrailingWhitespace", config=config): 3320 if self.__getEditorConfig("StripTrailingWhitespace", config=config):
3314 self.__removeTrailingWhitespace() 3321 self.__removeTrailingWhitespace()
3315 3322
3316 txt = self.text() 3323 txt = self.text()
3317 3324
3318 if self.__getEditorConfig("InsertFinalNewline", config=config): 3325 if self.__getEditorConfig("InsertFinalNewline", config=config):
3319 eol = self.getLineSeparator() 3326 eol = self.getLineSeparator()
3320 if eol: 3327 if eol:
3321 if len(txt) >= len(eol): 3328 if len(txt) >= len(eol):
3322 if txt[-len(eol):] != eol: 3329 if txt[-len(eol) :] != eol:
3323 txt += eol 3330 txt += eol
3324 else: 3331 else:
3325 txt += eol 3332 txt += eol
3326 3333
3327 # create a backup file, if the option is set 3334 # create a backup file, if the option is set
3328 createBackup = backup and Preferences.getEditor("CreateBackupFile") 3335 createBackup = backup and Preferences.getEditor("CreateBackupFile")
3329 if createBackup: 3336 if createBackup:
3330 if os.path.islink(fn): 3337 if os.path.islink(fn):
3331 fn = os.path.realpath(fn) 3338 fn = os.path.realpath(fn)
3332 bfn = '{0}~'.format(fn) 3339 bfn = "{0}~".format(fn)
3333 try: 3340 try:
3334 permissions = os.stat(fn).st_mode 3341 permissions = os.stat(fn).st_mode
3335 perms_valid = True 3342 perms_valid = True
3336 except OSError: 3343 except OSError:
3337 # if there was an error, ignore it 3344 # if there was an error, ignore it
3338 perms_valid = False 3345 perms_valid = False
3339 with contextlib.suppress(OSError): 3346 with contextlib.suppress(OSError):
3340 os.remove(bfn) 3347 os.remove(bfn)
3341 with contextlib.suppress(OSError): 3348 with contextlib.suppress(OSError):
3342 os.rename(fn, bfn) 3349 os.rename(fn, bfn)
3343 3350
3344 # now write text to the file fn 3351 # now write text to the file fn
3345 try: 3352 try:
3346 editorConfigEncoding = self.__getEditorConfig( 3353 editorConfigEncoding = self.__getEditorConfig(
3347 "DefaultEncoding", nodefault=True, config=config) 3354 "DefaultEncoding", nodefault=True, config=config
3355 )
3348 self.encoding = Utilities.writeEncodedFile( 3356 self.encoding = Utilities.writeEncodedFile(
3349 fn, txt, self.encoding, forcedEncoding=editorConfigEncoding) 3357 fn, txt, self.encoding, forcedEncoding=editorConfigEncoding
3358 )
3350 if createBackup and perms_valid: 3359 if createBackup and perms_valid:
3351 os.chmod(fn, permissions) 3360 os.chmod(fn, permissions)
3352 return True 3361 return True
3353 except (OSError, Utilities.CodingError, UnicodeError) as why: 3362 except (OSError, Utilities.CodingError, UnicodeError) as why:
3354 EricMessageBox.critical( 3363 EricMessageBox.critical(
3355 self, 3364 self,
3356 self.tr('Save File'), 3365 self.tr("Save File"),
3357 self.tr('<p>The file <b>{0}</b> could not be saved.<br/>' 3366 self.tr(
3358 'Reason: {1}</p>') 3367 "<p>The file <b>{0}</b> could not be saved.<br/>" "Reason: {1}</p>"
3359 .format(fn, str(why))) 3368 ).format(fn, str(why)),
3369 )
3360 return False 3370 return False
3361 3371
3362 def __getSaveFileName(self, path=None): 3372 def __getSaveFileName(self, path=None):
3363 """ 3373 """
3364 Private method to get the name of the file to be saved. 3374 Private method to get the name of the file to be saved.
3365 3375
3366 @param path directory to save the file in (string) 3376 @param path directory to save the file in (string)
3367 @return file name (string) 3377 @return file name (string)
3368 """ 3378 """
3369 # save to project, if a project is loaded 3379 # save to project, if a project is loaded
3370 if self.project.isOpen(): 3380 if self.project.isOpen():
3371 if ( 3381 if self.fileName and self.project.startswithProjectPath(self.fileName):
3372 self.fileName and
3373 self.project.startswithProjectPath(self.fileName)
3374 ):
3375 path = os.path.dirname(self.fileName) 3382 path = os.path.dirname(self.fileName)
3376 elif not self.fileName: 3383 elif not self.fileName:
3377 path = self.project.getProjectPath() 3384 path = self.project.getProjectPath()
3378 3385
3379 if not path and self.fileName: 3386 if not path and self.fileName:
3380 path = os.path.dirname(self.fileName) 3387 path = os.path.dirname(self.fileName)
3381 if not path: 3388 if not path:
3382 path = ( 3389 path = Preferences.getMultiProject("Workspace") or Utilities.getHomeDir()
3383 Preferences.getMultiProject("Workspace") or 3390
3384 Utilities.getHomeDir()
3385 )
3386
3387 from . import Lexers 3391 from . import Lexers
3392
3388 if self.fileName: 3393 if self.fileName:
3389 filterPattern = "(*{0})".format( 3394 filterPattern = "(*{0})".format(os.path.splitext(self.fileName)[1])
3390 os.path.splitext(self.fileName)[1])
3391 for fileFilter in Lexers.getSaveFileFiltersList(True): 3395 for fileFilter in Lexers.getSaveFileFiltersList(True):
3392 if filterPattern in fileFilter: 3396 if filterPattern in fileFilter:
3393 defaultFilter = fileFilter 3397 defaultFilter = fileFilter
3394 break 3398 break
3395 else: 3399 else:
3400 self, 3404 self,
3401 self.tr("Save File"), 3405 self.tr("Save File"),
3402 path, 3406 path,
3403 Lexers.getSaveFileFiltersList(True, True), 3407 Lexers.getSaveFileFiltersList(True, True),
3404 defaultFilter, 3408 defaultFilter,
3405 EricFileDialog.DontConfirmOverwrite) 3409 EricFileDialog.DontConfirmOverwrite,
3406 3410 )
3411
3407 if fn: 3412 if fn:
3408 if fn.endswith("."): 3413 if fn.endswith("."):
3409 fn = fn[:-1] 3414 fn = fn[:-1]
3410 3415
3411 fpath = pathlib.Path(fn) 3416 fpath = pathlib.Path(fn)
3412 if not fpath.suffix: 3417 if not fpath.suffix:
3413 ex = selectedFilter.split("(*")[1].split(")")[0] 3418 ex = selectedFilter.split("(*")[1].split(")")[0]
3414 if ex: 3419 if ex:
3415 fpath = fpath.with_suffix(ex) 3420 fpath = fpath.with_suffix(ex)
3416 if fpath.exists(): 3421 if fpath.exists():
3417 res = EricMessageBox.yesNo( 3422 res = EricMessageBox.yesNo(
3418 self, 3423 self,
3419 self.tr("Save File"), 3424 self.tr("Save File"),
3420 self.tr("<p>The file <b>{0}</b> already exists." 3425 self.tr(
3421 " Overwrite it?</p>").format(fpath), 3426 "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>"
3422 icon=EricMessageBox.Warning) 3427 ).format(fpath),
3428 icon=EricMessageBox.Warning,
3429 )
3423 if not res: 3430 if not res:
3424 return "" 3431 return ""
3425 3432
3426 return str(fpath) 3433 return str(fpath)
3427 3434
3428 return "" 3435 return ""
3429 3436
3430 def saveFileCopy(self, path=None): 3437 def saveFileCopy(self, path=None):
3431 """ 3438 """
3432 Public method to save a copy of the file. 3439 Public method to save a copy of the file.
3433 3440
3434 @param path directory to save the file in (string) 3441 @param path directory to save the file in (string)
3435 @return flag indicating success (boolean) 3442 @return flag indicating success (boolean)
3436 """ 3443 """
3437 fn = self.__getSaveFileName(path) 3444 fn = self.__getSaveFileName(path)
3438 if not fn: 3445 if not fn:
3439 return False 3446 return False
3440 3447
3441 res = self.writeFile(fn) 3448 res = self.writeFile(fn)
3442 if ( 3449 if res and self.project.isOpen() and self.project.startswithProjectPath(fn):
3443 res and
3444 self.project.isOpen() and
3445 self.project.startswithProjectPath(fn)
3446 ):
3447 # save to project, if a project is loaded 3450 # save to project, if a project is loaded
3448 self.project.appendFile(fn) 3451 self.project.appendFile(fn)
3449 3452
3450 return res 3453 return res
3451 3454
3452 def saveFile(self, saveas=False, path=None): 3455 def saveFile(self, saveas=False, path=None):
3453 """ 3456 """
3454 Public method to save the text to a file. 3457 Public method to save the text to a file.
3455 3458
3456 @param saveas flag indicating a 'save as' action (boolean) 3459 @param saveas flag indicating a 'save as' action (boolean)
3457 @param path directory to save the file in (string) 3460 @param path directory to save the file in (string)
3458 @return flag indicating success (boolean) 3461 @return flag indicating success (boolean)
3459 """ 3462 """
3460 if not saveas and not self.isModified(): 3463 if not saveas and not self.isModified():
3461 return False # do nothing if text wasn't changed 3464 return False # do nothing if text wasn't changed
3462 3465
3463 newName = None 3466 newName = None
3464 if saveas or self.fileName == "": 3467 if saveas or self.fileName == "":
3465 saveas = True 3468 saveas = True
3466 3469
3467 fn = self.__getSaveFileName(path) 3470 fn = self.__getSaveFileName(path)
3468 if not fn: 3471 if not fn:
3469 return False 3472 return False
3470 3473
3471 newName = fn 3474 newName = fn
3472 3475
3473 # save to project, if a project is loaded 3476 # save to project, if a project is loaded
3474 if ( 3477 if self.project.isOpen() and self.project.startswithProjectPath(fn):
3475 self.project.isOpen() and
3476 self.project.startswithProjectPath(fn)
3477 ):
3478 editorConfigEol = self.__getEditorConfig( 3478 editorConfigEol = self.__getEditorConfig(
3479 "EOLMode", nodefault=True, 3479 "EOLMode", nodefault=True, config=self.__loadEditorConfigObject(fn)
3480 config=self.__loadEditorConfigObject(fn)) 3480 )
3481 if editorConfigEol is not None: 3481 if editorConfigEol is not None:
3482 self.setEolMode(editorConfigEol) 3482 self.setEolMode(editorConfigEol)
3483 else: 3483 else:
3484 self.setEolModeByEolString(self.project.getEolString()) 3484 self.setEolModeByEolString(self.project.getEolString())
3485 self.convertEols(self.eolMode()) 3485 self.convertEols(self.eolMode())
3486 else: 3486 else:
3487 fn = self.fileName 3487 fn = self.fileName
3488 3488
3489 self.__loadEditorConfig(fn) 3489 self.__loadEditorConfig(fn)
3490 self.editorAboutToBeSaved.emit(self.fileName) 3490 self.editorAboutToBeSaved.emit(self.fileName)
3491 if self.writeFile(fn): 3491 if self.writeFile(fn):
3492 if saveas: 3492 if saveas:
3493 self.__clearBreakpoints(self.fileName) 3493 self.__clearBreakpoints(self.fileName)
3497 self.setWindowTitle(self.fileName) 3497 self.setWindowTitle(self.fileName)
3498 # get eric specific flags 3498 # get eric specific flags
3499 changedFlags = self.__processFlags() 3499 changedFlags = self.__processFlags()
3500 if not self.__lexerReset and "FileType" in changedFlags: 3500 if not self.__lexerReset and "FileType" in changedFlags:
3501 self.setLanguage(self.fileName) 3501 self.setLanguage(self.fileName)
3502 3502
3503 if saveas: 3503 if saveas:
3504 self.isResourcesFile = self.fileName.endswith(".qrc") 3504 self.isResourcesFile = self.fileName.endswith(".qrc")
3505 self.__initContextMenu() 3505 self.__initContextMenu()
3506 self.editorRenamed.emit(self.fileName) 3506 self.editorRenamed.emit(self.fileName)
3507 3507
3508 # save to project, if a project is loaded 3508 # save to project, if a project is loaded
3509 if ( 3509 if self.project.isOpen() and self.project.startswithProjectPath(fn):
3510 self.project.isOpen() and
3511 self.project.startswithProjectPath(fn)
3512 ):
3513 self.project.appendFile(fn) 3510 self.project.appendFile(fn)
3514 self.addedToProject() 3511 self.addedToProject()
3515 3512
3516 self.setLanguage(self.fileName) 3513 self.setLanguage(self.fileName)
3517 3514
3518 self.lastModified = pathlib.Path(fn).stat().st_mtime 3515 self.lastModified = pathlib.Path(fn).stat().st_mtime
3519 if newName is not None: 3516 if newName is not None:
3520 self.vm.addToRecentList(newName) 3517 self.vm.addToRecentList(newName)
3521 self.editorSaved.emit(self.fileName) 3518 self.editorSaved.emit(self.fileName)
3522 self.checkSyntax() 3519 self.checkSyntax()
3524 self.__resetOnlineChangeTraceInfo() 3521 self.__resetOnlineChangeTraceInfo()
3525 self.__checkEncoding() 3522 self.__checkEncoding()
3526 return True 3523 return True
3527 else: 3524 else:
3528 self.lastModified = ( 3525 self.lastModified = (
3529 pathlib.Path(fn).stat().st_mtime 3526 pathlib.Path(fn).stat().st_mtime if pathlib.Path(fn).exists() else 0
3530 if pathlib.Path(fn).exists() else
3531 0
3532 ) 3527 )
3533 return False 3528 return False
3534 3529
3535 def saveFileAs(self, path=None, toProject=False): 3530 def saveFileAs(self, path=None, toProject=False):
3536 """ 3531 """
3537 Public slot to save a file with a new name. 3532 Public slot to save a file with a new name.
3538 3533
3539 @param path directory to save the file in (string) 3534 @param path directory to save the file in (string)
3540 @param toProject flag indicating a save to project operation 3535 @param toProject flag indicating a save to project operation
3541 (boolean) 3536 (boolean)
3542 @return tuple of two values (boolean, string) giving a success 3537 @return tuple of two values (boolean, string) giving a success
3543 indicator and the name of the saved file 3538 indicator and the name of the saved file
3544 """ 3539 """
3545 return self.saveFile(True, path) 3540 return self.saveFile(True, path)
3546 3541
3547 def handleRenamed(self, fn): 3542 def handleRenamed(self, fn):
3548 """ 3543 """
3549 Public slot to handle the editorRenamed signal. 3544 Public slot to handle the editorRenamed signal.
3550 3545
3551 @param fn filename to be set for the editor (string). 3546 @param fn filename to be set for the editor (string).
3552 """ 3547 """
3553 self.__clearBreakpoints(fn) 3548 self.__clearBreakpoints(fn)
3554 3549
3555 self.__setFileName(fn) 3550 self.__setFileName(fn)
3556 self.setWindowTitle(self.fileName) 3551 self.setWindowTitle(self.fileName)
3557 3552
3558 self.__loadEditorConfig() 3553 self.__loadEditorConfig()
3559 3554
3560 if self.lexer_ is None: 3555 if self.lexer_ is None:
3561 self.setLanguage(self.fileName) 3556 self.setLanguage(self.fileName)
3562 3557
3563 self.lastModified = pathlib.Path(fn).stat().st_mtime 3558 self.lastModified = pathlib.Path(fn).stat().st_mtime
3564 self.vm.setEditorName(self, self.fileName) 3559 self.vm.setEditorName(self, self.fileName)
3565 self.__updateReadOnly(True) 3560 self.__updateReadOnly(True)
3566 3561
3567 def fileRenamed(self, fn): 3562 def fileRenamed(self, fn):
3568 """ 3563 """
3569 Public slot to handle the editorRenamed signal. 3564 Public slot to handle the editorRenamed signal.
3570 3565
3571 @param fn filename to be set for the editor (string). 3566 @param fn filename to be set for the editor (string).
3572 """ 3567 """
3573 self.handleRenamed(fn) 3568 self.handleRenamed(fn)
3574 if not self.inFileRenamed: 3569 if not self.inFileRenamed:
3575 self.inFileRenamed = True 3570 self.inFileRenamed = True
3576 self.editorRenamed.emit(self.fileName) 3571 self.editorRenamed.emit(self.fileName)
3577 self.inFileRenamed = False 3572 self.inFileRenamed = False
3578 3573
3579 ########################################################################### 3574 ###########################################################################
3580 ## Utility methods below 3575 ## Utility methods below
3581 ########################################################################### 3576 ###########################################################################
3582 3577
3583 def ensureVisible(self, line, expand=False): 3578 def ensureVisible(self, line, expand=False):
3584 """ 3579 """
3585 Public slot to ensure, that the specified line is visible. 3580 Public slot to ensure, that the specified line is visible.
3586 3581
3587 @param line line number to make visible 3582 @param line line number to make visible
3588 @type int 3583 @type int
3589 @param expand flag indicating to expand all folds 3584 @param expand flag indicating to expand all folds
3590 @type bool 3585 @type bool
3591 """ 3586 """
3592 self.ensureLineVisible(line - 1) 3587 self.ensureLineVisible(line - 1)
3593 if expand: 3588 if expand:
3594 self.SendScintilla(QsciScintilla.SCI_FOLDCHILDREN, line - 1, 3589 self.SendScintilla(
3595 QsciScintilla.SC_FOLDACTION_EXPAND) 3590 QsciScintilla.SCI_FOLDCHILDREN,
3596 3591 line - 1,
3592 QsciScintilla.SC_FOLDACTION_EXPAND,
3593 )
3594
3597 def ensureVisibleTop(self, line, expand=False): 3595 def ensureVisibleTop(self, line, expand=False):
3598 """ 3596 """
3599 Public slot to ensure, that the specified line is visible at the top 3597 Public slot to ensure, that the specified line is visible at the top
3600 of the editor. 3598 of the editor.
3601 3599
3602 @param line line number to make visible 3600 @param line line number to make visible
3603 @type int 3601 @type int
3604 @param expand flag indicating to expand all folds 3602 @param expand flag indicating to expand all folds
3605 @type bool 3603 @type bool
3606 """ 3604 """
3607 self.ensureVisible(line) 3605 self.ensureVisible(line)
3608 self.setFirstVisibleLine(line - 1) 3606 self.setFirstVisibleLine(line - 1)
3609 self.ensureCursorVisible() 3607 self.ensureCursorVisible()
3610 if expand: 3608 if expand:
3611 self.SendScintilla(QsciScintilla.SCI_FOLDCHILDREN, line - 1, 3609 self.SendScintilla(
3612 QsciScintilla.SC_FOLDACTION_EXPAND) 3610 QsciScintilla.SCI_FOLDCHILDREN,
3613 3611 line - 1,
3612 QsciScintilla.SC_FOLDACTION_EXPAND,
3613 )
3614
3614 def __marginClicked(self, margin, line, modifiers): 3615 def __marginClicked(self, margin, line, modifiers):
3615 """ 3616 """
3616 Private slot to handle the marginClicked signal. 3617 Private slot to handle the marginClicked signal.
3617 3618
3618 @param margin id of the clicked margin (integer) 3619 @param margin id of the clicked margin (integer)
3619 @param line line number of the click (integer) 3620 @param line line number of the click (integer)
3620 @param modifiers keyboard modifiers (Qt.KeyboardModifiers) 3621 @param modifiers keyboard modifiers (Qt.KeyboardModifiers)
3621 """ 3622 """
3622 if margin == self.__bmMargin: 3623 if margin == self.__bmMargin:
3626 elif margin == self.__indicMargin: 3627 elif margin == self.__indicMargin:
3627 if self.markersAtLine(line) & (1 << self.syntaxerror): 3628 if self.markersAtLine(line) & (1 << self.syntaxerror):
3628 self.__showSyntaxError(line) 3629 self.__showSyntaxError(line)
3629 elif self.markersAtLine(line) & (1 << self.warning): 3630 elif self.markersAtLine(line) & (1 << self.warning):
3630 self.__showWarning(line) 3631 self.__showWarning(line)
3631 3632
3632 def handleMonospacedEnable(self): 3633 def handleMonospacedEnable(self):
3633 """ 3634 """
3634 Public slot to handle the Use Monospaced Font context menu entry. 3635 Public slot to handle the Use Monospaced Font context menu entry.
3635 """ 3636 """
3636 if self.menuActs["MonospacedFont"].isChecked(): 3637 if self.menuActs["MonospacedFont"].isChecked():
3637 if not self.lexer_: 3638 if not self.lexer_:
3638 self.setMonospaced(True) 3639 self.setMonospaced(True)
3639 else: 3640 else:
3640 if self.lexer_: 3641 if self.lexer_:
3641 self.lexer_.readSettings( 3642 self.lexer_.readSettings(Preferences.getSettings(), "Scintilla")
3642 Preferences.getSettings(), "Scintilla")
3643 if self.lexer_.hasSubstyles(): 3643 if self.lexer_.hasSubstyles():
3644 self.lexer_.readSubstyles(self) 3644 self.lexer_.readSubstyles(self)
3645 self.lexer_.initProperties() 3645 self.lexer_.initProperties()
3646 self.setMonospaced(False) 3646 self.setMonospaced(False)
3647 self.__setMarginsDisplay() 3647 self.__setMarginsDisplay()
3648 3648
3649 def getWordBoundaries(self, line, index, useWordChars=True): 3649 def getWordBoundaries(self, line, index, useWordChars=True):
3650 """ 3650 """
3651 Public method to get the word boundaries at a position. 3651 Public method to get the word boundaries at a position.
3652 3652
3653 @param line number of line to look at (int) 3653 @param line number of line to look at (int)
3654 @param index position to look at (int) 3654 @param index position to look at (int)
3655 @param useWordChars flag indicating to use the wordCharacters 3655 @param useWordChars flag indicating to use the wordCharacters
3656 method (boolean) 3656 method (boolean)
3657 @return tuple with start and end indexes of the word at the position 3657 @return tuple with start and end indexes of the word at the position
3659 """ 3659 """
3660 wc = self.wordCharacters() 3660 wc = self.wordCharacters()
3661 if wc is None or not useWordChars: 3661 if wc is None or not useWordChars:
3662 pattern = r"\b[\w_]+\b" 3662 pattern = r"\b[\w_]+\b"
3663 else: 3663 else:
3664 wc = re.sub(r'\w', "", wc) 3664 wc = re.sub(r"\w", "", wc)
3665 pattern = r"\b[\w{0}]+\b".format(re.escape(wc)) 3665 pattern = r"\b[\w{0}]+\b".format(re.escape(wc))
3666 rx = ( 3666 rx = (
3667 re.compile(pattern) 3667 re.compile(pattern)
3668 if self.caseSensitive() else 3668 if self.caseSensitive()
3669 re.compile(pattern, re.IGNORECASE) 3669 else re.compile(pattern, re.IGNORECASE)
3670 ) 3670 )
3671 3671
3672 text = self.text(line) 3672 text = self.text(line)
3673 for match in rx.finditer(text): 3673 for match in rx.finditer(text):
3674 start, end = match.span() 3674 start, end = match.span()
3675 if start <= index <= end: 3675 if start <= index <= end:
3676 return (start, end) 3676 return (start, end)
3677 3677
3678 return (index, index) 3678 return (index, index)
3679 3679
3680 def getWord(self, line, index, direction=0, useWordChars=True): 3680 def getWord(self, line, index, direction=0, useWordChars=True):
3681 """ 3681 """
3682 Public method to get the word at a position. 3682 Public method to get the word at a position.
3683 3683
3684 @param line number of line to look at (int) 3684 @param line number of line to look at (int)
3685 @param index position to look at (int) 3685 @param index position to look at (int)
3686 @param direction direction to look in (0 = whole word, 1 = left, 3686 @param direction direction to look in (0 = whole word, 1 = left,
3687 2 = right) 3687 2 = right)
3688 @param useWordChars flag indicating to use the wordCharacters 3688 @param useWordChars flag indicating to use the wordCharacters
3696 start = index 3696 start = index
3697 if end > start: 3697 if end > start:
3698 text = self.text(line) 3698 text = self.text(line)
3699 word = text[start:end] 3699 word = text[start:end]
3700 else: 3700 else:
3701 word = '' 3701 word = ""
3702 return word 3702 return word
3703 3703
3704 def getWordLeft(self, line, index): 3704 def getWordLeft(self, line, index):
3705 """ 3705 """
3706 Public method to get the word to the left of a position. 3706 Public method to get the word to the left of a position.
3707 3707
3708 @param line number of line to look at (int) 3708 @param line number of line to look at (int)
3709 @param index position to look at (int) 3709 @param index position to look at (int)
3710 @return the word to the left of that position (string) 3710 @return the word to the left of that position (string)
3711 """ 3711 """
3712 return self.getWord(line, index, 1) 3712 return self.getWord(line, index, 1)
3713 3713
3714 def getWordRight(self, line, index): 3714 def getWordRight(self, line, index):
3715 """ 3715 """
3716 Public method to get the word to the right of a position. 3716 Public method to get the word to the right of a position.
3717 3717
3718 @param line number of line to look at (int) 3718 @param line number of line to look at (int)
3719 @param index position to look at (int) 3719 @param index position to look at (int)
3720 @return the word to the right of that position (string) 3720 @return the word to the right of that position (string)
3721 """ 3721 """
3722 return self.getWord(line, index, 2) 3722 return self.getWord(line, index, 2)
3723 3723
3724 def getCurrentWord(self): 3724 def getCurrentWord(self):
3725 """ 3725 """
3726 Public method to get the word at the current position. 3726 Public method to get the word at the current position.
3727 3727
3728 @return the word at that current position (string) 3728 @return the word at that current position (string)
3729 """ 3729 """
3730 line, index = self.getCursorPosition() 3730 line, index = self.getCursorPosition()
3731 return self.getWord(line, index) 3731 return self.getWord(line, index)
3732 3732
3733 def getCurrentWordBoundaries(self): 3733 def getCurrentWordBoundaries(self):
3734 """ 3734 """
3735 Public method to get the word boundaries at the current position. 3735 Public method to get the word boundaries at the current position.
3736 3736
3737 @return tuple with start and end indexes of the current word 3737 @return tuple with start and end indexes of the current word
3738 (integer, integer) 3738 (integer, integer)
3739 """ 3739 """
3740 line, index = self.getCursorPosition() 3740 line, index = self.getCursorPosition()
3741 return self.getWordBoundaries(line, index) 3741 return self.getWordBoundaries(line, index)
3742 3742
3743 def selectWord(self, line, index): 3743 def selectWord(self, line, index):
3744 """ 3744 """
3745 Public method to select the word at a position. 3745 Public method to select the word at a position.
3746 3746
3747 @param line number of line to look at (int) 3747 @param line number of line to look at (int)
3748 @param index position to look at (int) 3748 @param index position to look at (int)
3749 """ 3749 """
3750 start, end = self.getWordBoundaries(line, index) 3750 start, end = self.getWordBoundaries(line, index)
3751 self.setSelection(line, start, line, end) 3751 self.setSelection(line, start, line, end)
3752 3752
3753 def selectCurrentWord(self): 3753 def selectCurrentWord(self):
3754 """ 3754 """
3755 Public method to select the current word. 3755 Public method to select the current word.
3756 """ 3756 """
3757 line, index = self.getCursorPosition() 3757 line, index = self.getCursorPosition()
3758 self.selectWord(line, index) 3758 self.selectWord(line, index)
3759 3759
3760 def __getCharacter(self, pos): 3760 def __getCharacter(self, pos):
3761 """ 3761 """
3762 Private method to get the character to the left of the current position 3762 Private method to get the character to the left of the current position
3763 in the current line. 3763 in the current line.
3764 3764
3765 @param pos position to get character at (integer) 3765 @param pos position to get character at (integer)
3766 @return requested character or "", if there are no more (string) and 3766 @return requested character or "", if there are no more (string) and
3767 the next position (i.e. pos - 1) 3767 the next position (i.e. pos - 1)
3768 """ 3768 """
3769 if pos <= 0: 3769 if pos <= 0:
3770 return "", pos 3770 return "", pos
3771 3771
3772 pos = self.positionBefore(pos) 3772 pos = self.positionBefore(pos)
3773 ch = self.charAt(pos) 3773 ch = self.charAt(pos)
3774 3774
3775 # Don't go past the end of the previous line 3775 # Don't go past the end of the previous line
3776 if ch in ('\n', '\r'): 3776 if ch in ("\n", "\r"):
3777 return "", pos 3777 return "", pos
3778 3778
3779 return ch, pos 3779 return ch, pos
3780 3780
3781 def getSearchText(self, selectionOnly=False): 3781 def getSearchText(self, selectionOnly=False):
3782 """ 3782 """
3783 Public method to determine the selection or the current word for the 3783 Public method to determine the selection or the current word for the
3784 next search operation. 3784 next search operation.
3785 3785
3786 @param selectionOnly flag indicating that only selected text should be 3786 @param selectionOnly flag indicating that only selected text should be
3787 returned (boolean) 3787 returned (boolean)
3788 @return selection or current word (string) 3788 @return selection or current word (string)
3789 """ 3789 """
3790 if self.hasSelectedText(): 3790 if self.hasSelectedText():
3791 text = self.selectedText() 3791 text = self.selectedText()
3792 if '\r' in text or '\n' in text: 3792 if "\r" in text or "\n" in text:
3793 # the selection contains at least a newline, it is 3793 # the selection contains at least a newline, it is
3794 # unlikely to be the expression to search for 3794 # unlikely to be the expression to search for
3795 return '' 3795 return ""
3796 3796
3797 return text 3797 return text
3798 3798
3799 if not selectionOnly: 3799 if not selectionOnly:
3800 # no selected text, determine the word at the current position 3800 # no selected text, determine the word at the current position
3801 return self.getCurrentWord() 3801 return self.getCurrentWord()
3802 3802
3803 return '' 3803 return ""
3804 3804
3805 def setSearchIndicator(self, startPos, indicLength): 3805 def setSearchIndicator(self, startPos, indicLength):
3806 """ 3806 """
3807 Public method to set a search indicator for the given range. 3807 Public method to set a search indicator for the given range.
3808 3808
3809 @param startPos start position of the indicator (integer) 3809 @param startPos start position of the indicator (integer)
3810 @param indicLength length of the indicator (integer) 3810 @param indicLength length of the indicator (integer)
3811 """ 3811 """
3812 self.setIndicatorRange(self.searchIndicator, startPos, indicLength) 3812 self.setIndicatorRange(self.searchIndicator, startPos, indicLength)
3813 line = self.lineIndexFromPosition(startPos)[0] 3813 line = self.lineIndexFromPosition(startPos)[0]
3814 if line not in self.__searchIndicatorLines: 3814 if line not in self.__searchIndicatorLines:
3815 self.__searchIndicatorLines.append(line) 3815 self.__searchIndicatorLines.append(line)
3816 3816
3817 def clearSearchIndicators(self): 3817 def clearSearchIndicators(self):
3818 """ 3818 """
3819 Public method to clear all search indicators. 3819 Public method to clear all search indicators.
3820 """ 3820 """
3821 self.clearAllIndicators(self.searchIndicator) 3821 self.clearAllIndicators(self.searchIndicator)
3822 self.__markedText = "" 3822 self.__markedText = ""
3823 self.__searchIndicatorLines = [] 3823 self.__searchIndicatorLines = []
3824 self.__markerMap.update() 3824 self.__markerMap.update()
3825 3825
3826 def __markOccurrences(self): 3826 def __markOccurrences(self):
3827 """ 3827 """
3828 Private method to mark all occurrences of the current word. 3828 Private method to mark all occurrences of the current word.
3829 """ 3829 """
3830 word = self.getCurrentWord() 3830 word = self.getCurrentWord()
3831 if not word: 3831 if not word:
3832 self.clearSearchIndicators() 3832 self.clearSearchIndicators()
3833 return 3833 return
3834 3834
3835 if self.__markedText == word: 3835 if self.__markedText == word:
3836 return 3836 return
3837 3837
3838 self.clearSearchIndicators() 3838 self.clearSearchIndicators()
3839 ok = self.findFirstTarget(word, False, self.caseSensitive(), True, 3839 ok = self.findFirstTarget(word, False, self.caseSensitive(), True, 0, 0)
3840 0, 0)
3841 while ok: 3840 while ok:
3842 tgtPos, tgtLen = self.getFoundTarget() 3841 tgtPos, tgtLen = self.getFoundTarget()
3843 self.setSearchIndicator(tgtPos, tgtLen) 3842 self.setSearchIndicator(tgtPos, tgtLen)
3844 ok = self.findNextTarget() 3843 ok = self.findNextTarget()
3845 self.__markedText = word 3844 self.__markedText = word
3846 self.__markerMap.update() 3845 self.__markerMap.update()
3847 3846
3848 def getSearchIndicatorLines(self): 3847 def getSearchIndicatorLines(self):
3849 """ 3848 """
3850 Public method to get the lines containing a search indicator. 3849 Public method to get the lines containing a search indicator.
3851 3850
3852 @return list of lines containing a search indicator (list of integer) 3851 @return list of lines containing a search indicator (list of integer)
3853 """ 3852 """
3854 return self.__searchIndicatorLines[:] 3853 return self.__searchIndicatorLines[:]
3855 3854
3856 def updateMarkerMap(self): 3855 def updateMarkerMap(self):
3857 """ 3856 """
3858 Public method to initiate an update of the marker map. 3857 Public method to initiate an update of the marker map.
3859 """ 3858 """
3860 self.__markerMap.update() 3859 self.__markerMap.update()
3861 3860
3862 ########################################################################### 3861 ###########################################################################
3863 ## Highlighting marker handling methods below 3862 ## Highlighting marker handling methods below
3864 ########################################################################### 3863 ###########################################################################
3865 3864
3866 def setHighlight(self, startLine, startIndex, endLine, endIndex): 3865 def setHighlight(self, startLine, startIndex, endLine, endIndex):
3867 """ 3866 """
3868 Public method to set a text highlight. 3867 Public method to set a text highlight.
3869 3868
3870 @param startLine line of the highlight start 3869 @param startLine line of the highlight start
3871 @type int 3870 @type int
3872 @param startIndex index of the highlight start 3871 @param startIndex index of the highlight start
3873 @type int 3872 @type int
3874 @param endLine line of the highlight end 3873 @param endLine line of the highlight end
3875 @type int 3874 @type int
3876 @param endIndex index of the highlight end 3875 @param endIndex index of the highlight end
3877 @type int 3876 @type int
3878 """ 3877 """
3879 self.setIndicator(self.highlightIndicator, startLine, startIndex, 3878 self.setIndicator(
3880 endLine, endIndex) 3879 self.highlightIndicator, startLine, startIndex, endLine, endIndex
3881 3880 )
3881
3882 def clearAllHighlights(self): 3882 def clearAllHighlights(self):
3883 """ 3883 """
3884 Public method to clear all highlights. 3884 Public method to clear all highlights.
3885 """ 3885 """
3886 self.clearAllIndicators(self.highlightIndicator) 3886 self.clearAllIndicators(self.highlightIndicator)
3887 3887
3888 def clearHighlight(self, startLine, startIndex, endLine, endIndex): 3888 def clearHighlight(self, startLine, startIndex, endLine, endIndex):
3889 """ 3889 """
3890 Public method to clear a text highlight. 3890 Public method to clear a text highlight.
3891 3891
3892 @param startLine line of the highlight start 3892 @param startLine line of the highlight start
3893 @type int 3893 @type int
3894 @param startIndex index of the highlight start 3894 @param startIndex index of the highlight start
3895 @type int 3895 @type int
3896 @param endLine line of the highlight end 3896 @param endLine line of the highlight end
3897 @type int 3897 @type int
3898 @param endIndex index of the highlight end 3898 @param endIndex index of the highlight end
3899 @type int 3899 @type int
3900 """ 3900 """
3901 self.clearIndicator(self.highlightIndicator, startLine, startIndex, 3901 self.clearIndicator(
3902 endLine, endIndex) 3902 self.highlightIndicator, startLine, startIndex, endLine, endIndex
3903 3903 )
3904
3904 ########################################################################### 3905 ###########################################################################
3905 ## Comment handling methods below 3906 ## Comment handling methods below
3906 ########################################################################### 3907 ###########################################################################
3907 3908
3908 def __isCommentedLine(self, line, commentStr): 3909 def __isCommentedLine(self, line, commentStr):
3909 """ 3910 """
3910 Private method to check, if the given line is a comment line as 3911 Private method to check, if the given line is a comment line as
3911 produced by the configured comment rules. 3912 produced by the configured comment rules.
3912 3913
3913 @param line text of the line to check (string) 3914 @param line text of the line to check (string)
3914 @param commentStr comment string to check against (string) 3915 @param commentStr comment string to check against (string)
3915 @return flag indicating a commented line (boolean) 3916 @return flag indicating a commented line (boolean)
3916 """ 3917 """
3917 if Preferences.getEditor("CommentColumn0"): 3918 if Preferences.getEditor("CommentColumn0"):
3918 return line.startswith(commentStr) 3919 return line.startswith(commentStr)
3919 else: 3920 else:
3920 return line.strip().startswith(commentStr) 3921 return line.strip().startswith(commentStr)
3921 3922
3922 def toggleCommentBlock(self): 3923 def toggleCommentBlock(self):
3923 """ 3924 """
3924 Public slot to toggle the comment of a block. 3925 Public slot to toggle the comment of a block.
3925 3926
3926 If the line of the cursor or the selection is not commented, it will 3927 If the line of the cursor or the selection is not commented, it will
3927 be commented. If it is commented, the comment block will be removed. 3928 be commented. If it is commented, the comment block will be removed.
3928 The later works independent of the current selection. 3929 The later works independent of the current selection.
3929 """ 3930 """
3930 if self.lexer_ is None or not self.lexer_.canBlockComment(): 3931 if self.lexer_ is None or not self.lexer_.canBlockComment():
3931 return 3932 return
3932 3933
3933 commentStr = self.lexer_.commentStr() 3934 commentStr = self.lexer_.commentStr()
3934 line, index = self.getCursorPosition() 3935 line, index = self.getCursorPosition()
3935 3936
3936 # check if line starts with our comment string (i.e. was commented 3937 # check if line starts with our comment string (i.e. was commented
3937 # by our comment...() slots 3938 # by our comment...() slots
3938 if ( 3939 if self.hasSelectedText() and self.__isCommentedLine(
3939 self.hasSelectedText() and 3940 self.text(self.getSelection()[0]), commentStr
3940 self.__isCommentedLine(self.text(self.getSelection()[0]),
3941 commentStr)
3942 ): 3941 ):
3943 self.uncommentLineOrSelection() 3942 self.uncommentLineOrSelection()
3944 elif not self.__isCommentedLine(self.text(line), commentStr): 3943 elif not self.__isCommentedLine(self.text(line), commentStr):
3945 # it doesn't, so comment the line or selection 3944 # it doesn't, so comment the line or selection
3946 self.commentLineOrSelection() 3945 self.commentLineOrSelection()
3947 else: 3946 else:
3948 # determine the start of the comment block 3947 # determine the start of the comment block
3949 begline = line 3948 begline = line
3950 while ( 3949 while begline > 0 and self.__isCommentedLine(
3951 begline > 0 and 3950 self.text(begline - 1), commentStr
3952 self.__isCommentedLine(self.text(begline - 1), commentStr)
3953 ): 3951 ):
3954 begline -= 1 3952 begline -= 1
3955 # determine the end of the comment block 3953 # determine the end of the comment block
3956 endline = line 3954 endline = line
3957 lines = self.lines() 3955 lines = self.lines()
3958 while ( 3956 while endline < lines and self.__isCommentedLine(
3959 endline < lines and 3957 self.text(endline + 1), commentStr
3960 self.__isCommentedLine(self.text(endline + 1), commentStr)
3961 ): 3958 ):
3962 endline += 1 3959 endline += 1
3963 3960
3964 self.setSelection(begline, 0, endline, self.lineLength(endline)) 3961 self.setSelection(begline, 0, endline, self.lineLength(endline))
3965 self.uncommentLineOrSelection() 3962 self.uncommentLineOrSelection()
3966 3963
3967 # reset the cursor 3964 # reset the cursor
3968 self.setCursorPosition(line, index - len(commentStr)) 3965 self.setCursorPosition(line, index - len(commentStr))
3969 3966
3970 def commentLine(self): 3967 def commentLine(self):
3971 """ 3968 """
3972 Public slot to comment the current line. 3969 Public slot to comment the current line.
3973 """ 3970 """
3974 if self.lexer_ is None or not self.lexer_.canBlockComment(): 3971 if self.lexer_ is None or not self.lexer_.canBlockComment():
3975 return 3972 return
3976 3973
3977 line, index = self.getCursorPosition() 3974 line, index = self.getCursorPosition()
3978 self.beginUndoAction() 3975 self.beginUndoAction()
3979 if Preferences.getEditor("CommentColumn0"): 3976 if Preferences.getEditor("CommentColumn0"):
3980 self.insertAt(self.lexer_.commentStr(), line, 0) 3977 self.insertAt(self.lexer_.commentStr(), line, 0)
3981 else: 3978 else:
3982 lineText = self.text(line) 3979 lineText = self.text(line)
3983 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) 3980 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
3984 self.insertAt(self.lexer_.commentStr(), line, pos) 3981 self.insertAt(self.lexer_.commentStr(), line, pos)
3985 self.endUndoAction() 3982 self.endUndoAction()
3986 3983
3987 def uncommentLine(self): 3984 def uncommentLine(self):
3988 """ 3985 """
3989 Public slot to uncomment the current line. 3986 Public slot to uncomment the current line.
3990 """ 3987 """
3991 if self.lexer_ is None or not self.lexer_.canBlockComment(): 3988 if self.lexer_ is None or not self.lexer_.canBlockComment():
3992 return 3989 return
3993 3990
3994 commentStr = self.lexer_.commentStr() 3991 commentStr = self.lexer_.commentStr()
3995 line, index = self.getCursorPosition() 3992 line, index = self.getCursorPosition()
3996 3993
3997 # check if line starts with our comment string (i.e. was commented 3994 # check if line starts with our comment string (i.e. was commented
3998 # by our comment...() slots 3995 # by our comment...() slots
3999 if not self.__isCommentedLine(self.text(line), commentStr): 3996 if not self.__isCommentedLine(self.text(line), commentStr):
4000 return 3997 return
4001 3998
4002 # now remove the comment string 3999 # now remove the comment string
4003 self.beginUndoAction() 4000 self.beginUndoAction()
4004 if Preferences.getEditor("CommentColumn0"): 4001 if Preferences.getEditor("CommentColumn0"):
4005 self.setSelection(line, 0, line, len(commentStr)) 4002 self.setSelection(line, 0, line, len(commentStr))
4006 else: 4003 else:
4007 lineText = self.text(line) 4004 lineText = self.text(line)
4008 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) 4005 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
4009 self.setSelection(line, pos, line, pos + len(commentStr)) 4006 self.setSelection(line, pos, line, pos + len(commentStr))
4010 self.removeSelectedText() 4007 self.removeSelectedText()
4011 self.endUndoAction() 4008 self.endUndoAction()
4012 4009
4013 def commentSelection(self): 4010 def commentSelection(self):
4014 """ 4011 """
4015 Public slot to comment the current selection. 4012 Public slot to comment the current selection.
4016 """ 4013 """
4017 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4014 if self.lexer_ is None or not self.lexer_.canBlockComment():
4018 return 4015 return
4019 4016
4020 if not self.hasSelectedText(): 4017 if not self.hasSelectedText():
4021 return 4018 return
4022 4019
4023 commentStr = self.lexer_.commentStr() 4020 commentStr = self.lexer_.commentStr()
4024 4021
4025 # get the selection boundaries 4022 # get the selection boundaries
4026 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4023 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4027 endLine = lineTo if indexTo else lineTo - 1 4024 endLine = lineTo if indexTo else lineTo - 1
4028 4025
4029 self.beginUndoAction() 4026 self.beginUndoAction()
4030 # iterate over the lines 4027 # iterate over the lines
4031 for line in range(lineFrom, endLine + 1): 4028 for line in range(lineFrom, endLine + 1):
4032 if Preferences.getEditor("CommentColumn0"): 4029 if Preferences.getEditor("CommentColumn0"):
4033 self.insertAt(commentStr, line, 0) 4030 self.insertAt(commentStr, line, 0)
4034 else: 4031 else:
4035 lineText = self.text(line) 4032 lineText = self.text(line)
4036 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) 4033 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
4037 self.insertAt(commentStr, line, pos) 4034 self.insertAt(commentStr, line, pos)
4038 4035
4039 # change the selection accordingly 4036 # change the selection accordingly
4040 self.setSelection(lineFrom, 0, endLine + 1, 0) 4037 self.setSelection(lineFrom, 0, endLine + 1, 0)
4041 self.endUndoAction() 4038 self.endUndoAction()
4042 4039
4043 def uncommentSelection(self): 4040 def uncommentSelection(self):
4044 """ 4041 """
4045 Public slot to uncomment the current selection. 4042 Public slot to uncomment the current selection.
4046 """ 4043 """
4047 if self.lexer_ is None or not self.lexer_.canBlockComment(): 4044 if self.lexer_ is None or not self.lexer_.canBlockComment():
4048 return 4045 return
4049 4046
4050 if not self.hasSelectedText(): 4047 if not self.hasSelectedText():
4051 return 4048 return
4052 4049
4053 commentStr = self.lexer_.commentStr() 4050 commentStr = self.lexer_.commentStr()
4054 4051
4055 # get the selection boundaries 4052 # get the selection boundaries
4056 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4053 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4057 endLine = lineTo if indexTo else lineTo - 1 4054 endLine = lineTo if indexTo else lineTo - 1
4058 4055
4059 self.beginUndoAction() 4056 self.beginUndoAction()
4060 # iterate over the lines 4057 # iterate over the lines
4061 for line in range(lineFrom, endLine + 1): 4058 for line in range(lineFrom, endLine + 1):
4062 # check if line starts with our comment string (i.e. was commented 4059 # check if line starts with our comment string (i.e. was commented
4063 # by our comment...() slots 4060 # by our comment...() slots
4064 if not self.__isCommentedLine(self.text(line), commentStr): 4061 if not self.__isCommentedLine(self.text(line), commentStr):
4065 continue 4062 continue
4066 4063
4067 if Preferences.getEditor("CommentColumn0"): 4064 if Preferences.getEditor("CommentColumn0"):
4068 self.setSelection(line, 0, line, len(commentStr)) 4065 self.setSelection(line, 0, line, len(commentStr))
4069 else: 4066 else:
4070 lineText = self.text(line) 4067 lineText = self.text(line)
4071 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) 4068 pos = len(lineText.replace(lineText.lstrip(" \t"), ""))
4072 self.setSelection(line, pos, line, pos + len(commentStr)) 4069 self.setSelection(line, pos, line, pos + len(commentStr))
4073 self.removeSelectedText() 4070 self.removeSelectedText()
4074 4071
4075 # adjust selection start 4072 # adjust selection start
4076 if line == lineFrom: 4073 if line == lineFrom:
4077 indexFrom -= len(commentStr) 4074 indexFrom -= len(commentStr)
4078 if indexFrom < 0: 4075 if indexFrom < 0:
4079 indexFrom = 0 4076 indexFrom = 0
4080 4077
4081 # adjust selection end 4078 # adjust selection end
4082 if line == lineTo: 4079 if line == lineTo:
4083 indexTo -= len(commentStr) 4080 indexTo -= len(commentStr)
4084 if indexTo < 0: 4081 if indexTo < 0:
4085 indexTo = 0 4082 indexTo = 0
4086 4083
4087 # change the selection accordingly 4084 # change the selection accordingly
4088 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) 4085 self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
4089 self.endUndoAction() 4086 self.endUndoAction()
4090 4087
4091 def commentLineOrSelection(self): 4088 def commentLineOrSelection(self):
4092 """ 4089 """
4093 Public slot to comment the current line or current selection. 4090 Public slot to comment the current line or current selection.
4094 """ 4091 """
4095 if self.hasSelectedText(): 4092 if self.hasSelectedText():
4110 """ 4107 """
4111 Public slot to stream comment the current line. 4108 Public slot to stream comment the current line.
4112 """ 4109 """
4113 if self.lexer_ is None or not self.lexer_.canStreamComment(): 4110 if self.lexer_ is None or not self.lexer_.canStreamComment():
4114 return 4111 return
4115 4112
4116 commentStr = self.lexer_.streamCommentStr() 4113 commentStr = self.lexer_.streamCommentStr()
4117 line, index = self.getCursorPosition() 4114 line, index = self.getCursorPosition()
4118 4115
4119 self.beginUndoAction() 4116 self.beginUndoAction()
4120 self.insertAt(commentStr['end'], line, self.lineLength(line)) 4117 self.insertAt(commentStr["end"], line, self.lineLength(line))
4121 self.insertAt(commentStr['start'], line, 0) 4118 self.insertAt(commentStr["start"], line, 0)
4122 self.endUndoAction() 4119 self.endUndoAction()
4123 4120
4124 def streamCommentSelection(self): 4121 def streamCommentSelection(self):
4125 """ 4122 """
4126 Public slot to comment the current selection. 4123 Public slot to comment the current selection.
4127 """ 4124 """
4128 if self.lexer_ is None or not self.lexer_.canStreamComment(): 4125 if self.lexer_ is None or not self.lexer_.canStreamComment():
4129 return 4126 return
4130 4127
4131 if not self.hasSelectedText(): 4128 if not self.hasSelectedText():
4132 return 4129 return
4133 4130
4134 commentStr = self.lexer_.streamCommentStr() 4131 commentStr = self.lexer_.streamCommentStr()
4135 4132
4136 # get the selection boundaries 4133 # get the selection boundaries
4137 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4134 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4138 if indexTo == 0: 4135 if indexTo == 0:
4139 endLine = lineTo - 1 4136 endLine = lineTo - 1
4140 endIndex = self.lineLength(endLine) 4137 endIndex = self.lineLength(endLine)
4141 else: 4138 else:
4142 endLine = lineTo 4139 endLine = lineTo
4143 endIndex = indexTo 4140 endIndex = indexTo
4144 4141
4145 self.beginUndoAction() 4142 self.beginUndoAction()
4146 self.insertAt(commentStr['end'], endLine, endIndex) 4143 self.insertAt(commentStr["end"], endLine, endIndex)
4147 self.insertAt(commentStr['start'], lineFrom, indexFrom) 4144 self.insertAt(commentStr["start"], lineFrom, indexFrom)
4148 4145
4149 # change the selection accordingly 4146 # change the selection accordingly
4150 if indexTo > 0: 4147 if indexTo > 0:
4151 indexTo += len(commentStr['end']) 4148 indexTo += len(commentStr["end"])
4152 if lineFrom == endLine: 4149 if lineFrom == endLine:
4153 indexTo += len(commentStr['start']) 4150 indexTo += len(commentStr["start"])
4154 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) 4151 self.setSelection(lineFrom, indexFrom, lineTo, indexTo)
4155 self.endUndoAction() 4152 self.endUndoAction()
4156 4153
4157 def streamCommentLineOrSelection(self): 4154 def streamCommentLineOrSelection(self):
4158 """ 4155 """
4159 Public slot to stream comment the current line or current selection. 4156 Public slot to stream comment the current line or current selection.
4160 """ 4157 """
4161 if self.hasSelectedText(): 4158 if self.hasSelectedText():
4162 self.streamCommentSelection() 4159 self.streamCommentSelection()
4163 else: 4160 else:
4164 self.streamCommentLine() 4161 self.streamCommentLine()
4165 4162
4166 def boxCommentLine(self): 4163 def boxCommentLine(self):
4167 """ 4164 """
4168 Public slot to box comment the current line. 4165 Public slot to box comment the current line.
4169 """ 4166 """
4170 if self.lexer_ is None or not self.lexer_.canBoxComment(): 4167 if self.lexer_ is None or not self.lexer_.canBoxComment():
4171 return 4168 return
4172 4169
4173 commentStr = self.lexer_.boxCommentStr() 4170 commentStr = self.lexer_.boxCommentStr()
4174 line, index = self.getCursorPosition() 4171 line, index = self.getCursorPosition()
4175 4172
4176 eol = self.getLineSeparator() 4173 eol = self.getLineSeparator()
4177 self.beginUndoAction() 4174 self.beginUndoAction()
4178 self.insertAt(eol, line, self.lineLength(line)) 4175 self.insertAt(eol, line, self.lineLength(line))
4179 self.insertAt(commentStr['end'], line + 1, 0) 4176 self.insertAt(commentStr["end"], line + 1, 0)
4180 self.insertAt(commentStr['middle'], line, 0) 4177 self.insertAt(commentStr["middle"], line, 0)
4181 self.insertAt(eol, line, 0) 4178 self.insertAt(eol, line, 0)
4182 self.insertAt(commentStr['start'], line, 0) 4179 self.insertAt(commentStr["start"], line, 0)
4183 self.endUndoAction() 4180 self.endUndoAction()
4184 4181
4185 def boxCommentSelection(self): 4182 def boxCommentSelection(self):
4186 """ 4183 """
4187 Public slot to box comment the current selection. 4184 Public slot to box comment the current selection.
4188 """ 4185 """
4189 if self.lexer_ is None or not self.lexer_.canBoxComment(): 4186 if self.lexer_ is None or not self.lexer_.canBoxComment():
4190 return 4187 return
4191 4188
4192 if not self.hasSelectedText(): 4189 if not self.hasSelectedText():
4193 return 4190 return
4194 4191
4195 commentStr = self.lexer_.boxCommentStr() 4192 commentStr = self.lexer_.boxCommentStr()
4196 4193
4197 # get the selection boundaries 4194 # get the selection boundaries
4198 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4195 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4199 endLine = lineTo if indexTo else lineTo - 1 4196 endLine = lineTo if indexTo else lineTo - 1
4200 4197
4201 self.beginUndoAction() 4198 self.beginUndoAction()
4202 # iterate over the lines 4199 # iterate over the lines
4203 for line in range(lineFrom, endLine + 1): 4200 for line in range(lineFrom, endLine + 1):
4204 self.insertAt(commentStr['middle'], line, 0) 4201 self.insertAt(commentStr["middle"], line, 0)
4205 4202
4206 # now do the comments before and after the selection 4203 # now do the comments before and after the selection
4207 eol = self.getLineSeparator() 4204 eol = self.getLineSeparator()
4208 self.insertAt(eol, endLine, self.lineLength(endLine)) 4205 self.insertAt(eol, endLine, self.lineLength(endLine))
4209 self.insertAt(commentStr['end'], endLine + 1, 0) 4206 self.insertAt(commentStr["end"], endLine + 1, 0)
4210 self.insertAt(eol, lineFrom, 0) 4207 self.insertAt(eol, lineFrom, 0)
4211 self.insertAt(commentStr['start'], lineFrom, 0) 4208 self.insertAt(commentStr["start"], lineFrom, 0)
4212 4209
4213 # change the selection accordingly 4210 # change the selection accordingly
4214 self.setSelection(lineFrom, 0, endLine + 3, 0) 4211 self.setSelection(lineFrom, 0, endLine + 3, 0)
4215 self.endUndoAction() 4212 self.endUndoAction()
4216 4213
4217 def boxCommentLineOrSelection(self): 4214 def boxCommentLineOrSelection(self):
4218 """ 4215 """
4219 Public slot to box comment the current line or current selection. 4216 Public slot to box comment the current line or current selection.
4220 """ 4217 """
4221 if self.hasSelectedText(): 4218 if self.hasSelectedText():
4222 self.boxCommentSelection() 4219 self.boxCommentSelection()
4223 else: 4220 else:
4224 self.boxCommentLine() 4221 self.boxCommentLine()
4225 4222
4226 ########################################################################### 4223 ###########################################################################
4227 ## Indentation handling methods below 4224 ## Indentation handling methods below
4228 ########################################################################### 4225 ###########################################################################
4229 4226
4230 def __indentLine(self, indent=True): 4227 def __indentLine(self, indent=True):
4231 """ 4228 """
4232 Private method to indent or unindent the current line. 4229 Private method to indent or unindent the current line.
4233 4230
4234 @param indent flag indicating an indent operation (boolean) 4231 @param indent flag indicating an indent operation (boolean)
4235 <br />If the flag is true, an indent operation is performed. 4232 <br />If the flag is true, an indent operation is performed.
4236 Otherwise the current line is unindented. 4233 Otherwise the current line is unindented.
4237 """ 4234 """
4238 line, index = self.getCursorPosition() 4235 line, index = self.getCursorPosition()
4244 self.endUndoAction() 4241 self.endUndoAction()
4245 if indent: 4242 if indent:
4246 self.setCursorPosition(line, index + self.indentationWidth()) 4243 self.setCursorPosition(line, index + self.indentationWidth())
4247 else: 4244 else:
4248 self.setCursorPosition(line, index - self.indentationWidth()) 4245 self.setCursorPosition(line, index - self.indentationWidth())
4249 4246
4250 def __indentSelection(self, indent=True): 4247 def __indentSelection(self, indent=True):
4251 """ 4248 """
4252 Private method to indent or unindent the current selection. 4249 Private method to indent or unindent the current selection.
4253 4250
4254 @param indent flag indicating an indent operation (boolean) 4251 @param indent flag indicating an indent operation (boolean)
4255 <br />If the flag is true, an indent operation is performed. 4252 <br />If the flag is true, an indent operation is performed.
4256 Otherwise the current line is unindented. 4253 Otherwise the current line is unindented.
4257 """ 4254 """
4258 if not self.hasSelectedText(): 4255 if not self.hasSelectedText():
4259 return 4256 return
4260 4257
4261 # get the selection 4258 # get the selection
4262 lineFrom, indexFrom, lineTo, indexTo = self.getSelection() 4259 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
4263 endLine = lineTo if indexTo else lineTo - 1 4260 endLine = lineTo if indexTo else lineTo - 1
4264 4261
4265 self.beginUndoAction() 4262 self.beginUndoAction()
4266 # iterate over the lines 4263 # iterate over the lines
4267 for line in range(lineFrom, endLine + 1): 4264 for line in range(lineFrom, endLine + 1):
4268 if indent: 4265 if indent:
4269 self.indent(line) 4266 self.indent(line)
4271 self.unindent(line) 4268 self.unindent(line)
4272 self.endUndoAction() 4269 self.endUndoAction()
4273 if indent: 4270 if indent:
4274 if indexTo == 0: 4271 if indexTo == 0:
4275 self.setSelection( 4272 self.setSelection(
4276 lineFrom, indexFrom + self.indentationWidth(), 4273 lineFrom, indexFrom + self.indentationWidth(), lineTo, 0
4277 lineTo, 0) 4274 )
4278 else: 4275 else:
4279 self.setSelection( 4276 self.setSelection(
4280 lineFrom, indexFrom + self.indentationWidth(), 4277 lineFrom,
4281 lineTo, indexTo + self.indentationWidth()) 4278 indexFrom + self.indentationWidth(),
4279 lineTo,
4280 indexTo + self.indentationWidth(),
4281 )
4282 else: 4282 else:
4283 indexStart = indexFrom - self.indentationWidth() 4283 indexStart = indexFrom - self.indentationWidth()
4284 if indexStart < 0: 4284 if indexStart < 0:
4285 indexStart = 0 4285 indexStart = 0
4286 indexEnd = indexTo - self.indentationWidth() 4286 indexEnd = indexTo - self.indentationWidth()
4287 if indexEnd < 0: 4287 if indexEnd < 0:
4288 indexEnd = 0 4288 indexEnd = 0
4289 self.setSelection(lineFrom, indexStart, lineTo, indexEnd) 4289 self.setSelection(lineFrom, indexStart, lineTo, indexEnd)
4290 4290
4291 def indentLineOrSelection(self): 4291 def indentLineOrSelection(self):
4292 """ 4292 """
4293 Public slot to indent the current line or current selection. 4293 Public slot to indent the current line or current selection.
4294 """ 4294 """
4295 if self.hasSelectedText(): 4295 if self.hasSelectedText():
4296 self.__indentSelection(True) 4296 self.__indentSelection(True)
4297 else: 4297 else:
4298 self.__indentLine(True) 4298 self.__indentLine(True)
4299 4299
4300 def unindentLineOrSelection(self): 4300 def unindentLineOrSelection(self):
4301 """ 4301 """
4302 Public slot to unindent the current line or current selection. 4302 Public slot to unindent the current line or current selection.
4303 """ 4303 """
4304 if self.hasSelectedText(): 4304 if self.hasSelectedText():
4305 self.__indentSelection(False) 4305 self.__indentSelection(False)
4306 else: 4306 else:
4307 self.__indentLine(False) 4307 self.__indentLine(False)
4308 4308
4309 def smartIndentLineOrSelection(self): 4309 def smartIndentLineOrSelection(self):
4310 """ 4310 """
4311 Public slot to indent current line smartly. 4311 Public slot to indent current line smartly.
4312 """ 4312 """
4313 if self.hasSelectedText(): 4313 if self.hasSelectedText():
4318 else: 4318 else:
4319 if self.lexer_ and self.lexer_.hasSmartIndent(): 4319 if self.lexer_ and self.lexer_.hasSmartIndent():
4320 self.lexer_.smartIndentLine(self) 4320 self.lexer_.smartIndentLine(self)
4321 else: 4321 else:
4322 self.__indentLine(True) 4322 self.__indentLine(True)
4323 4323
4324 def gotoLine(self, line, pos=1, firstVisible=False, expand=False): 4324 def gotoLine(self, line, pos=1, firstVisible=False, expand=False):
4325 """ 4325 """
4326 Public slot to jump to the beginning of a line. 4326 Public slot to jump to the beginning of a line.
4327 4327
4328 @param line line number to go to 4328 @param line line number to go to
4329 @type int 4329 @type int
4330 @param pos position in line to go to 4330 @param pos position in line to go to
4331 @type int 4331 @type int
4332 @param firstVisible flag indicating to make the line the first 4332 @param firstVisible flag indicating to make the line the first
4338 self.setCursorPosition(line - 1, pos - 1) 4338 self.setCursorPosition(line - 1, pos - 1)
4339 if firstVisible: 4339 if firstVisible:
4340 self.ensureVisibleTop(line, expand) 4340 self.ensureVisibleTop(line, expand)
4341 else: 4341 else:
4342 self.ensureVisible(line, expand) 4342 self.ensureVisible(line, expand)
4343 4343
4344 def __textChanged(self): 4344 def __textChanged(self):
4345 """ 4345 """
4346 Private slot to handle a change of the editor text. 4346 Private slot to handle a change of the editor text.
4347 4347
4348 This slot defers the handling to the next time the event loop 4348 This slot defers the handling to the next time the event loop
4349 is run in order to ensure, that cursor position has been updated 4349 is run in order to ensure, that cursor position has been updated
4350 by the underlying Scintilla editor. 4350 by the underlying Scintilla editor.
4351 """ 4351 """
4352 QTimer.singleShot(0, self.__saveLastEditPosition) 4352 QTimer.singleShot(0, self.__saveLastEditPosition)
4353 4353
4354 def __saveLastEditPosition(self): 4354 def __saveLastEditPosition(self):
4355 """ 4355 """
4356 Private slot to record the last edit position. 4356 Private slot to record the last edit position.
4357 """ 4357 """
4358 self.__lastEditPosition = self.getCursorPosition() 4358 self.__lastEditPosition = self.getCursorPosition()
4359 self.lastEditPositionAvailable.emit() 4359 self.lastEditPositionAvailable.emit()
4360 4360
4361 def isLastEditPositionAvailable(self): 4361 def isLastEditPositionAvailable(self):
4362 """ 4362 """
4363 Public method to check, if a last edit position is available. 4363 Public method to check, if a last edit position is available.
4364 4364
4365 @return flag indicating availability (boolean) 4365 @return flag indicating availability (boolean)
4366 """ 4366 """
4367 return self.__lastEditPosition is not None 4367 return self.__lastEditPosition is not None
4368 4368
4369 def gotoLastEditPosition(self): 4369 def gotoLastEditPosition(self):
4370 """ 4370 """
4371 Public method to move the cursor to the last edit position. 4371 Public method to move the cursor to the last edit position.
4372 """ 4372 """
4373 self.setCursorPosition(*self.__lastEditPosition) 4373 self.setCursorPosition(*self.__lastEditPosition)
4374 self.ensureVisible(self.__lastEditPosition[0]) 4374 self.ensureVisible(self.__lastEditPosition[0])
4375 4375
4376 def gotoMethodClass(self, goUp=False): 4376 def gotoMethodClass(self, goUp=False):
4377 """ 4377 """
4378 Public method to go to the next Python method or class definition. 4378 Public method to go to the next Python method or class definition.
4379 4379
4380 @param goUp flag indicating the move direction (boolean) 4380 @param goUp flag indicating the move direction (boolean)
4381 """ 4381 """
4382 if self.isPyFile() or self.isRubyFile(): 4382 if self.isPyFile() or self.isRubyFile():
4383 lineNo = self.getCursorPosition()[0] 4383 lineNo = self.getCursorPosition()[0]
4384 line = self.text(lineNo) 4384 line = self.text(lineNo)
4395 elif not goUp and lineNo == self.lines(): 4395 elif not goUp and lineNo == self.lines():
4396 lineNo = self.lines() - 1 4396 lineNo = self.lines() - 1
4397 self.setCursorPosition(lineNo, self.lineLength(lineNo)) 4397 self.setCursorPosition(lineNo, self.lineLength(lineNo))
4398 self.ensureVisible(lineNo) 4398 self.ensureVisible(lineNo)
4399 return 4399 return
4400 4400
4401 line = self.text(lineNo) 4401 line = self.text(lineNo)
4402 if line.strip().startswith(("class ", "def ", "module ")): 4402 if line.strip().startswith(("class ", "def ", "module ")):
4403 # try 'def ' first because it occurs more often 4403 # try 'def ' first because it occurs more often
4404 first = line.find("def ") 4404 first = line.find("def ")
4405 if first > -1: 4405 if first > -1:
4416 else: 4416 else:
4417 end = self.lineLength(lineNo) - 1 4417 end = self.lineLength(lineNo) - 1
4418 self.setSelection(lineNo, first, lineNo, end) 4418 self.setSelection(lineNo, first, lineNo, end)
4419 self.ensureVisible(lineNo) 4419 self.ensureVisible(lineNo)
4420 return 4420 return
4421 4421
4422 if goUp: 4422 if goUp:
4423 lineNo -= 1 4423 lineNo -= 1
4424 else: 4424 else:
4425 lineNo += 1 4425 lineNo += 1
4426 4426
4427 ########################################################################### 4427 ###########################################################################
4428 ## Setup methods below 4428 ## Setup methods below
4429 ########################################################################### 4429 ###########################################################################
4430 4430
4431 def readSettings(self): 4431 def readSettings(self):
4436 if self.lexer_ is not None: 4436 if self.lexer_ is not None:
4437 self.lexer_.readSettings(Preferences.getSettings(), "Scintilla") 4437 self.lexer_.readSettings(Preferences.getSettings(), "Scintilla")
4438 if self.lexer_.hasSubstyles(): 4438 if self.lexer_.hasSubstyles():
4439 self.lexer_.readSubstyles(self) 4439 self.lexer_.readSubstyles(self)
4440 self.lexer_.initProperties() 4440 self.lexer_.initProperties()
4441 4441
4442 self.lexer_.setDefaultColor(self.lexer_.color(0)) 4442 self.lexer_.setDefaultColor(self.lexer_.color(0))
4443 self.lexer_.setDefaultPaper(self.lexer_.paper(0)) 4443 self.lexer_.setDefaultPaper(self.lexer_.paper(0))
4444 4444
4445 self.__bindLexer(self.fileName) 4445 self.__bindLexer(self.fileName)
4446 self.recolor() 4446 self.recolor()
4447 4447
4448 # read the typing completer settings 4448 # read the typing completer settings
4449 if self.completer is not None: 4449 if self.completer is not None:
4450 self.completer.readSettings() 4450 self.completer.readSettings()
4451 4451
4452 # set the line marker colours or pixmap 4452 # set the line marker colours or pixmap
4453 if Preferences.getEditor("LineMarkersBackground"): 4453 if Preferences.getEditor("LineMarkersBackground"):
4454 self.markerDefine(QsciScintilla.MarkerSymbol.Background, 4454 self.markerDefine(QsciScintilla.MarkerSymbol.Background, self.currentline)
4455 self.currentline) 4455 self.markerDefine(QsciScintilla.MarkerSymbol.Background, self.errorline)
4456 self.markerDefine(QsciScintilla.MarkerSymbol.Background,
4457 self.errorline)
4458 self.__setLineMarkerColours() 4456 self.__setLineMarkerColours()
4459 else: 4457 else:
4460 self.markerDefine( 4458 self.markerDefine(
4461 UI.PixmapCache.getPixmap("currentLineMarker"), 4459 UI.PixmapCache.getPixmap("currentLineMarker"), self.currentline
4462 self.currentline) 4460 )
4463 self.markerDefine( 4461 self.markerDefine(
4464 UI.PixmapCache.getPixmap("errorLineMarker"), 4462 UI.PixmapCache.getPixmap("errorLineMarker"), self.errorline
4465 self.errorline) 4463 )
4466 4464
4467 # set the text display 4465 # set the text display
4468 self.__setTextDisplay() 4466 self.__setTextDisplay()
4469 4467
4470 # set margin 0 and 2 configuration 4468 # set margin 0 and 2 configuration
4471 self.__setMarginsDisplay() 4469 self.__setMarginsDisplay()
4472 4470
4473 # set the auto-completion function 4471 # set the auto-completion function
4474 self.__acCache.setSize( 4472 self.__acCache.setSize(Preferences.getEditor("AutoCompletionCacheSize"))
4475 Preferences.getEditor("AutoCompletionCacheSize"))
4476 self.__acCache.setMaximumCacheTime( 4473 self.__acCache.setMaximumCacheTime(
4477 Preferences.getEditor("AutoCompletionCacheTime")) 4474 Preferences.getEditor("AutoCompletionCacheTime")
4478 self.__acCacheEnabled = Preferences.getEditor( 4475 )
4479 "AutoCompletionCacheEnabled") 4476 self.__acCacheEnabled = Preferences.getEditor("AutoCompletionCacheEnabled")
4480 acTimeout = Preferences.getEditor("AutoCompletionTimeout") 4477 acTimeout = Preferences.getEditor("AutoCompletionTimeout")
4481 if acTimeout != self.__acTimer.interval: 4478 if acTimeout != self.__acTimer.interval:
4482 self.__acTimer.setInterval(acTimeout) 4479 self.__acTimer.setInterval(acTimeout)
4483 self.__setAutoCompletion() 4480 self.__setAutoCompletion()
4484 4481
4485 # set the calltips function 4482 # set the calltips function
4486 self.__setCallTips() 4483 self.__setCallTips()
4487 4484
4488 # set the autosave flags 4485 # set the autosave flags
4489 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0 4486 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0
4490 4487
4491 if Preferences.getEditor("MiniContextMenu") != self.miniMenu: 4488 if Preferences.getEditor("MiniContextMenu") != self.miniMenu:
4492 # regenerate context menu 4489 # regenerate context menu
4493 self.__initContextMenu() 4490 self.__initContextMenu()
4494 else: 4491 else:
4495 # set checked context menu items 4492 # set checked context menu items
4496 self.menuActs["AutoCompletionEnable"].setChecked( 4493 self.menuActs["AutoCompletionEnable"].setChecked(
4497 self.autoCompletionThreshold() != -1) 4494 self.autoCompletionThreshold() != -1
4498 self.menuActs["MonospacedFont"].setChecked( 4495 )
4499 self.useMonospaced) 4496 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced)
4500 self.menuActs["AutosaveEnable"].setChecked( 4497 self.menuActs["AutosaveEnable"].setChecked(
4501 self.autosaveEnabled and not self.autosaveManuallyDisabled) 4498 self.autosaveEnabled and not self.autosaveManuallyDisabled
4502 4499 )
4500
4503 # regenerate the margins context menu(s) 4501 # regenerate the margins context menu(s)
4504 self.__initContextMenuMargins() 4502 self.__initContextMenuMargins()
4505 4503
4506 if Preferences.getEditor("MarkOccurrencesEnabled"): 4504 if Preferences.getEditor("MarkOccurrencesEnabled"):
4507 self.__markOccurrencesTimer.setInterval( 4505 self.__markOccurrencesTimer.setInterval(
4508 Preferences.getEditor("MarkOccurrencesTimeout")) 4506 Preferences.getEditor("MarkOccurrencesTimeout")
4507 )
4509 else: 4508 else:
4510 self.__markOccurrencesTimer.stop() 4509 self.__markOccurrencesTimer.stop()
4511 self.clearSearchIndicators() 4510 self.clearSearchIndicators()
4512 4511
4513 if Preferences.getEditor("OnlineSyntaxCheck"): 4512 if Preferences.getEditor("OnlineSyntaxCheck"):
4514 self.__onlineSyntaxCheckTimer.setInterval( 4513 self.__onlineSyntaxCheckTimer.setInterval(
4515 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000) 4514 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000
4515 )
4516 else: 4516 else:
4517 self.__onlineSyntaxCheckTimer.stop() 4517 self.__onlineSyntaxCheckTimer.stop()
4518 4518
4519 if Preferences.getEditor("OnlineChangeTrace"): 4519 if Preferences.getEditor("OnlineChangeTrace"):
4520 self.__onlineChangeTraceTimer.setInterval( 4520 self.__onlineChangeTraceTimer.setInterval(
4521 Preferences.getEditor("OnlineChangeTraceInterval")) 4521 Preferences.getEditor("OnlineChangeTraceInterval")
4522 )
4522 else: 4523 else:
4523 self.__onlineChangeTraceTimer.stop() 4524 self.__onlineChangeTraceTimer.stop()
4524 self.__deleteAllChangeMarkers() 4525 self.__deleteAllChangeMarkers()
4525 self.markerDefine(self.__createChangeMarkerPixmap( 4526 self.markerDefine(
4526 "OnlineChangeTraceMarkerUnsaved"), self.__changeMarkerUnsaved) 4527 self.__createChangeMarkerPixmap("OnlineChangeTraceMarkerUnsaved"),
4527 self.markerDefine(self.__createChangeMarkerPixmap( 4528 self.__changeMarkerUnsaved,
4528 "OnlineChangeTraceMarkerSaved"), self.__changeMarkerSaved) 4529 )
4529 4530 self.markerDefine(
4531 self.__createChangeMarkerPixmap("OnlineChangeTraceMarkerSaved"),
4532 self.__changeMarkerSaved,
4533 )
4534
4530 # refresh the annotations display 4535 # refresh the annotations display
4531 self.__refreshAnnotations() 4536 self.__refreshAnnotations()
4532 4537
4533 self.__markerMap.setMapPosition( 4538 self.__markerMap.setMapPosition(Preferences.getEditor("ShowMarkerMapOnRight"))
4534 Preferences.getEditor("ShowMarkerMapOnRight"))
4535 self.__markerMap.initColors() 4539 self.__markerMap.initColors()
4536 4540
4537 self.setLanguage(self.fileName, propagate=False) 4541 self.setLanguage(self.fileName, propagate=False)
4538 4542
4539 self.settingsRead.emit() 4543 self.settingsRead.emit()
4540 4544
4541 def __setLineMarkerColours(self): 4545 def __setLineMarkerColours(self):
4542 """ 4546 """
4543 Private method to set the line marker colours. 4547 Private method to set the line marker colours.
4544 """ 4548 """
4545 self.setMarkerForegroundColor( 4549 self.setMarkerForegroundColor(
4546 Preferences.getEditorColour("CurrentMarker"), self.currentline) 4550 Preferences.getEditorColour("CurrentMarker"), self.currentline
4551 )
4547 self.setMarkerBackgroundColor( 4552 self.setMarkerBackgroundColor(
4548 Preferences.getEditorColour("CurrentMarker"), self.currentline) 4553 Preferences.getEditorColour("CurrentMarker"), self.currentline
4554 )
4549 self.setMarkerForegroundColor( 4555 self.setMarkerForegroundColor(
4550 Preferences.getEditorColour("ErrorMarker"), self.errorline) 4556 Preferences.getEditorColour("ErrorMarker"), self.errorline
4557 )
4551 self.setMarkerBackgroundColor( 4558 self.setMarkerBackgroundColor(
4552 Preferences.getEditorColour("ErrorMarker"), self.errorline) 4559 Preferences.getEditorColour("ErrorMarker"), self.errorline
4553 4560 )
4561
4554 def __setMarginsDisplay(self): 4562 def __setMarginsDisplay(self):
4555 """ 4563 """
4556 Private method to configure margins 0 and 2. 4564 Private method to configure margins 0 and 2.
4557 """ 4565 """
4558 # set the settings for all margins 4566 # set the settings for all margins
4559 self.setMarginsFont(Preferences.getEditorOtherFonts("MarginsFont")) 4567 self.setMarginsFont(Preferences.getEditorOtherFonts("MarginsFont"))
4560 self.setMarginsForegroundColor( 4568 self.setMarginsForegroundColor(Preferences.getEditorColour("MarginsForeground"))
4561 Preferences.getEditorColour("MarginsForeground")) 4569 self.setMarginsBackgroundColor(Preferences.getEditorColour("MarginsBackground"))
4562 self.setMarginsBackgroundColor( 4570
4563 Preferences.getEditorColour("MarginsBackground"))
4564
4565 # reset standard margins settings 4571 # reset standard margins settings
4566 for margin in range(5): 4572 for margin in range(5):
4567 self.setMarginLineNumbers(margin, False) 4573 self.setMarginLineNumbers(margin, False)
4568 self.setMarginMarkerMask(margin, 0) 4574 self.setMarginMarkerMask(margin, 0)
4569 self.setMarginWidth(margin, 0) 4575 self.setMarginWidth(margin, 0)
4570 self.setMarginSensitivity(margin, False) 4576 self.setMarginSensitivity(margin, False)
4571 4577
4572 # set marker margin(s) settings 4578 # set marker margin(s) settings
4573 self.__bmMargin = 0 4579 self.__bmMargin = 0
4574 self.__linenoMargin = 1 4580 self.__linenoMargin = 1
4575 self.__bpMargin = 2 4581 self.__bpMargin = 2
4576 self.__foldMargin = 3 4582 self.__foldMargin = 3
4577 self.__indicMargin = 4 4583 self.__indicMargin = 4
4578 4584
4579 marginBmMask = (1 << self.bookmark) 4585 marginBmMask = 1 << self.bookmark
4580 self.setMarginWidth(self.__bmMargin, 16) 4586 self.setMarginWidth(self.__bmMargin, 16)
4581 self.setMarginSensitivity(self.__bmMargin, True) 4587 self.setMarginSensitivity(self.__bmMargin, True)
4582 self.setMarginMarkerMask(self.__bmMargin, marginBmMask) 4588 self.setMarginMarkerMask(self.__bmMargin, marginBmMask)
4583 4589
4584 marginBpMask = ( 4590 marginBpMask = (
4585 (1 << self.breakpoint) | 4591 (1 << self.breakpoint)
4586 (1 << self.cbreakpoint) | 4592 | (1 << self.cbreakpoint)
4587 (1 << self.tbreakpoint) | 4593 | (1 << self.tbreakpoint)
4588 (1 << self.tcbreakpoint) | 4594 | (1 << self.tcbreakpoint)
4589 (1 << self.dbreakpoint) 4595 | (1 << self.dbreakpoint)
4590 ) 4596 )
4591 self.setMarginWidth(self.__bpMargin, 16) 4597 self.setMarginWidth(self.__bpMargin, 16)
4592 self.setMarginSensitivity(self.__bpMargin, True) 4598 self.setMarginSensitivity(self.__bpMargin, True)
4593 self.setMarginMarkerMask(self.__bpMargin, marginBpMask) 4599 self.setMarginMarkerMask(self.__bpMargin, marginBpMask)
4594 4600
4595 marginIndicMask = ( 4601 marginIndicMask = (
4596 (1 << self.syntaxerror) | 4602 (1 << self.syntaxerror)
4597 (1 << self.notcovered) | 4603 | (1 << self.notcovered)
4598 (1 << self.taskmarker) | 4604 | (1 << self.taskmarker)
4599 (1 << self.warning) | 4605 | (1 << self.warning)
4600 (1 << self.__changeMarkerUnsaved) | 4606 | (1 << self.__changeMarkerUnsaved)
4601 (1 << self.__changeMarkerSaved) | 4607 | (1 << self.__changeMarkerSaved)
4602 (1 << self.currentline) | 4608 | (1 << self.currentline)
4603 (1 << self.errorline) 4609 | (1 << self.errorline)
4604 ) 4610 )
4605 self.setMarginWidth(self.__indicMargin, 16) 4611 self.setMarginWidth(self.__indicMargin, 16)
4606 self.setMarginSensitivity(self.__indicMargin, True) 4612 self.setMarginSensitivity(self.__indicMargin, True)
4607 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask) 4613 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask)
4608 4614
4609 # set linenumber margin settings 4615 # set linenumber margin settings
4610 linenoMargin = Preferences.getEditor("LinenoMargin") 4616 linenoMargin = Preferences.getEditor("LinenoMargin")
4611 self.setMarginLineNumbers(self.__linenoMargin, linenoMargin) 4617 self.setMarginLineNumbers(self.__linenoMargin, linenoMargin)
4612 if linenoMargin: 4618 if linenoMargin:
4613 self.__resizeLinenoMargin() 4619 self.__resizeLinenoMargin()
4614 else: 4620 else:
4615 self.setMarginWidth(self.__linenoMargin, 0) 4621 self.setMarginWidth(self.__linenoMargin, 0)
4616 4622
4617 # set folding margin settings 4623 # set folding margin settings
4618 if Preferences.getEditor("FoldingMargin"): 4624 if Preferences.getEditor("FoldingMargin"):
4619 self.setMarginWidth(self.__foldMargin, 16) 4625 self.setMarginWidth(self.__foldMargin, 16)
4620 folding = Preferences.getEditor("FoldingStyle") 4626 folding = Preferences.getEditor("FoldingStyle")
4621 self.setFolding(folding, self.__foldMargin) 4627 self.setFolding(folding, self.__foldMargin)
4622 self.setFoldMarginColors( 4628 self.setFoldMarginColors(
4623 Preferences.getEditorColour("FoldmarginBackground"), 4629 Preferences.getEditorColour("FoldmarginBackground"),
4624 Preferences.getEditorColour("FoldmarginBackground")) 4630 Preferences.getEditorColour("FoldmarginBackground"),
4631 )
4625 self.setFoldMarkersColors( 4632 self.setFoldMarkersColors(
4626 Preferences.getEditorColour("FoldMarkersForeground"), 4633 Preferences.getEditorColour("FoldMarkersForeground"),
4627 Preferences.getEditorColour("FoldMarkersBackground")) 4634 Preferences.getEditorColour("FoldMarkersBackground"),
4635 )
4628 else: 4636 else:
4629 self.setMarginWidth(self.__foldMargin, 0) 4637 self.setMarginWidth(self.__foldMargin, 0)
4630 self.setFolding(QsciScintilla.FoldStyle.NoFoldStyle.value, 4638 self.setFolding(
4631 self.__foldMargin) 4639 QsciScintilla.FoldStyle.NoFoldStyle.value, self.__foldMargin
4632 4640 )
4641
4633 def __resizeLinenoMargin(self): 4642 def __resizeLinenoMargin(self):
4634 """ 4643 """
4635 Private slot to resize the line numbers margin. 4644 Private slot to resize the line numbers margin.
4636 """ 4645 """
4637 linenoMargin = Preferences.getEditor("LinenoMargin") 4646 linenoMargin = Preferences.getEditor("LinenoMargin")
4638 if linenoMargin: 4647 if linenoMargin:
4639 self.setMarginWidth( 4648 self.setMarginWidth(self.__linenoMargin, "8" * (len(str(self.lines())) + 1))
4640 self.__linenoMargin, '8' * (len(str(self.lines())) + 1)) 4649
4641
4642 def __setTabAndIndent(self): 4650 def __setTabAndIndent(self):
4643 """ 4651 """
4644 Private method to set indentation size and style and tab width. 4652 Private method to set indentation size and style and tab width.
4645 """ 4653 """
4646 self.setTabWidth(self.__getEditorConfig("TabWidth")) 4654 self.setTabWidth(self.__getEditorConfig("TabWidth"))
4647 self.setIndentationWidth(self.__getEditorConfig("IndentWidth")) 4655 self.setIndentationWidth(self.__getEditorConfig("IndentWidth"))
4648 if self.lexer_ and self.lexer_.alwaysKeepTabs(): 4656 if self.lexer_ and self.lexer_.alwaysKeepTabs():
4649 self.setIndentationsUseTabs(True) 4657 self.setIndentationsUseTabs(True)
4650 else: 4658 else:
4651 self.setIndentationsUseTabs( 4659 self.setIndentationsUseTabs(self.__getEditorConfig("TabForIndentation"))
4652 self.__getEditorConfig("TabForIndentation")) 4660
4653
4654 def __setTextDisplay(self): 4661 def __setTextDisplay(self):
4655 """ 4662 """
4656 Private method to configure the text display. 4663 Private method to configure the text display.
4657 """ 4664 """
4658 self.__setTabAndIndent() 4665 self.__setTabAndIndent()
4659 4666
4660 self.setTabIndents(Preferences.getEditor("TabIndents")) 4667 self.setTabIndents(Preferences.getEditor("TabIndents"))
4661 self.setBackspaceUnindents(Preferences.getEditor("TabIndents")) 4668 self.setBackspaceUnindents(Preferences.getEditor("TabIndents"))
4662 self.setIndentationGuides(Preferences.getEditor("IndentationGuides")) 4669 self.setIndentationGuides(Preferences.getEditor("IndentationGuides"))
4663 self.setIndentationGuidesBackgroundColor( 4670 self.setIndentationGuidesBackgroundColor(
4664 Preferences.getEditorColour("IndentationGuidesBackground")) 4671 Preferences.getEditorColour("IndentationGuidesBackground")
4672 )
4665 self.setIndentationGuidesForegroundColor( 4673 self.setIndentationGuidesForegroundColor(
4666 Preferences.getEditorColour("IndentationGuidesForeground")) 4674 Preferences.getEditorColour("IndentationGuidesForeground")
4675 )
4667 if Preferences.getEditor("ShowWhitespace"): 4676 if Preferences.getEditor("ShowWhitespace"):
4668 self.setWhitespaceVisibility( 4677 self.setWhitespaceVisibility(QsciScintilla.WhitespaceVisibility.WsVisible)
4669 QsciScintilla.WhitespaceVisibility.WsVisible)
4670 with contextlib.suppress(AttributeError): 4678 with contextlib.suppress(AttributeError):
4671 self.setWhitespaceForegroundColor( 4679 self.setWhitespaceForegroundColor(
4672 Preferences.getEditorColour("WhitespaceForeground")) 4680 Preferences.getEditorColour("WhitespaceForeground")
4681 )
4673 self.setWhitespaceBackgroundColor( 4682 self.setWhitespaceBackgroundColor(
4674 Preferences.getEditorColour("WhitespaceBackground")) 4683 Preferences.getEditorColour("WhitespaceBackground")
4675 self.setWhitespaceSize( 4684 )
4676 Preferences.getEditor("WhitespaceSize")) 4685 self.setWhitespaceSize(Preferences.getEditor("WhitespaceSize"))
4677 else: 4686 else:
4678 self.setWhitespaceVisibility( 4687 self.setWhitespaceVisibility(QsciScintilla.WhitespaceVisibility.WsInvisible)
4679 QsciScintilla.WhitespaceVisibility.WsInvisible)
4680 self.setEolVisibility(Preferences.getEditor("ShowEOL")) 4688 self.setEolVisibility(Preferences.getEditor("ShowEOL"))
4681 self.setAutoIndent(Preferences.getEditor("AutoIndentation")) 4689 self.setAutoIndent(Preferences.getEditor("AutoIndentation"))
4682 if Preferences.getEditor("BraceHighlighting"): 4690 if Preferences.getEditor("BraceHighlighting"):
4683 self.setBraceMatching(QsciScintilla.BraceMatch.SloppyBraceMatch) 4691 self.setBraceMatching(QsciScintilla.BraceMatch.SloppyBraceMatch)
4684 else: 4692 else:
4685 self.setBraceMatching(QsciScintilla.BraceMatch.NoBraceMatch) 4693 self.setBraceMatching(QsciScintilla.BraceMatch.NoBraceMatch)
4686 self.setMatchedBraceForegroundColor( 4694 self.setMatchedBraceForegroundColor(
4687 Preferences.getEditorColour("MatchingBrace")) 4695 Preferences.getEditorColour("MatchingBrace")
4696 )
4688 self.setMatchedBraceBackgroundColor( 4697 self.setMatchedBraceBackgroundColor(
4689 Preferences.getEditorColour("MatchingBraceBack")) 4698 Preferences.getEditorColour("MatchingBraceBack")
4699 )
4690 self.setUnmatchedBraceForegroundColor( 4700 self.setUnmatchedBraceForegroundColor(
4691 Preferences.getEditorColour("NonmatchingBrace")) 4701 Preferences.getEditorColour("NonmatchingBrace")
4702 )
4692 self.setUnmatchedBraceBackgroundColor( 4703 self.setUnmatchedBraceBackgroundColor(
4693 Preferences.getEditorColour("NonmatchingBraceBack")) 4704 Preferences.getEditorColour("NonmatchingBraceBack")
4705 )
4694 if Preferences.getEditor("CustomSelectionColours"): 4706 if Preferences.getEditor("CustomSelectionColours"):
4695 self.setSelectionBackgroundColor( 4707 self.setSelectionBackgroundColor(
4696 Preferences.getEditorColour("SelectionBackground")) 4708 Preferences.getEditorColour("SelectionBackground")
4709 )
4697 else: 4710 else:
4698 self.setSelectionBackgroundColor( 4711 self.setSelectionBackgroundColor(
4699 QApplication.palette().color(QPalette.ColorRole.Highlight)) 4712 QApplication.palette().color(QPalette.ColorRole.Highlight)
4713 )
4700 if Preferences.getEditor("ColourizeSelText"): 4714 if Preferences.getEditor("ColourizeSelText"):
4701 self.resetSelectionForegroundColor() 4715 self.resetSelectionForegroundColor()
4702 elif Preferences.getEditor("CustomSelectionColours"): 4716 elif Preferences.getEditor("CustomSelectionColours"):
4703 self.setSelectionForegroundColor( 4717 self.setSelectionForegroundColor(
4704 Preferences.getEditorColour("SelectionForeground")) 4718 Preferences.getEditorColour("SelectionForeground")
4719 )
4705 else: 4720 else:
4706 self.setSelectionForegroundColor( 4721 self.setSelectionForegroundColor(
4707 QApplication.palette().color( 4722 QApplication.palette().color(QPalette.ColorRole.HighlightedText)
4708 QPalette.ColorRole.HighlightedText)) 4723 )
4709 self.setSelectionToEol(Preferences.getEditor("ExtendSelectionToEol")) 4724 self.setSelectionToEol(Preferences.getEditor("ExtendSelectionToEol"))
4710 self.setCaretForegroundColor( 4725 self.setCaretForegroundColor(Preferences.getEditorColour("CaretForeground"))
4711 Preferences.getEditorColour("CaretForeground"))
4712 self.setCaretLineBackgroundColor( 4726 self.setCaretLineBackgroundColor(
4713 Preferences.getEditorColour("CaretLineBackground")) 4727 Preferences.getEditorColour("CaretLineBackground")
4728 )
4714 self.setCaretLineVisible(Preferences.getEditor("CaretLineVisible")) 4729 self.setCaretLineVisible(Preferences.getEditor("CaretLineVisible"))
4715 self.setCaretLineAlwaysVisible( 4730 self.setCaretLineAlwaysVisible(Preferences.getEditor("CaretLineAlwaysVisible"))
4716 Preferences.getEditor("CaretLineAlwaysVisible"))
4717 self.caretWidth = Preferences.getEditor("CaretWidth") 4731 self.caretWidth = Preferences.getEditor("CaretWidth")
4718 self.setCaretWidth(self.caretWidth) 4732 self.setCaretWidth(self.caretWidth)
4719 self.caretLineFrameWidth = Preferences.getEditor("CaretLineFrameWidth") 4733 self.caretLineFrameWidth = Preferences.getEditor("CaretLineFrameWidth")
4720 self.setCaretLineFrameWidth(self.caretLineFrameWidth) 4734 self.setCaretLineFrameWidth(self.caretLineFrameWidth)
4721 self.useMonospaced = Preferences.getEditor("UseMonospacedFont") 4735 self.useMonospaced = Preferences.getEditor("UseMonospacedFont")
4724 edge = QsciScintilla.EdgeMode(edgeMode) 4738 edge = QsciScintilla.EdgeMode(edgeMode)
4725 self.setEdgeMode(edge) 4739 self.setEdgeMode(edge)
4726 if edgeMode: 4740 if edgeMode:
4727 self.setEdgeColumn(Preferences.getEditor("EdgeColumn")) 4741 self.setEdgeColumn(Preferences.getEditor("EdgeColumn"))
4728 self.setEdgeColor(Preferences.getEditorColour("Edge")) 4742 self.setEdgeColor(Preferences.getEditorColour("Edge"))
4729 4743
4730 wrapVisualFlag = Preferences.getEditor("WrapVisualFlag") 4744 wrapVisualFlag = Preferences.getEditor("WrapVisualFlag")
4731 self.setWrapMode(Preferences.getEditor("WrapLongLinesMode")) 4745 self.setWrapMode(Preferences.getEditor("WrapLongLinesMode"))
4732 self.setWrapVisualFlags(wrapVisualFlag, wrapVisualFlag) 4746 self.setWrapVisualFlags(wrapVisualFlag, wrapVisualFlag)
4733 self.setWrapIndentMode(Preferences.getEditor("WrapIndentMode")) 4747 self.setWrapIndentMode(Preferences.getEditor("WrapIndentMode"))
4734 self.setWrapStartIndent(Preferences.getEditor("WrapStartIndent")) 4748 self.setWrapStartIndent(Preferences.getEditor("WrapStartIndent"))
4735 4749
4736 self.zoomTo(Preferences.getEditor("ZoomFactor")) 4750 self.zoomTo(Preferences.getEditor("ZoomFactor"))
4737 4751
4738 self.searchIndicator = QsciScintilla.INDIC_CONTAINER 4752 self.searchIndicator = QsciScintilla.INDIC_CONTAINER
4739 self.indicatorDefine( 4753 self.indicatorDefine(
4740 self.searchIndicator, QsciScintilla.INDIC_BOX, 4754 self.searchIndicator,
4741 Preferences.getEditorColour("SearchMarkers")) 4755 QsciScintilla.INDIC_BOX,
4756 Preferences.getEditorColour("SearchMarkers"),
4757 )
4742 if ( 4758 if (
4743 not Preferences.getEditor("SearchMarkersEnabled") and 4759 not Preferences.getEditor("SearchMarkersEnabled")
4744 not Preferences.getEditor("QuickSearchMarkersEnabled") and 4760 and not Preferences.getEditor("QuickSearchMarkersEnabled")
4745 not Preferences.getEditor("MarkOccurrencesEnabled") 4761 and not Preferences.getEditor("MarkOccurrencesEnabled")
4746 ): 4762 ):
4747 self.clearAllIndicators(self.searchIndicator) 4763 self.clearAllIndicators(self.searchIndicator)
4748 4764
4749 self.spellingIndicator = QsciScintilla.INDIC_CONTAINER + 1 4765 self.spellingIndicator = QsciScintilla.INDIC_CONTAINER + 1
4750 self.indicatorDefine( 4766 self.indicatorDefine(
4751 self.spellingIndicator, QsciScintilla.INDIC_SQUIGGLE, 4767 self.spellingIndicator,
4752 Preferences.getEditorColour("SpellingMarkers")) 4768 QsciScintilla.INDIC_SQUIGGLE,
4769 Preferences.getEditorColour("SpellingMarkers"),
4770 )
4753 self.__setSpelling() 4771 self.__setSpelling()
4754 4772
4755 self.highlightIndicator = QsciScintilla.INDIC_CONTAINER + 2 4773 self.highlightIndicator = QsciScintilla.INDIC_CONTAINER + 2
4756 self.indicatorDefine( 4774 self.indicatorDefine(
4757 self.highlightIndicator, QsciScintilla.INDIC_FULLBOX, 4775 self.highlightIndicator,
4758 Preferences.getEditorColour("HighlightMarker")) 4776 QsciScintilla.INDIC_FULLBOX,
4759 4777 Preferences.getEditorColour("HighlightMarker"),
4778 )
4779
4760 self.setCursorFlashTime(QApplication.cursorFlashTime()) 4780 self.setCursorFlashTime(QApplication.cursorFlashTime())
4761 4781
4762 with contextlib.suppress(AttributeError): 4782 with contextlib.suppress(AttributeError):
4763 if Preferences.getEditor("AnnotationsEnabled"): 4783 if Preferences.getEditor("AnnotationsEnabled"):
4764 self.setAnnotationDisplay( 4784 self.setAnnotationDisplay(
4765 QsciScintilla.AnnotationDisplay.AnnotationBoxed) 4785 QsciScintilla.AnnotationDisplay.AnnotationBoxed
4786 )
4766 else: 4787 else:
4767 self.setAnnotationDisplay( 4788 self.setAnnotationDisplay(
4768 QsciScintilla.AnnotationDisplay.AnnotationHidden) 4789 QsciScintilla.AnnotationDisplay.AnnotationHidden
4790 )
4769 self.__setAnnotationStyles() 4791 self.__setAnnotationStyles()
4770 4792
4771 if Preferences.getEditor("OverrideEditAreaColours"): 4793 if Preferences.getEditor("OverrideEditAreaColours"):
4772 self.setColor(Preferences.getEditorColour("EditAreaForeground")) 4794 self.setColor(Preferences.getEditorColour("EditAreaForeground"))
4773 self.setPaper(Preferences.getEditorColour("EditAreaBackground")) 4795 self.setPaper(Preferences.getEditorColour("EditAreaBackground"))
4774 4796
4775 self.setVirtualSpaceOptions( 4797 self.setVirtualSpaceOptions(Preferences.getEditor("VirtualSpaceOptions"))
4776 Preferences.getEditor("VirtualSpaceOptions")) 4798
4777
4778 if Preferences.getEditor("MouseHoverHelp"): 4799 if Preferences.getEditor("MouseHoverHelp"):
4779 self.SendScintilla(QsciScintilla.SCI_SETMOUSEDWELLTIME, 4800 self.SendScintilla(
4780 Preferences.getEditor("MouseHoverTimeout")) 4801 QsciScintilla.SCI_SETMOUSEDWELLTIME,
4781 else: 4802 Preferences.getEditor("MouseHoverTimeout"),
4782 self.SendScintilla(QsciScintilla.SCI_SETMOUSEDWELLTIME, 4803 )
4783 QsciScintilla.SC_TIME_FOREVER) 4804 else:
4784 4805 self.SendScintilla(
4806 QsciScintilla.SCI_SETMOUSEDWELLTIME, QsciScintilla.SC_TIME_FOREVER
4807 )
4808
4785 # to avoid errors due to line endings by pasting 4809 # to avoid errors due to line endings by pasting
4786 self.SendScintilla(QsciScintilla.SCI_SETPASTECONVERTENDINGS, True) 4810 self.SendScintilla(QsciScintilla.SCI_SETPASTECONVERTENDINGS, True)
4787 4811
4788 self.__markerMap.setEnabled(True) 4812 self.__markerMap.setEnabled(True)
4789 4813
4790 def __setEolMode(self): 4814 def __setEolMode(self):
4791 """ 4815 """
4792 Private method to configure the eol mode of the editor. 4816 Private method to configure the eol mode of the editor.
4793 """ 4817 """
4794 if ( 4818 if (
4795 self.fileName and 4819 self.fileName
4796 self.project.isOpen() and 4820 and self.project.isOpen()
4797 self.project.isProjectFile(self.fileName) 4821 and self.project.isProjectFile(self.fileName)
4798 ): 4822 ):
4799 eolMode = self.__getEditorConfig("EOLMode", nodefault=True) 4823 eolMode = self.__getEditorConfig("EOLMode", nodefault=True)
4800 if eolMode is None: 4824 if eolMode is None:
4801 eolStr = self.project.getEolString() 4825 eolStr = self.project.getEolString()
4802 self.setEolModeByEolString(eolStr) 4826 self.setEolModeByEolString(eolStr)
4804 self.setEolMode(eolMode) 4828 self.setEolMode(eolMode)
4805 else: 4829 else:
4806 eolMode = self.__getEditorConfig("EOLMode") 4830 eolMode = self.__getEditorConfig("EOLMode")
4807 self.setEolMode(eolMode) 4831 self.setEolMode(eolMode)
4808 self.__eolChanged() 4832 self.__eolChanged()
4809 4833
4810 def __setAutoCompletion(self): 4834 def __setAutoCompletion(self):
4811 """ 4835 """
4812 Private method to configure the autocompletion function. 4836 Private method to configure the autocompletion function.
4813 """ 4837 """
4814 if self.lexer_: 4838 if self.lexer_:
4815 self.setAutoCompletionFillupsEnabled( 4839 self.setAutoCompletionFillupsEnabled(
4816 Preferences.getEditor("AutoCompletionFillups")) 4840 Preferences.getEditor("AutoCompletionFillups")
4841 )
4817 self.setAutoCompletionCaseSensitivity( 4842 self.setAutoCompletionCaseSensitivity(
4818 Preferences.getEditor("AutoCompletionCaseSensitivity")) 4843 Preferences.getEditor("AutoCompletionCaseSensitivity")
4844 )
4819 self.setAutoCompletionReplaceWord( 4845 self.setAutoCompletionReplaceWord(
4820 Preferences.getEditor("AutoCompletionReplaceWord")) 4846 Preferences.getEditor("AutoCompletionReplaceWord")
4847 )
4821 self.setAutoCompletionThreshold(0) 4848 self.setAutoCompletionThreshold(0)
4822 if Preferences.getEditor("AutoCompletionShowSingle"): 4849 if Preferences.getEditor("AutoCompletionShowSingle"):
4823 self.setAutoCompletionUseSingle( 4850 self.setAutoCompletionUseSingle(
4824 QsciScintilla.AutoCompletionUseSingle.AcusAlways) 4851 QsciScintilla.AutoCompletionUseSingle.AcusAlways
4852 )
4825 else: 4853 else:
4826 self.setAutoCompletionUseSingle( 4854 self.setAutoCompletionUseSingle(
4827 QsciScintilla.AutoCompletionUseSingle.AcusNever) 4855 QsciScintilla.AutoCompletionUseSingle.AcusNever
4856 )
4828 autoCompletionSource = Preferences.getEditor("AutoCompletionSource") 4857 autoCompletionSource = Preferences.getEditor("AutoCompletionSource")
4829 if ( 4858 if autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsDocument:
4830 autoCompletionSource == 4859 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsDocument)
4831 QsciScintilla.AutoCompletionSource.AcsDocument 4860 elif autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsAPIs:
4832 ): 4861 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAPIs)
4833 self.setAutoCompletionSource( 4862 else:
4834 QsciScintilla.AutoCompletionSource.AcsDocument) 4863 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll)
4835 elif ( 4864
4836 autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsAPIs
4837 ):
4838 self.setAutoCompletionSource(
4839 QsciScintilla.AutoCompletionSource.AcsAPIs)
4840 else:
4841 self.setAutoCompletionSource(
4842 QsciScintilla.AutoCompletionSource.AcsAll)
4843
4844 self.setAutoCompletionWidgetSize( 4865 self.setAutoCompletionWidgetSize(
4845 Preferences.getEditor("AutoCompletionMaxChars"), 4866 Preferences.getEditor("AutoCompletionMaxChars"),
4846 Preferences.getEditor("AutoCompletionMaxLines") 4867 Preferences.getEditor("AutoCompletionMaxLines"),
4847 ) 4868 )
4848 4869
4849 def __setCallTips(self): 4870 def __setCallTips(self):
4850 """ 4871 """
4851 Private method to configure the calltips function. 4872 Private method to configure the calltips function.
4852 """ 4873 """
4853 self.setCallTipsBackgroundColor( 4874 self.setCallTipsBackgroundColor(
4854 Preferences.getEditorColour("CallTipsBackground")) 4875 Preferences.getEditorColour("CallTipsBackground")
4876 )
4855 self.setCallTipsForegroundColor( 4877 self.setCallTipsForegroundColor(
4856 Preferences.getEditorColour("CallTipsForeground")) 4878 Preferences.getEditorColour("CallTipsForeground")
4857 self.setCallTipsHighlightColor( 4879 )
4858 Preferences.getEditorColour("CallTipsHighlight")) 4880 self.setCallTipsHighlightColor(Preferences.getEditorColour("CallTipsHighlight"))
4859 self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible")) 4881 self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible"))
4860 calltipsStyle = Preferences.getEditor("CallTipsStyle") 4882 calltipsStyle = Preferences.getEditor("CallTipsStyle")
4861 with contextlib.suppress(AttributeError): 4883 with contextlib.suppress(AttributeError):
4862 self.setCallTipsPosition( 4884 self.setCallTipsPosition(Preferences.getEditor("CallTipsPosition"))
4863 Preferences.getEditor("CallTipsPosition")) 4885
4864
4865 if Preferences.getEditor("CallTipsEnabled"): 4886 if Preferences.getEditor("CallTipsEnabled"):
4866 if calltipsStyle == QsciScintilla.CallTipsStyle.CallTipsNoContext: 4887 if calltipsStyle == QsciScintilla.CallTipsStyle.CallTipsNoContext:
4867 self.setCallTipsStyle( 4888 self.setCallTipsStyle(QsciScintilla.CallTipsStyle.CallTipsNoContext)
4868 QsciScintilla.CallTipsStyle.CallTipsNoContext)
4869 elif ( 4889 elif (
4870 calltipsStyle == 4890 calltipsStyle
4871 QsciScintilla.CallTipsStyle.CallTipsNoAutoCompletionContext 4891 == QsciScintilla.CallTipsStyle.CallTipsNoAutoCompletionContext
4872 ): 4892 ):
4873 self.setCallTipsStyle( 4893 self.setCallTipsStyle(
4874 QsciScintilla.CallTipsStyle 4894 QsciScintilla.CallTipsStyle.CallTipsNoAutoCompletionContext
4875 .CallTipsNoAutoCompletionContext) 4895 )
4876 else: 4896 else:
4877 self.setCallTipsStyle( 4897 self.setCallTipsStyle(QsciScintilla.CallTipsStyle.CallTipsContext)
4878 QsciScintilla.CallTipsStyle.CallTipsContext)
4879 else: 4898 else:
4880 self.setCallTipsStyle(QsciScintilla.CallTipsStyle.CallTipsNone) 4899 self.setCallTipsStyle(QsciScintilla.CallTipsStyle.CallTipsNone)
4881 4900
4882 ########################################################################### 4901 ###########################################################################
4883 ## Autocompletion handling methods below 4902 ## Autocompletion handling methods below
4884 ########################################################################### 4903 ###########################################################################
4885 4904
4886 def canAutoCompleteFromAPIs(self): 4905 def canAutoCompleteFromAPIs(self):
4887 """ 4906 """
4888 Public method to check for API availablity. 4907 Public method to check for API availablity.
4889 4908
4890 @return flag indicating autocompletion from APIs is available (boolean) 4909 @return flag indicating autocompletion from APIs is available (boolean)
4891 """ 4910 """
4892 return self.acAPI 4911 return self.acAPI
4893 4912
4894 def autoCompleteQScintilla(self): 4913 def autoCompleteQScintilla(self):
4895 """ 4914 """
4896 Public method to perform an autocompletion using QScintilla methods. 4915 Public method to perform an autocompletion using QScintilla methods.
4897 """ 4916 """
4898 self.__acText = ' ' # Prevent long running ACs to add results 4917 self.__acText = " " # Prevent long running ACs to add results
4899 self.__acWatchdog.stop() 4918 self.__acWatchdog.stop()
4900 if self.__acCompletions: 4919 if self.__acCompletions:
4901 return 4920 return
4902 4921
4903 acs = Preferences.getEditor("AutoCompletionSource") 4922 acs = Preferences.getEditor("AutoCompletionSource")
4904 if acs == QsciScintilla.AutoCompletionSource.AcsDocument: 4923 if acs == QsciScintilla.AutoCompletionSource.AcsDocument:
4905 self.autoCompleteFromDocument() 4924 self.autoCompleteFromDocument()
4906 elif acs == QsciScintilla.AutoCompletionSource.AcsAPIs: 4925 elif acs == QsciScintilla.AutoCompletionSource.AcsAPIs:
4907 self.autoCompleteFromAPIs() 4926 self.autoCompleteFromAPIs()
4911 EricMessageBox.information( 4930 EricMessageBox.information(
4912 self, 4931 self,
4913 self.tr("Autocompletion"), 4932 self.tr("Autocompletion"),
4914 self.tr( 4933 self.tr(
4915 """Autocompletion is not available because""" 4934 """Autocompletion is not available because"""
4916 """ there is no autocompletion source set.""")) 4935 """ there is no autocompletion source set."""
4917 4936 ),
4937 )
4938
4918 def setAutoCompletionEnabled(self, enable): 4939 def setAutoCompletionEnabled(self, enable):
4919 """ 4940 """
4920 Public method to enable/disable autocompletion. 4941 Public method to enable/disable autocompletion.
4921 4942
4922 @param enable flag indicating the desired autocompletion status 4943 @param enable flag indicating the desired autocompletion status
4923 (boolean) 4944 (boolean)
4924 """ 4945 """
4925 if enable: 4946 if enable:
4926 autoCompletionSource = Preferences.getEditor( 4947 autoCompletionSource = Preferences.getEditor("AutoCompletionSource")
4927 "AutoCompletionSource") 4948 if autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsDocument:
4928 if (
4929 autoCompletionSource ==
4930 QsciScintilla.AutoCompletionSource.AcsDocument
4931 ):
4932 self.setAutoCompletionSource( 4949 self.setAutoCompletionSource(
4933 QsciScintilla.AutoCompletionSource.AcsDocument) 4950 QsciScintilla.AutoCompletionSource.AcsDocument
4934 elif ( 4951 )
4935 autoCompletionSource == 4952 elif autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsAPIs:
4936 QsciScintilla.AutoCompletionSource.AcsAPIs 4953 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAPIs)
4937 ):
4938 self.setAutoCompletionSource(
4939 QsciScintilla.AutoCompletionSource.AcsAPIs)
4940 else: 4954 else:
4941 self.setAutoCompletionSource( 4955 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll)
4942 QsciScintilla.AutoCompletionSource.AcsAll) 4956
4943
4944 def __toggleAutoCompletionEnable(self): 4957 def __toggleAutoCompletionEnable(self):
4945 """ 4958 """
4946 Private slot to handle the Enable Autocompletion context menu entry. 4959 Private slot to handle the Enable Autocompletion context menu entry.
4947 """ 4960 """
4948 if self.menuActs["AutoCompletionEnable"].isChecked(): 4961 if self.menuActs["AutoCompletionEnable"].isChecked():
4949 self.setAutoCompletionEnabled(True) 4962 self.setAutoCompletionEnabled(True)
4950 else: 4963 else:
4951 self.setAutoCompletionEnabled(False) 4964 self.setAutoCompletionEnabled(False)
4952 4965
4953 ################################################################# 4966 #################################################################
4954 ## Support for autocompletion hook methods 4967 ## Support for autocompletion hook methods
4955 ################################################################# 4968 #################################################################
4956 4969
4957 def __charAdded(self, charNumber): 4970 def __charAdded(self, charNumber):
4958 """ 4971 """
4959 Private slot called to handle the user entering a character. 4972 Private slot called to handle the user entering a character.
4960 4973
4961 @param charNumber value of the character entered (integer) 4974 @param charNumber value of the character entered (integer)
4962 """ 4975 """
4963 char = chr(charNumber) 4976 char = chr(charNumber)
4964 # update code documentation viewer 4977 # update code documentation viewer
4965 if ( 4978 if char == "(" and Preferences.getDocuViewer("ShowInfoOnOpenParenthesis"):
4966 char == "(" and
4967 Preferences.getDocuViewer("ShowInfoOnOpenParenthesis")
4968 ):
4969 self.vm.showEditorInfo(self) 4979 self.vm.showEditorInfo(self)
4970 4980
4971 self.__delayedDocstringMenuPopup(self.getCursorPosition()) 4981 self.__delayedDocstringMenuPopup(self.getCursorPosition())
4972 4982
4973 if self.isListActive(): 4983 if self.isListActive():
4974 if self.__isStartChar(char): 4984 if self.__isStartChar(char):
4975 self.cancelList() 4985 self.cancelList()
4976 self.autoComplete(auto=True, context=True) 4986 self.autoComplete(auto=True, context=True)
4977 return 4987 return
4978 elif char == '(': 4988 elif char == "(":
4979 self.cancelList() 4989 self.cancelList()
4980 else: 4990 else:
4981 self.__acTimer.stop() 4991 self.__acTimer.stop()
4982 4992
4983 if ( 4993 if (
4984 self.callTipsStyle() != 4994 self.callTipsStyle() != QsciScintilla.CallTipsStyle.CallTipsNone
4985 QsciScintilla.CallTipsStyle.CallTipsNone and 4995 and self.lexer_ is not None
4986 self.lexer_ is not None and chr(charNumber) in '()' 4996 and chr(charNumber) in "()"
4987 ): 4997 ):
4988 self.callTip() 4998 self.callTip()
4989 4999
4990 if not self.isCallTipActive(): 5000 if not self.isCallTipActive():
4991 char = chr(charNumber) 5001 char = chr(charNumber)
4992 if self.__isStartChar(char): 5002 if self.__isStartChar(char):
4993 self.autoComplete(auto=True, context=True) 5003 self.autoComplete(auto=True, context=True)
4994 return 5004 return
4995 5005
4996 line, col = self.getCursorPosition() 5006 line, col = self.getCursorPosition()
4997 txt = self.getWordLeft(line, col) 5007 txt = self.getWordLeft(line, col)
4998 if len(txt) >= Preferences.getEditor("AutoCompletionThreshold"): 5008 if len(txt) >= Preferences.getEditor("AutoCompletionThreshold"):
4999 self.autoComplete(auto=True, context=False) 5009 self.autoComplete(auto=True, context=False)
5000 return 5010 return
5001 5011
5002 def __isStartChar(self, ch): 5012 def __isStartChar(self, ch):
5003 """ 5013 """
5004 Private method to check, if a character is an autocompletion start 5014 Private method to check, if a character is an autocompletion start
5005 character. 5015 character.
5006 5016
5007 @param ch character to be checked (one character string) 5017 @param ch character to be checked (one character string)
5008 @return flag indicating the result (boolean) 5018 @return flag indicating the result (boolean)
5009 """ 5019 """
5010 if self.lexer_ is None: 5020 if self.lexer_ is None:
5011 return False 5021 return False
5012 5022
5013 wseps = self.lexer_.autoCompletionWordSeparators() 5023 wseps = self.lexer_.autoCompletionWordSeparators()
5014 return any(wsep.endswith(ch) for wsep in wseps) 5024 return any(wsep.endswith(ch) for wsep in wseps)
5015 5025
5016 def __autocompletionCancelled(self): 5026 def __autocompletionCancelled(self):
5017 """ 5027 """
5018 Private slot to handle the cancellation of an auto-completion list. 5028 Private slot to handle the cancellation of an auto-completion list.
5019 """ 5029 """
5020 self.__acWatchdog.stop() 5030 self.__acWatchdog.stop()
5021 5031
5022 self.__acText = "" 5032 self.__acText = ""
5023 5033
5024 ################################################################# 5034 #################################################################
5025 ## auto-completion hook interfaces 5035 ## auto-completion hook interfaces
5026 ################################################################# 5036 #################################################################
5027 5037
5028 def addCompletionListHook(self, key, func, asynchroneous=False): 5038 def addCompletionListHook(self, key, func, asynchroneous=False):
5029 """ 5039 """
5030 Public method to set an auto-completion list provider. 5040 Public method to set an auto-completion list provider.
5031 5041
5032 @param key name of the provider 5042 @param key name of the provider
5033 @type str 5043 @type str
5034 @param func function providing completion list. func 5044 @param func function providing completion list. func
5035 should be a function taking a reference to the editor and 5045 should be a function taking a reference to the editor and
5036 a boolean indicating to complete a context. It should return 5046 a boolean indicating to complete a context. It should return
5040 is True 5050 is True
5041 @param asynchroneous flag indicating an asynchroneous function 5051 @param asynchroneous flag indicating an asynchroneous function
5042 @type bool 5052 @type bool
5043 """ 5053 """
5044 if ( 5054 if (
5045 key in self.__completionListHookFunctions or 5055 key in self.__completionListHookFunctions
5046 key in self.__completionListAsyncHookFunctions 5056 or key in self.__completionListAsyncHookFunctions
5047 ): 5057 ):
5048 # it was already registered 5058 # it was already registered
5049 EricMessageBox.warning( 5059 EricMessageBox.warning(
5050 self, 5060 self,
5051 self.tr("Auto-Completion Provider"), 5061 self.tr("Auto-Completion Provider"),
5052 self.tr("""The completion list provider '{0}' was already""" 5062 self.tr(
5053 """ registered. Ignoring duplicate request.""") 5063 """The completion list provider '{0}' was already"""
5054 .format(key)) 5064 """ registered. Ignoring duplicate request."""
5065 ).format(key),
5066 )
5055 return 5067 return
5056 5068
5057 if asynchroneous: 5069 if asynchroneous:
5058 self.__completionListAsyncHookFunctions[key] = func 5070 self.__completionListAsyncHookFunctions[key] = func
5059 else: 5071 else:
5060 self.__completionListHookFunctions[key] = func 5072 self.__completionListHookFunctions[key] = func
5061 5073
5062 def removeCompletionListHook(self, key): 5074 def removeCompletionListHook(self, key):
5063 """ 5075 """
5064 Public method to remove a previously registered completion list 5076 Public method to remove a previously registered completion list
5065 provider. 5077 provider.
5066 5078
5067 @param key name of the provider 5079 @param key name of the provider
5068 @type str 5080 @type str
5069 """ 5081 """
5070 if key in self.__completionListHookFunctions: 5082 if key in self.__completionListHookFunctions:
5071 del self.__completionListHookFunctions[key] 5083 del self.__completionListHookFunctions[key]
5072 elif key in self.__completionListAsyncHookFunctions: 5084 elif key in self.__completionListAsyncHookFunctions:
5073 del self.__completionListAsyncHookFunctions[key] 5085 del self.__completionListAsyncHookFunctions[key]
5074 5086
5075 def getCompletionListHook(self, key): 5087 def getCompletionListHook(self, key):
5076 """ 5088 """
5077 Public method to get the registered completion list provider. 5089 Public method to get the registered completion list provider.
5078 5090
5079 @param key name of the provider 5091 @param key name of the provider
5080 @type str 5092 @type str
5081 @return function providing completion list 5093 @return function providing completion list
5082 @rtype function or None 5094 @rtype function or None
5083 """ 5095 """
5084 return (self.__completionListHookFunctions.get(key) or 5096 return self.__completionListHookFunctions.get(
5085 self.__completionListAsyncHookFunctions.get(key)) 5097 key
5086 5098 ) or self.__completionListAsyncHookFunctions.get(key)
5099
5087 def autoComplete(self, auto=False, context=True): 5100 def autoComplete(self, auto=False, context=True):
5088 """ 5101 """
5089 Public method to start auto-completion. 5102 Public method to start auto-completion.
5090 5103
5091 @param auto flag indicating a call from the __charAdded method 5104 @param auto flag indicating a call from the __charAdded method
5092 (boolean) 5105 (boolean)
5093 @param context flag indicating to complete a context (boolean) 5106 @param context flag indicating to complete a context (boolean)
5094 """ 5107 """
5095 if auto and not Preferences.getEditor("AutoCompletionEnabled"): 5108 if auto and not Preferences.getEditor("AutoCompletionEnabled"):
5096 # auto-completion is disabled 5109 # auto-completion is disabled
5097 return 5110 return
5098 5111
5099 if self.isListActive(): 5112 if self.isListActive():
5100 self.cancelList() 5113 self.cancelList()
5101 5114
5102 if ( 5115 if (
5103 self.__completionListHookFunctions or 5116 self.__completionListHookFunctions
5104 self.__completionListAsyncHookFunctions 5117 or self.__completionListAsyncHookFunctions
5105 ): 5118 ):
5106 # Avoid delayed auto-completion after cursor repositioning 5119 # Avoid delayed auto-completion after cursor repositioning
5107 self.__acText = self.__getAcText() 5120 self.__acText = self.__getAcText()
5108 if auto and Preferences.getEditor("AutoCompletionTimeout"): 5121 if auto and Preferences.getEditor("AutoCompletionTimeout"):
5109 self.__acTimer.stop() 5122 self.__acTimer.stop()
5110 self.__acContext = context 5123 self.__acContext = context
5111 self.__acTimer.start() 5124 self.__acTimer.start()
5112 else: 5125 else:
5113 self.__autoComplete(auto, context) 5126 self.__autoComplete(auto, context)
5114 elif ( 5127 elif not auto or (
5115 not auto or 5128 self.autoCompletionSource() != QsciScintilla.AutoCompletionSource.AcsNone
5116 (self.autoCompletionSource() !=
5117 QsciScintilla.AutoCompletionSource.AcsNone)
5118 ): 5129 ):
5119 self.autoCompleteQScintilla() 5130 self.autoCompleteQScintilla()
5120 5131
5121 def __getAcText(self): 5132 def __getAcText(self):
5122 """ 5133 """
5123 Private method to get the text from cursor position for autocompleting. 5134 Private method to get the text from cursor position for autocompleting.
5124 5135
5125 @return text left of cursor position 5136 @return text left of cursor position
5126 @rtype str 5137 @rtype str
5127 """ 5138 """
5128 line, col = self.getCursorPosition() 5139 line, col = self.getCursorPosition()
5129 text = self.text(line) 5140 text = self.text(line)
5130 try: 5141 try:
5131 acText = ( 5142 acText = (
5132 self.getWordLeft(line, col - 1) + text[col - 1] 5143 self.getWordLeft(line, col - 1) + text[col - 1]
5133 if self.__isStartChar(text[col - 1]) else 5144 if self.__isStartChar(text[col - 1])
5134 self.getWordLeft(line, col) 5145 else self.getWordLeft(line, col)
5135 ) 5146 )
5136 except IndexError: 5147 except IndexError:
5137 acText = "" 5148 acText = ""
5138 5149
5139 return acText 5150 return acText
5140 5151
5141 def __autoComplete(self, auto=True, context=None): 5152 def __autoComplete(self, auto=True, context=None):
5142 """ 5153 """
5143 Private method to start auto-completion via plug-ins. 5154 Private method to start auto-completion via plug-ins.
5144 5155
5145 @param auto flag indicating a call from the __charAdded method 5156 @param auto flag indicating a call from the __charAdded method
5146 (boolean) 5157 (boolean)
5147 @param context flag indicating to complete a context 5158 @param context flag indicating to complete a context
5148 @type bool or None 5159 @type bool or None
5149 """ 5160 """
5150 self.__acCompletions.clear() 5161 self.__acCompletions.clear()
5151 self.__acCompletionsFinished = 0 5162 self.__acCompletionsFinished = 0
5152 5163
5153 # Suppress empty completions 5164 # Suppress empty completions
5154 if auto and self.__acText == '': 5165 if auto and self.__acText == "":
5155 return 5166 return
5156 5167
5157 completions = ( 5168 completions = (
5158 self.__acCache.get(self.__acText) 5169 self.__acCache.get(self.__acText) if self.__acCacheEnabled else None
5159 if self.__acCacheEnabled else
5160 None
5161 ) 5170 )
5162 if completions is not None: 5171 if completions is not None:
5163 # show list with cached entries 5172 # show list with cached entries
5164 if self.isListActive(): 5173 if self.isListActive():
5165 self.cancelList() 5174 self.cancelList()
5166 5175
5167 self.__showCompletionsList(completions) 5176 self.__showCompletionsList(completions)
5168 else: 5177 else:
5169 if context is None: 5178 if context is None:
5170 context = self.__acContext 5179 context = self.__acContext
5171 5180
5172 for key in self.__completionListAsyncHookFunctions: 5181 for key in self.__completionListAsyncHookFunctions:
5173 self.__completionListAsyncHookFunctions[key]( 5182 self.__completionListAsyncHookFunctions[key](
5174 self, context, self.__acText) 5183 self, context, self.__acText
5175 5184 )
5185
5176 for key in self.__completionListHookFunctions: 5186 for key in self.__completionListHookFunctions:
5177 completions = self.__completionListHookFunctions[key]( 5187 completions = self.__completionListHookFunctions[key](self, context)
5178 self, context)
5179 self.completionsListReady(completions, self.__acText) 5188 self.completionsListReady(completions, self.__acText)
5180 5189
5181 if Preferences.getEditor("AutoCompletionScintillaOnFail"): 5190 if Preferences.getEditor("AutoCompletionScintillaOnFail"):
5182 self.__acWatchdog.start() 5191 self.__acWatchdog.start()
5183 5192
5184 def completionsListReady(self, completions, acText): 5193 def completionsListReady(self, completions, acText):
5185 """ 5194 """
5186 Public method to show the completions determined by a completions 5195 Public method to show the completions determined by a completions
5187 provider. 5196 provider.
5188 5197
5189 @param completions list of possible completions 5198 @param completions list of possible completions
5190 @type list of str or set of str 5199 @type list of str or set of str
5191 @param acText text to be completed 5200 @param acText text to be completed
5192 @type str 5201 @type str
5193 """ 5202 """
5194 currentWord = self.__getAcText() or ' ' 5203 currentWord = self.__getAcText() or " "
5195 # process the list only, if not already obsolete ... 5204 # process the list only, if not already obsolete ...
5196 if acText != self.__acText or not self.__acText.endswith(currentWord): 5205 if acText != self.__acText or not self.__acText.endswith(currentWord):
5197 # Suppress auto-completion done by QScintilla as fallback 5206 # Suppress auto-completion done by QScintilla as fallback
5198 self.__acWatchdog.stop() 5207 self.__acWatchdog.stop()
5199 return 5208 return
5200 5209
5201 self.__acCompletions.update(set(completions)) 5210 self.__acCompletions.update(set(completions))
5202 5211
5203 self.__acCompletionsFinished += 1 5212 self.__acCompletionsFinished += 1
5204 # Got all results from auto completer? 5213 # Got all results from auto completer?
5205 if self.__acCompletionsFinished >= ( 5214 if self.__acCompletionsFinished >= (
5206 len(self.__completionListAsyncHookFunctions) + 5215 len(self.__completionListAsyncHookFunctions)
5207 len(self.__completionListHookFunctions) 5216 + len(self.__completionListHookFunctions)
5208 ): 5217 ):
5209 self.__acWatchdog.stop() 5218 self.__acWatchdog.stop()
5210 5219
5211 # Autocomplete with QScintilla if no results present 5220 # Autocomplete with QScintilla if no results present
5212 if ( 5221 if (
5213 Preferences.getEditor("AutoCompletionScintillaOnFail") and 5222 Preferences.getEditor("AutoCompletionScintillaOnFail")
5214 not self.__acCompletions 5223 and not self.__acCompletions
5215 ): 5224 ):
5216 self.autoCompleteQScintilla() 5225 self.autoCompleteQScintilla()
5217 return 5226 return
5218 5227
5219 # ... or completions are not empty 5228 # ... or completions are not empty
5220 if not bool(completions): 5229 if not bool(completions):
5221 return 5230 return
5222 5231
5223 if self.isListActive(): 5232 if self.isListActive():
5224 self.cancelList() 5233 self.cancelList()
5225 5234
5226 if self.__acCompletions: 5235 if self.__acCompletions:
5227 if self.__acCacheEnabled: 5236 if self.__acCacheEnabled:
5228 self.__acCache.add(acText, set(self.__acCompletions)) 5237 self.__acCache.add(acText, set(self.__acCompletions))
5229 self.__showCompletionsList(self.__acCompletions) 5238 self.__showCompletionsList(self.__acCompletions)
5230 5239
5231 def __showCompletionsList(self, completions): 5240 def __showCompletionsList(self, completions):
5232 """ 5241 """
5233 Private method to show the completions list. 5242 Private method to show the completions list.
5234 5243
5235 @param completions completions to be shown 5244 @param completions completions to be shown
5236 @type list of str or set of str 5245 @type list of str or set of str
5237 """ 5246 """
5238 acCompletions = ( 5247 acCompletions = (
5239 sorted(completions, 5248 sorted(completions, key=self.__replaceLeadingUnderscores)
5240 key=self.__replaceLeadingUnderscores) 5249 if Preferences.getEditor("AutoCompletionReversedList")
5241 if Preferences.getEditor("AutoCompletionReversedList") else 5250 else sorted(completions)
5242 sorted(completions)
5243 ) 5251 )
5244 self.showUserList(EditorAutoCompletionListID, acCompletions) 5252 self.showUserList(EditorAutoCompletionListID, acCompletions)
5245 5253
5246 def __replaceLeadingUnderscores(self, txt): 5254 def __replaceLeadingUnderscores(self, txt):
5247 """ 5255 """
5248 Private method to replace the first two underlines for invers sorting. 5256 Private method to replace the first two underlines for invers sorting.
5249 5257
5250 @param txt completion text 5258 @param txt completion text
5251 @type str 5259 @type str
5252 @return modified completion text 5260 @return modified completion text
5253 @rtype str 5261 @rtype str
5254 """ 5262 """
5255 if txt.startswith('_'): 5263 if txt.startswith("_"):
5256 return txt[:2].replace('_', '~') + txt[2:] 5264 return txt[:2].replace("_", "~") + txt[2:]
5257 else: 5265 else:
5258 return txt 5266 return txt
5259 5267
5260 def __clearCompletionsCache(self): 5268 def __clearCompletionsCache(self):
5261 """ 5269 """
5262 Private method to clear the auto-completions cache. 5270 Private method to clear the auto-completions cache.
5263 """ 5271 """
5264 self.__acCache.clear() 5272 self.__acCache.clear()
5265 5273
5266 def __completionListSelected(self, listId, txt): 5274 def __completionListSelected(self, listId, txt):
5267 """ 5275 """
5268 Private slot to handle the selection from the completion list. 5276 Private slot to handle the selection from the completion list.
5269 5277
5270 @param listId the ID of the user list (should be 1 or 2) (integer) 5278 @param listId the ID of the user list (should be 1 or 2) (integer)
5271 @param txt the selected text (string) 5279 @param txt the selected text (string)
5272 """ 5280 """
5273 # custom completions via plug-ins 5281 # custom completions via plug-ins
5274 if listId == EditorAutoCompletionListID: 5282 if listId == EditorAutoCompletionListID:
5275 lst = txt.split() 5283 lst = txt.split()
5276 if len(lst) > 1: 5284 if len(lst) > 1:
5277 txt = lst[0] 5285 txt = lst[0]
5278 5286
5279 self.beginUndoAction() 5287 self.beginUndoAction()
5280 if Preferences.getEditor("AutoCompletionReplaceWord"): 5288 if Preferences.getEditor("AutoCompletionReplaceWord"):
5281 self.selectCurrentWord() 5289 self.selectCurrentWord()
5282 self.removeSelectedText() 5290 self.removeSelectedText()
5283 line, col = self.getCursorPosition() 5291 line, col = self.getCursorPosition()
5287 if not txt.startswith(wLeft): 5295 if not txt.startswith(wLeft):
5288 self.selectCurrentWord() 5296 self.selectCurrentWord()
5289 self.removeSelectedText() 5297 self.removeSelectedText()
5290 line, col = self.getCursorPosition() 5298 line, col = self.getCursorPosition()
5291 elif wLeft: 5299 elif wLeft:
5292 txt = txt[len(wLeft):] 5300 txt = txt[len(wLeft) :]
5293 5301
5294 if txt and txt[0] in "'\"": 5302 if txt and txt[0] in "'\"":
5295 # New in jedi 0.16: AC of dict keys 5303 # New in jedi 0.16: AC of dict keys
5296 txt = txt[1:] 5304 txt = txt[1:]
5297 self.insert(txt) 5305 self.insert(txt)
5298 self.endUndoAction() 5306 self.endUndoAction()
5299 self.setCursorPosition(line, col + len(txt)) 5307 self.setCursorPosition(line, col + len(txt))
5300 5308
5301 # template completions 5309 # template completions
5302 elif listId == TemplateCompletionListID: 5310 elif listId == TemplateCompletionListID:
5303 self.__applyTemplate(txt, self.getLanguage()) 5311 self.__applyTemplate(txt, self.getLanguage())
5304 5312
5305 # 'goto reference' completions 5313 # 'goto reference' completions
5306 elif listId == ReferencesListID: 5314 elif listId == ReferencesListID:
5307 with contextlib.suppress(ValueError, IndexError): 5315 with contextlib.suppress(ValueError, IndexError):
5308 index = self.__referencesList.index(txt) 5316 index = self.__referencesList.index(txt)
5309 filename, line, column = self.__referencesPositionsList[index] 5317 filename, line, column = self.__referencesPositionsList[index]
5310 self.vm.openSourceFile( 5318 self.vm.openSourceFile(filename, lineno=line, pos=column, addNext=True)
5311 filename, lineno=line, pos=column, addNext=True) 5319
5312
5313 def canProvideDynamicAutoCompletion(self): 5320 def canProvideDynamicAutoCompletion(self):
5314 """ 5321 """
5315 Public method to test the dynamic auto-completion availability. 5322 Public method to test the dynamic auto-completion availability.
5316 5323
5317 @return flag indicating the availability of dynamic auto-completion 5324 @return flag indicating the availability of dynamic auto-completion
5318 (boolean) 5325 (boolean)
5319 """ 5326 """
5320 return (self.acAPI or 5327 return (
5321 bool(self.__completionListHookFunctions) or 5328 self.acAPI
5322 bool(self.__completionListAsyncHookFunctions)) 5329 or bool(self.__completionListHookFunctions)
5323 5330 or bool(self.__completionListAsyncHookFunctions)
5331 )
5332
5324 ################################################################# 5333 #################################################################
5325 ## call-tip hook interfaces 5334 ## call-tip hook interfaces
5326 ################################################################# 5335 #################################################################
5327 5336
5328 def addCallTipHook(self, key, func): 5337 def addCallTipHook(self, key, func):
5329 """ 5338 """
5330 Public method to set a calltip provider. 5339 Public method to set a calltip provider.
5331 5340
5332 @param key name of the provider 5341 @param key name of the provider
5333 @type str 5342 @type str
5334 @param func function providing calltips. func 5343 @param func function providing calltips. func
5335 should be a function taking a reference to the editor, 5344 should be a function taking a reference to the editor,
5336 a position into the text and the amount of commas to the 5345 a position into the text and the amount of commas to the
5341 if key in self.__ctHookFunctions: 5350 if key in self.__ctHookFunctions:
5342 # it was already registered 5351 # it was already registered
5343 EricMessageBox.warning( 5352 EricMessageBox.warning(
5344 self, 5353 self,
5345 self.tr("Call-Tips Provider"), 5354 self.tr("Call-Tips Provider"),
5346 self.tr("""The call-tips provider '{0}' was already""" 5355 self.tr(
5347 """ registered. Ignoring duplicate request.""") 5356 """The call-tips provider '{0}' was already"""
5348 .format(key)) 5357 """ registered. Ignoring duplicate request."""
5358 ).format(key),
5359 )
5349 return 5360 return
5350 5361
5351 self.__ctHookFunctions[key] = func 5362 self.__ctHookFunctions[key] = func
5352 5363
5353 def removeCallTipHook(self, key): 5364 def removeCallTipHook(self, key):
5354 """ 5365 """
5355 Public method to remove a previously registered calltip provider. 5366 Public method to remove a previously registered calltip provider.
5356 5367
5357 @param key name of the provider 5368 @param key name of the provider
5358 @type str 5369 @type str
5359 """ 5370 """
5360 if key in self.__ctHookFunctions: 5371 if key in self.__ctHookFunctions:
5361 del self.__ctHookFunctions[key] 5372 del self.__ctHookFunctions[key]
5362 5373
5363 def getCallTipHook(self, key): 5374 def getCallTipHook(self, key):
5364 """ 5375 """
5365 Public method to get the registered calltip provider. 5376 Public method to get the registered calltip provider.
5366 5377
5367 @param key name of the provider 5378 @param key name of the provider
5368 @type str 5379 @type str
5369 @return function providing calltips 5380 @return function providing calltips
5370 @rtype function or None 5381 @rtype function or None
5371 """ 5382 """
5372 if key in self.__ctHookFunctions: 5383 if key in self.__ctHookFunctions:
5373 return self.__ctHookFunctions[key] 5384 return self.__ctHookFunctions[key]
5374 else: 5385 else:
5375 return None 5386 return None
5376 5387
5377 def canProvideCallTipps(self): 5388 def canProvideCallTipps(self):
5378 """ 5389 """
5379 Public method to test the calltips availability. 5390 Public method to test the calltips availability.
5380 5391
5381 @return flag indicating the availability of calltips (boolean) 5392 @return flag indicating the availability of calltips (boolean)
5382 """ 5393 """
5383 return (self.acAPI or 5394 return self.acAPI or bool(self.__ctHookFunctions)
5384 bool(self.__ctHookFunctions)) 5395
5385
5386 def callTip(self): 5396 def callTip(self):
5387 """ 5397 """
5388 Public method to show calltips. 5398 Public method to show calltips.
5389 """ 5399 """
5390 if bool(self.__ctHookFunctions): 5400 if bool(self.__ctHookFunctions):
5391 self.__callTip() 5401 self.__callTip()
5392 else: 5402 else:
5393 super().callTip() 5403 super().callTip()
5394 5404
5395 def __callTip(self): 5405 def __callTip(self):
5396 """ 5406 """
5397 Private method to show call tips provided by a plugin. 5407 Private method to show call tips provided by a plugin.
5398 """ 5408 """
5399 pos = self.currentPosition() 5409 pos = self.currentPosition()
5400 5410
5401 # move backward to the start of the current calltip working out 5411 # move backward to the start of the current calltip working out
5402 # which argument to highlight 5412 # which argument to highlight
5403 commas = 0 5413 commas = 0
5404 found = False 5414 found = False
5405 ch, pos = self.__getCharacter(pos) 5415 ch, pos = self.__getCharacter(pos)
5406 while ch: 5416 while ch:
5407 if ch == ',': 5417 if ch == ",":
5408 commas += 1 5418 commas += 1
5409 elif ch == ')': 5419 elif ch == ")":
5410 depth = 1 5420 depth = 1
5411 5421
5412 # ignore everything back to the start of the corresponding 5422 # ignore everything back to the start of the corresponding
5413 # parenthesis 5423 # parenthesis
5414 ch, pos = self.__getCharacter(pos) 5424 ch, pos = self.__getCharacter(pos)
5415 while ch: 5425 while ch:
5416 if ch == ')': 5426 if ch == ")":
5417 depth += 1 5427 depth += 1
5418 elif ch == '(': 5428 elif ch == "(":
5419 depth -= 1 5429 depth -= 1
5420 if depth == 0: 5430 if depth == 0:
5421 break 5431 break
5422 ch, pos = self.__getCharacter(pos) 5432 ch, pos = self.__getCharacter(pos)
5423 elif ch == '(': 5433 elif ch == "(":
5424 found = True 5434 found = True
5425 break 5435 break
5426 5436
5427 ch, pos = self.__getCharacter(pos) 5437 ch, pos = self.__getCharacter(pos)
5428 5438
5429 self.cancelCallTips() 5439 self.cancelCallTips()
5430 5440
5431 if not found: 5441 if not found:
5432 return 5442 return
5433 5443
5434 callTips = [] 5444 callTips = []
5435 if self.__ctHookFunctions: 5445 if self.__ctHookFunctions:
5436 for key in self.__ctHookFunctions: 5446 for key in self.__ctHookFunctions:
5437 callTips.extend(self.__ctHookFunctions[key](self, pos, commas)) 5447 callTips.extend(self.__ctHookFunctions[key](self, pos, commas))
5438 callTips = list(set(callTips)) 5448 callTips = list(set(callTips))
5444 if len(callTips) == 0: 5454 if len(callTips) == 0:
5445 if Preferences.getEditor("CallTipsScintillaOnFail"): 5455 if Preferences.getEditor("CallTipsScintillaOnFail"):
5446 # try QScintilla calltips 5456 # try QScintilla calltips
5447 super().callTip() 5457 super().callTip()
5448 return 5458 return
5449 5459
5450 ctshift = 0 5460 ctshift = 0
5451 for ct in callTips: 5461 for ct in callTips:
5452 shift = ct.index("(") 5462 shift = ct.index("(")
5453 if ctshift < shift: 5463 if ctshift < shift:
5454 ctshift = shift 5464 ctshift = shift
5455 5465
5456 cv = self.callTipsVisible() 5466 cv = self.callTipsVisible()
5457 ct = ( 5467 ct = (
5458 # this is just a safe guard 5468 # this is just a safe guard
5459 self._encodeString("\n".join(callTips[:cv])) 5469 self._encodeString("\n".join(callTips[:cv]))
5460 if cv > 0 else 5470 if cv > 0
5471 else
5461 # until here and unindent below 5472 # until here and unindent below
5462 self._encodeString("\n".join(callTips)) 5473 self._encodeString("\n".join(callTips))
5463 ) 5474 )
5464 5475
5465 self.SendScintilla(QsciScintilla.SCI_CALLTIPSHOW, 5476 self.SendScintilla(
5466 self.__adjustedCallTipPosition(ctshift, pos), ct) 5477 QsciScintilla.SCI_CALLTIPSHOW,
5467 if b'\n' in ct: 5478 self.__adjustedCallTipPosition(ctshift, pos),
5479 ct,
5480 )
5481 if b"\n" in ct:
5468 return 5482 return
5469 5483
5470 # Highlight the current argument 5484 # Highlight the current argument
5471 if commas == 0: 5485 if commas == 0:
5472 astart = ct.find(b'(') 5486 astart = ct.find(b"(")
5473 else: 5487 else:
5474 astart = ct.find(b',') 5488 astart = ct.find(b",")
5475 commas -= 1 5489 commas -= 1
5476 while astart != -1 and commas > 0: 5490 while astart != -1 and commas > 0:
5477 astart = ct.find(b',', astart + 1) 5491 astart = ct.find(b",", astart + 1)
5478 commas -= 1 5492 commas -= 1
5479 5493
5480 if astart == -1: 5494 if astart == -1:
5481 return 5495 return
5482 5496
5483 depth = 0 5497 depth = 0
5484 for aend in range(astart + 1, len(ct)): 5498 for aend in range(astart + 1, len(ct)):
5485 ch = ct[aend:aend + 1] 5499 ch = ct[aend : aend + 1]
5486 5500
5487 if ch == b',' and depth == 0: 5501 if ch == b"," and depth == 0:
5488 break 5502 break
5489 elif ch == b'(': 5503 elif ch == b"(":
5490 depth += 1 5504 depth += 1
5491 elif ch == b')': 5505 elif ch == b")":
5492 if depth == 0: 5506 if depth == 0:
5493 break 5507 break
5494 5508
5495 depth -= 1 5509 depth -= 1
5496 5510
5497 if astart != aend: 5511 if astart != aend:
5498 self.SendScintilla(QsciScintilla.SCI_CALLTIPSETHLT, 5512 self.SendScintilla(QsciScintilla.SCI_CALLTIPSETHLT, astart + 1, aend)
5499 astart + 1, aend) 5513
5500
5501 def __adjustedCallTipPosition(self, ctshift, pos): 5514 def __adjustedCallTipPosition(self, ctshift, pos):
5502 """ 5515 """
5503 Private method to calculate an adjusted position for showing calltips. 5516 Private method to calculate an adjusted position for showing calltips.
5504 5517
5505 @param ctshift amount the calltip shall be shifted (integer) 5518 @param ctshift amount the calltip shall be shifted (integer)
5506 @param pos position into the text (integer) 5519 @param pos position into the text (integer)
5507 @return new position for the calltip (integer) 5520 @return new position for the calltip (integer)
5508 """ 5521 """
5509 ct = pos 5522 ct = pos
5510 if ctshift: 5523 if ctshift:
5511 ctmin = self.SendScintilla( 5524 ctmin = self.SendScintilla(
5512 QsciScintilla.SCI_POSITIONFROMLINE, 5525 QsciScintilla.SCI_POSITIONFROMLINE,
5513 self.SendScintilla(QsciScintilla.SCI_LINEFROMPOSITION, ct)) 5526 self.SendScintilla(QsciScintilla.SCI_LINEFROMPOSITION, ct),
5527 )
5514 if ct - ctshift < ctmin: 5528 if ct - ctshift < ctmin:
5515 ct = ctmin 5529 ct = ctmin
5516 else: 5530 else:
5517 ct -= ctshift 5531 ct -= ctshift
5518 return ct 5532 return ct
5519 5533
5520 ################################################################# 5534 #################################################################
5521 ## Methods needed by the code documentation viewer 5535 ## Methods needed by the code documentation viewer
5522 ################################################################# 5536 #################################################################
5523 5537
5524 def __showCodeInfo(self): 5538 def __showCodeInfo(self):
5525 """ 5539 """
5526 Private slot to handle the context menu action to show code info. 5540 Private slot to handle the context menu action to show code info.
5527 """ 5541 """
5528 self.vm.showEditorInfo(self) 5542 self.vm.showEditorInfo(self)
5529 5543
5530 ################################################################# 5544 #################################################################
5531 ## Methods needed by the context menu 5545 ## Methods needed by the context menu
5532 ################################################################# 5546 #################################################################
5533 5547
5534 def __marginNumber(self, xPos): 5548 def __marginNumber(self, xPos):
5535 """ 5549 """
5536 Private method to calculate the margin number based on a x position. 5550 Private method to calculate the margin number based on a x position.
5537 5551
5538 @param xPos x position (integer) 5552 @param xPos x position (integer)
5539 @return margin number (integer, -1 for no margin) 5553 @return margin number (integer, -1 for no margin)
5540 """ 5554 """
5541 width = 0 5555 width = 0
5542 for margin in range(5): 5556 for margin in range(5):
5543 width += self.marginWidth(margin) 5557 width += self.marginWidth(margin)
5544 if xPos <= width: 5558 if xPos <= width:
5545 return margin 5559 return margin
5546 return -1 5560 return -1
5547 5561
5548 def contextMenuEvent(self, evt): 5562 def contextMenuEvent(self, evt):
5549 """ 5563 """
5550 Protected method implementing the context menu event. 5564 Protected method implementing the context menu event.
5551 5565
5552 @param evt the context menu event (QContextMenuEvent) 5566 @param evt the context menu event (QContextMenuEvent)
5553 """ 5567 """
5554 evt.accept() 5568 evt.accept()
5555 if self.__marginNumber(evt.x()) == -1: 5569 if self.__marginNumber(evt.x()) == -1:
5556 self.spellingMenuPos = self.positionFromPoint(evt.pos()) 5570 self.spellingMenuPos = self.positionFromPoint(evt.pos())
5557 if ( 5571 if (
5558 self.spellingMenuPos >= 0 and 5572 self.spellingMenuPos >= 0
5559 self.spell is not None and 5573 and self.spell is not None
5560 self.hasIndicator(self.spellingIndicator, 5574 and self.hasIndicator(self.spellingIndicator, self.spellingMenuPos)
5561 self.spellingMenuPos)
5562 ): 5575 ):
5563 self.spellingMenu.popup(evt.globalPos()) 5576 self.spellingMenu.popup(evt.globalPos())
5564 else: 5577 else:
5565 self.menu.popup(evt.globalPos()) 5578 self.menu.popup(evt.globalPos())
5566 else: 5579 else:
5567 self.line = self.lineAt(evt.pos()) 5580 self.line = self.lineAt(evt.pos())
5568 if self.__marginNumber(evt.x()) in [self.__bmMargin, 5581 if self.__marginNumber(evt.x()) in [self.__bmMargin, self.__linenoMargin]:
5569 self.__linenoMargin]:
5570 self.bmMarginMenu.popup(evt.globalPos()) 5582 self.bmMarginMenu.popup(evt.globalPos())
5571 elif self.__marginNumber(evt.x()) == self.__bpMargin: 5583 elif self.__marginNumber(evt.x()) == self.__bpMargin:
5572 self.bpMarginMenu.popup(evt.globalPos()) 5584 self.bpMarginMenu.popup(evt.globalPos())
5573 elif self.__marginNumber(evt.x()) == self.__indicMargin: 5585 elif self.__marginNumber(evt.x()) == self.__indicMargin:
5574 self.indicMarginMenu.popup(evt.globalPos()) 5586 self.indicMarginMenu.popup(evt.globalPos())
5575 elif self.__marginNumber(evt.x()) == self.__foldMargin: 5587 elif self.__marginNumber(evt.x()) == self.__foldMargin:
5576 self.foldMarginMenu.popup(evt.globalPos()) 5588 self.foldMarginMenu.popup(evt.globalPos())
5577 5589
5578 def __showContextMenu(self): 5590 def __showContextMenu(self):
5579 """ 5591 """
5580 Private slot handling the aboutToShow signal of the context menu. 5592 Private slot handling the aboutToShow signal of the context menu.
5581 """ 5593 """
5582 self.menuActs["Reopen"].setEnabled( 5594 self.menuActs["Reopen"].setEnabled(
5583 not self.isModified() and bool(self.fileName)) 5595 not self.isModified() and bool(self.fileName)
5596 )
5584 self.menuActs["Save"].setEnabled(self.isModified()) 5597 self.menuActs["Save"].setEnabled(self.isModified())
5585 self.menuActs["Undo"].setEnabled(self.isUndoAvailable()) 5598 self.menuActs["Undo"].setEnabled(self.isUndoAvailable())
5586 self.menuActs["Redo"].setEnabled(self.isRedoAvailable()) 5599 self.menuActs["Redo"].setEnabled(self.isRedoAvailable())
5587 self.menuActs["Revert"].setEnabled(self.isModified()) 5600 self.menuActs["Revert"].setEnabled(self.isModified())
5588 self.menuActs["Cut"].setEnabled(self.hasSelectedText()) 5601 self.menuActs["Cut"].setEnabled(self.hasSelectedText())
5589 self.menuActs["Copy"].setEnabled(self.hasSelectedText()) 5602 self.menuActs["Copy"].setEnabled(self.hasSelectedText())
5590 if self.menuActs["ExecuteSelection"] is not None: 5603 if self.menuActs["ExecuteSelection"] is not None:
5591 self.menuActs["ExecuteSelection"].setEnabled( 5604 self.menuActs["ExecuteSelection"].setEnabled(self.hasSelectedText())
5592 self.hasSelectedText())
5593 self.menuActs["Paste"].setEnabled(self.canPaste()) 5605 self.menuActs["Paste"].setEnabled(self.canPaste())
5594 if not self.isResourcesFile: 5606 if not self.isResourcesFile:
5595 if self.fileName and self.isPyFile(): 5607 if self.fileName and self.isPyFile():
5596 self.menuActs["Show"].setEnabled(True) 5608 self.menuActs["Show"].setEnabled(True)
5597 else: 5609 else:
5598 self.menuActs["Show"].setEnabled(False) 5610 self.menuActs["Show"].setEnabled(False)
5599 if ( 5611 if self.fileName and (self.isPyFile() or self.isRubyFile()):
5600 self.fileName and
5601 (self.isPyFile() or self.isRubyFile())
5602 ):
5603 self.menuActs["Diagrams"].setEnabled(True) 5612 self.menuActs["Diagrams"].setEnabled(True)
5604 else: 5613 else:
5605 self.menuActs["Diagrams"].setEnabled(False) 5614 self.menuActs["Diagrams"].setEnabled(False)
5606 if not self.miniMenu: 5615 if not self.miniMenu:
5607 if self.lexer_ is not None: 5616 if self.lexer_ is not None:
5608 self.menuActs["Comment"].setEnabled( 5617 self.menuActs["Comment"].setEnabled(self.lexer_.canBlockComment())
5609 self.lexer_.canBlockComment()) 5618 self.menuActs["Uncomment"].setEnabled(self.lexer_.canBlockComment())
5610 self.menuActs["Uncomment"].setEnabled(
5611 self.lexer_.canBlockComment())
5612 else: 5619 else:
5613 self.menuActs["Comment"].setEnabled(False) 5620 self.menuActs["Comment"].setEnabled(False)
5614 self.menuActs["Uncomment"].setEnabled(False) 5621 self.menuActs["Uncomment"].setEnabled(False)
5615 5622
5616 cline = self.getCursorPosition()[0] 5623 cline = self.getCursorPosition()[0]
5617 line = self.text(cline) 5624 line = self.text(cline)
5618 self.menuActs["Docstring"].setEnabled( 5625 self.menuActs["Docstring"].setEnabled(
5619 self.getDocstringGenerator().isFunctionStart(line)) 5626 self.getDocstringGenerator().isFunctionStart(line)
5620 5627 )
5621 self.menuActs["TypingAidsEnabled"].setEnabled( 5628
5622 self.completer is not None) 5629 self.menuActs["TypingAidsEnabled"].setEnabled(self.completer is not None)
5623 self.menuActs["TypingAidsEnabled"].setChecked( 5630 self.menuActs["TypingAidsEnabled"].setChecked(
5624 self.completer is not None and self.completer.isEnabled()) 5631 self.completer is not None and self.completer.isEnabled()
5625 5632 )
5633
5626 if not self.isResourcesFile: 5634 if not self.isResourcesFile:
5627 self.menuActs["calltip"].setEnabled(self.canProvideCallTipps()) 5635 self.menuActs["calltip"].setEnabled(self.canProvideCallTipps())
5628 self.menuActs["codeInfo"].setEnabled( 5636 self.menuActs["codeInfo"].setEnabled(
5629 self.vm.isEditorInfoSupported(self.getLanguage())) 5637 self.vm.isEditorInfoSupported(self.getLanguage())
5630 5638 )
5639
5631 self.menuActs["MonospacedFont"].setEnabled(self.lexer_ is None) 5640 self.menuActs["MonospacedFont"].setEnabled(self.lexer_ is None)
5632 5641
5633 splitOrientation = self.vm.getSplitOrientation() 5642 splitOrientation = self.vm.getSplitOrientation()
5634 if splitOrientation == Qt.Orientation.Horizontal: 5643 if splitOrientation == Qt.Orientation.Horizontal:
5635 self.menuActs["NewSplit"].setIcon( 5644 self.menuActs["NewSplit"].setIcon(UI.PixmapCache.getIcon("splitHorizontal"))
5636 UI.PixmapCache.getIcon("splitHorizontal")) 5645 else:
5637 else: 5646 self.menuActs["NewSplit"].setIcon(UI.PixmapCache.getIcon("splitVertical"))
5638 self.menuActs["NewSplit"].setIcon( 5647
5639 UI.PixmapCache.getIcon("splitVertical"))
5640
5641 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty()) 5648 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty())
5642 5649
5643 self.showMenu.emit("Main", self.menu, self) 5650 self.showMenu.emit("Main", self.menu, self)
5644 5651
5645 def __showContextMenuAutocompletion(self): 5652 def __showContextMenuAutocompletion(self):
5646 """ 5653 """
5647 Private slot called before the autocompletion menu is shown. 5654 Private slot called before the autocompletion menu is shown.
5648 """ 5655 """
5649 self.menuActs["acDynamic"].setEnabled( 5656 self.menuActs["acDynamic"].setEnabled(self.canProvideDynamicAutoCompletion())
5650 self.canProvideDynamicAutoCompletion()) 5657 self.menuActs["acClearCache"].setEnabled(self.canProvideDynamicAutoCompletion())
5651 self.menuActs["acClearCache"].setEnabled(
5652 self.canProvideDynamicAutoCompletion())
5653 self.menuActs["acAPI"].setEnabled(self.acAPI) 5658 self.menuActs["acAPI"].setEnabled(self.acAPI)
5654 self.menuActs["acAPIDocument"].setEnabled(self.acAPI) 5659 self.menuActs["acAPIDocument"].setEnabled(self.acAPI)
5655 5660
5656 self.showMenu.emit("Autocompletion", self.autocompletionMenu, self) 5661 self.showMenu.emit("Autocompletion", self.autocompletionMenu, self)
5657 5662
5658 def __showContextMenuShow(self): 5663 def __showContextMenuShow(self):
5659 """ 5664 """
5660 Private slot called before the show menu is shown. 5665 Private slot called before the show menu is shown.
5661 """ 5666 """
5662 prEnable = False 5667 prEnable = False
5663 coEnable = False 5668 coEnable = False
5664 5669
5665 # first check if the file belongs to a project 5670 # first check if the file belongs to a project
5666 if ( 5671 if self.project.isOpen() and self.project.isProjectSource(self.fileName):
5667 self.project.isOpen() and
5668 self.project.isProjectSource(self.fileName)
5669 ):
5670 fn = self.project.getMainScript(True) 5672 fn = self.project.getMainScript(True)
5671 if fn is not None: 5673 if fn is not None:
5672 prEnable = ( 5674 prEnable = self.project.isPy3Project() and bool(
5673 self.project.isPy3Project() and 5675 Utilities.getProfileFileNames(fn)
5674 bool(Utilities.getProfileFileNames(fn))
5675 ) 5676 )
5676 coEnable = ( 5677 coEnable = self.project.isPy3Project() and bool(
5677 self.project.isPy3Project() and 5678 Utilities.getCoverageFileNames(fn)
5678 bool(Utilities.getCoverageFileNames(fn))
5679 ) 5679 )
5680 5680
5681 # now check ourselves 5681 # now check ourselves
5682 fn = self.getFileName() 5682 fn = self.getFileName()
5683 if fn is not None: 5683 if fn is not None:
5684 prEnable |= ( 5684 prEnable |= self.project.isPy3Project() and bool(
5685 self.project.isPy3Project() and 5685 Utilities.getProfileFileName(fn)
5686 bool(Utilities.getProfileFileName(fn)) 5686 )
5687 ) 5687 coEnable |= self.project.isPy3Project() and bool(
5688 coEnable |= ( 5688 Utilities.getCoverageFileName(fn)
5689 self.project.isPy3Project() and 5689 )
5690 bool(Utilities.getCoverageFileName(fn)) 5690
5691 )
5692
5693 coEnable |= bool(self.__coverageFile) 5691 coEnable |= bool(self.__coverageFile)
5694 5692
5695 # now check for syntax errors 5693 # now check for syntax errors
5696 if self.hasSyntaxErrors(): 5694 if self.hasSyntaxErrors():
5697 coEnable = False 5695 coEnable = False
5698 5696
5699 self.profileMenuAct.setEnabled(prEnable) 5697 self.profileMenuAct.setEnabled(prEnable)
5700 self.coverageMenuAct.setEnabled(coEnable) 5698 self.coverageMenuAct.setEnabled(coEnable)
5701 self.coverageShowAnnotationMenuAct.setEnabled( 5699 self.coverageShowAnnotationMenuAct.setEnabled(
5702 coEnable and len(self.notcoveredMarkers) == 0) 5700 coEnable and len(self.notcoveredMarkers) == 0
5703 self.coverageHideAnnotationMenuAct.setEnabled( 5701 )
5704 len(self.notcoveredMarkers) > 0) 5702 self.coverageHideAnnotationMenuAct.setEnabled(len(self.notcoveredMarkers) > 0)
5705 5703
5706 self.showMenu.emit("Show", self.menuShow, self) 5704 self.showMenu.emit("Show", self.menuShow, self)
5707 5705
5708 def __showContextMenuGraphics(self): 5706 def __showContextMenuGraphics(self):
5709 """ 5707 """
5710 Private slot handling the aboutToShow signal of the diagrams context 5708 Private slot handling the aboutToShow signal of the diagrams context
5711 menu. 5709 menu.
5712 """ 5710 """
5713 if ( 5711 if self.project.isOpen() and self.project.isProjectSource(self.fileName):
5714 self.project.isOpen() and
5715 self.project.isProjectSource(self.fileName)
5716 ):
5717 self.applicationDiagramMenuAct.setEnabled(True) 5712 self.applicationDiagramMenuAct.setEnabled(True)
5718 else: 5713 else:
5719 self.applicationDiagramMenuAct.setEnabled(False) 5714 self.applicationDiagramMenuAct.setEnabled(False)
5720 5715
5721 self.showMenu.emit("Graphics", self.graphicsMenu, self) 5716 self.showMenu.emit("Graphics", self.graphicsMenu, self)
5722 5717
5723 def __showContextMenuMargin(self, menu): 5718 def __showContextMenuMargin(self, menu):
5724 """ 5719 """
5725 Private slot handling the aboutToShow signal of the margins context 5720 Private slot handling the aboutToShow signal of the margins context
5726 menu. 5721 menu.
5727 5722
5728 @param menu reference to the menu to be shown 5723 @param menu reference to the menu to be shown
5729 @type QMenu 5724 @type QMenu
5730 """ 5725 """
5731 if menu is self.bpMarginMenu: 5726 if menu is self.bpMarginMenu:
5732 supportsDebugger = bool(self.fileName and self.isPyFile()) 5727 supportsDebugger = bool(self.fileName and self.isPyFile())
5733 hasBreakpoints = bool(self.breaks) 5728 hasBreakpoints = bool(self.breaks)
5734 hasBreakpoint = bool( 5729 hasBreakpoint = bool(self.markersAtLine(self.line) & self.breakpointMask)
5735 self.markersAtLine(self.line) & self.breakpointMask) 5730
5736
5737 self.marginMenuActs["Breakpoint"].setEnabled(supportsDebugger) 5731 self.marginMenuActs["Breakpoint"].setEnabled(supportsDebugger)
5738 self.marginMenuActs["TempBreakpoint"].setEnabled(supportsDebugger) 5732 self.marginMenuActs["TempBreakpoint"].setEnabled(supportsDebugger)
5739 self.marginMenuActs["NextBreakpoint"].setEnabled( 5733 self.marginMenuActs["NextBreakpoint"].setEnabled(
5740 supportsDebugger and hasBreakpoints) 5734 supportsDebugger and hasBreakpoints
5735 )
5741 self.marginMenuActs["PreviousBreakpoint"].setEnabled( 5736 self.marginMenuActs["PreviousBreakpoint"].setEnabled(
5742 supportsDebugger and hasBreakpoints) 5737 supportsDebugger and hasBreakpoints
5738 )
5743 self.marginMenuActs["ClearBreakpoint"].setEnabled( 5739 self.marginMenuActs["ClearBreakpoint"].setEnabled(
5744 supportsDebugger and hasBreakpoints) 5740 supportsDebugger and hasBreakpoints
5741 )
5745 self.marginMenuActs["EditBreakpoint"].setEnabled( 5742 self.marginMenuActs["EditBreakpoint"].setEnabled(
5746 supportsDebugger and hasBreakpoint) 5743 supportsDebugger and hasBreakpoint
5744 )
5747 self.marginMenuActs["EnableBreakpoint"].setEnabled( 5745 self.marginMenuActs["EnableBreakpoint"].setEnabled(
5748 supportsDebugger and hasBreakpoint) 5746 supportsDebugger and hasBreakpoint
5747 )
5749 if supportsDebugger: 5748 if supportsDebugger:
5750 if self.markersAtLine(self.line) & (1 << self.dbreakpoint): 5749 if self.markersAtLine(self.line) & (1 << self.dbreakpoint):
5751 self.marginMenuActs["EnableBreakpoint"].setText( 5750 self.marginMenuActs["EnableBreakpoint"].setText(
5752 self.tr('Enable breakpoint')) 5751 self.tr("Enable breakpoint")
5752 )
5753 else: 5753 else:
5754 self.marginMenuActs["EnableBreakpoint"].setText( 5754 self.marginMenuActs["EnableBreakpoint"].setText(
5755 self.tr('Disable breakpoint')) 5755 self.tr("Disable breakpoint")
5756 5756 )
5757
5757 if menu is self.bmMarginMenu: 5758 if menu is self.bmMarginMenu:
5758 hasBookmarks = bool(self.bookmarks) 5759 hasBookmarks = bool(self.bookmarks)
5759 5760
5760 self.marginMenuActs["NextBookmark"].setEnabled(hasBookmarks) 5761 self.marginMenuActs["NextBookmark"].setEnabled(hasBookmarks)
5761 self.marginMenuActs["PreviousBookmark"].setEnabled(hasBookmarks) 5762 self.marginMenuActs["PreviousBookmark"].setEnabled(hasBookmarks)
5762 self.marginMenuActs["ClearBookmark"].setEnabled(hasBookmarks) 5763 self.marginMenuActs["ClearBookmark"].setEnabled(hasBookmarks)
5763 5764
5764 if menu is self.foldMarginMenu: 5765 if menu is self.foldMarginMenu:
5765 isFoldHeader = bool(self.SendScintilla( 5766 isFoldHeader = bool(
5766 QsciScintilla.SCI_GETFOLDLEVEL, self.line) & 5767 self.SendScintilla(QsciScintilla.SCI_GETFOLDLEVEL, self.line)
5767 QsciScintilla.SC_FOLDLEVELHEADERFLAG) 5768 & QsciScintilla.SC_FOLDLEVELHEADERFLAG
5768 5769 )
5770
5769 self.marginMenuActs["ExpandChildren"].setEnabled(isFoldHeader) 5771 self.marginMenuActs["ExpandChildren"].setEnabled(isFoldHeader)
5770 self.marginMenuActs["CollapseChildren"].setEnabled(isFoldHeader) 5772 self.marginMenuActs["CollapseChildren"].setEnabled(isFoldHeader)
5771 5773
5772 if menu is self.indicMarginMenu: 5774 if menu is self.indicMarginMenu:
5773 hasSyntaxErrors = bool(self.syntaxerrors) 5775 hasSyntaxErrors = bool(self.syntaxerrors)
5774 hasWarnings = bool(self.warnings) 5776 hasWarnings = bool(self.warnings)
5775 hasNotCoveredMarkers = bool(self.notcoveredMarkers) 5777 hasNotCoveredMarkers = bool(self.notcoveredMarkers)
5776 5778
5777 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors) 5779 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors)
5778 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors) 5780 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors)
5779 if ( 5781 if hasSyntaxErrors and self.markersAtLine(self.line) & (
5780 hasSyntaxErrors and 5782 1 << self.syntaxerror
5781 self.markersAtLine(self.line) & (1 << self.syntaxerror)
5782 ): 5783 ):
5783 self.marginMenuActs["ShowSyntaxError"].setEnabled(True) 5784 self.marginMenuActs["ShowSyntaxError"].setEnabled(True)
5784 else: 5785 else:
5785 self.marginMenuActs["ShowSyntaxError"].setEnabled(False) 5786 self.marginMenuActs["ShowSyntaxError"].setEnabled(False)
5786 5787
5787 self.marginMenuActs["NextWarningMarker"].setEnabled(hasWarnings) 5788 self.marginMenuActs["NextWarningMarker"].setEnabled(hasWarnings)
5788 self.marginMenuActs["PreviousWarningMarker"].setEnabled( 5789 self.marginMenuActs["PreviousWarningMarker"].setEnabled(hasWarnings)
5789 hasWarnings)
5790 self.marginMenuActs["ClearWarnings"].setEnabled(hasWarnings) 5790 self.marginMenuActs["ClearWarnings"].setEnabled(hasWarnings)
5791 if ( 5791 if hasWarnings and self.markersAtLine(self.line) & (1 << self.warning):
5792 hasWarnings and
5793 self.markersAtLine(self.line) & (1 << self.warning)
5794 ):
5795 self.marginMenuActs["ShowWarning"].setEnabled(True) 5792 self.marginMenuActs["ShowWarning"].setEnabled(True)
5796 else: 5793 else:
5797 self.marginMenuActs["ShowWarning"].setEnabled(False) 5794 self.marginMenuActs["ShowWarning"].setEnabled(False)
5798 5795
5799 self.marginMenuActs["NextCoverageMarker"].setEnabled( 5796 self.marginMenuActs["NextCoverageMarker"].setEnabled(hasNotCoveredMarkers)
5800 hasNotCoveredMarkers)
5801 self.marginMenuActs["PreviousCoverageMarker"].setEnabled( 5797 self.marginMenuActs["PreviousCoverageMarker"].setEnabled(
5802 hasNotCoveredMarkers) 5798 hasNotCoveredMarkers
5803 5799 )
5804 self.marginMenuActs["PreviousTaskMarker"].setEnabled( 5800
5805 self.__hasTaskMarkers) 5801 self.marginMenuActs["PreviousTaskMarker"].setEnabled(self.__hasTaskMarkers)
5806 self.marginMenuActs["NextTaskMarker"].setEnabled( 5802 self.marginMenuActs["NextTaskMarker"].setEnabled(self.__hasTaskMarkers)
5807 self.__hasTaskMarkers) 5803
5808
5809 self.marginMenuActs["PreviousChangeMarker"].setEnabled( 5804 self.marginMenuActs["PreviousChangeMarker"].setEnabled(
5810 self.__hasChangeMarkers) 5805 self.__hasChangeMarkers
5811 self.marginMenuActs["NextChangeMarker"].setEnabled( 5806 )
5812 self.__hasChangeMarkers) 5807 self.marginMenuActs["NextChangeMarker"].setEnabled(self.__hasChangeMarkers)
5813 self.marginMenuActs["ClearChangeMarkers"].setEnabled( 5808 self.marginMenuActs["ClearChangeMarkers"].setEnabled(
5814 self.__hasChangeMarkers) 5809 self.__hasChangeMarkers
5815 5810 )
5811
5816 self.showMenu.emit("Margin", menu, self) 5812 self.showMenu.emit("Margin", menu, self)
5817 5813
5818 def __showContextMenuChecks(self): 5814 def __showContextMenuChecks(self):
5819 """ 5815 """
5820 Private slot handling the aboutToShow signal of the checks context 5816 Private slot handling the aboutToShow signal of the checks context
5821 menu. 5817 menu.
5822 """ 5818 """
5823 self.showMenu.emit("Checks", self.checksMenu, self) 5819 self.showMenu.emit("Checks", self.checksMenu, self)
5824 5820
5825 def __showContextMenuTools(self): 5821 def __showContextMenuTools(self):
5826 """ 5822 """
5827 Private slot handling the aboutToShow signal of the tools context 5823 Private slot handling the aboutToShow signal of the tools context
5828 menu. 5824 menu.
5829 """ 5825 """
5830 self.showMenu.emit("Tools", self.toolsMenu, self) 5826 self.showMenu.emit("Tools", self.toolsMenu, self)
5831 5827
5832 def __showContextMenuFormatting(self): 5828 def __showContextMenuFormatting(self):
5833 """ 5829 """
5834 Private slot handling the aboutToShow signal of the code formatting context 5830 Private slot handling the aboutToShow signal of the code formatting context
5835 menu. 5831 menu.
5836 """ 5832 """
5837 self.showMenu.emit("Formatting", self.codeFormattingMenu, self) 5833 self.showMenu.emit("Formatting", self.codeFormattingMenu, self)
5838 5834
5839 def __reopenWithEncodingMenuTriggered(self, act): 5835 def __reopenWithEncodingMenuTriggered(self, act):
5840 """ 5836 """
5841 Private method to handle the rereading of the file with a selected 5837 Private method to handle the rereading of the file with a selected
5842 encoding. 5838 encoding.
5843 5839
5844 @param act reference to the action that was triggered (QAction) 5840 @param act reference to the action that was triggered (QAction)
5845 """ 5841 """
5846 encoding = act.data() 5842 encoding = act.data()
5847 self.readFile(self.fileName, encoding=encoding) 5843 self.readFile(self.fileName, encoding=encoding)
5848 self.__convertTabs() 5844 self.__convertTabs()
5849 self.__checkEncoding() 5845 self.__checkEncoding()
5850 5846
5851 def __contextSave(self): 5847 def __contextSave(self):
5852 """ 5848 """
5853 Private slot handling the save context menu entry. 5849 Private slot handling the save context menu entry.
5854 """ 5850 """
5855 ok = self.saveFile() 5851 ok = self.saveFile()
5856 if ok: 5852 if ok:
5857 self.vm.setEditorName(self, self.fileName) 5853 self.vm.setEditorName(self, self.fileName)
5858 5854
5859 def __contextSaveAs(self): 5855 def __contextSaveAs(self):
5860 """ 5856 """
5861 Private slot handling the save as context menu entry. 5857 Private slot handling the save as context menu entry.
5862 """ 5858 """
5863 ok = self.saveFileAs() 5859 ok = self.saveFileAs()
5864 if ok: 5860 if ok:
5865 self.vm.setEditorName(self, self.fileName) 5861 self.vm.setEditorName(self, self.fileName)
5866 5862
5867 def __contextSaveCopy(self): 5863 def __contextSaveCopy(self):
5868 """ 5864 """
5869 Private slot handling the save copy context menu entry. 5865 Private slot handling the save copy context menu entry.
5870 """ 5866 """
5871 self.saveFileCopy() 5867 self.saveFileCopy()
5872 5868
5873 def __contextClose(self): 5869 def __contextClose(self):
5874 """ 5870 """
5875 Private slot handling the close context menu entry. 5871 Private slot handling the close context menu entry.
5876 """ 5872 """
5877 self.vm.closeEditor(self) 5873 self.vm.closeEditor(self)
5878 5874
5879 def __newView(self): 5875 def __newView(self):
5880 """ 5876 """
5881 Private slot to create a new view to an open document. 5877 Private slot to create a new view to an open document.
5882 """ 5878 """
5883 self.vm.newEditorView(self.fileName, self, self.filetype) 5879 self.vm.newEditorView(self.fileName, self, self.filetype)
5884 5880
5885 def __newViewNewSplit(self): 5881 def __newViewNewSplit(self):
5886 """ 5882 """
5887 Private slot to create a new view to an open document. 5883 Private slot to create a new view to an open document.
5888 """ 5884 """
5889 self.vm.addSplit() 5885 self.vm.addSplit()
5890 self.vm.newEditorView(self.fileName, self, self.filetype) 5886 self.vm.newEditorView(self.fileName, self, self.filetype)
5891 5887
5892 def __selectAll(self): 5888 def __selectAll(self):
5893 """ 5889 """
5894 Private slot handling the select all context menu action. 5890 Private slot handling the select all context menu action.
5895 """ 5891 """
5896 self.selectAll(True) 5892 self.selectAll(True)
5897 5893
5898 def __deselectAll(self): 5894 def __deselectAll(self):
5899 """ 5895 """
5900 Private slot handling the deselect all context menu action. 5896 Private slot handling the deselect all context menu action.
5901 """ 5897 """
5902 self.selectAll(False) 5898 self.selectAll(False)
5903 5899
5904 def joinLines(self): 5900 def joinLines(self):
5905 """ 5901 """
5906 Public slot to join the current line with the next one. 5902 Public slot to join the current line with the next one.
5907 """ 5903 """
5908 curLine = self.getCursorPosition()[0] 5904 curLine = self.getCursorPosition()[0]
5909 if curLine == self.lines() - 1: 5905 if curLine == self.lines() - 1:
5910 return 5906 return
5911 5907
5912 line0Text = self.text(curLine) 5908 line0Text = self.text(curLine)
5913 line1Text = self.text(curLine + 1) 5909 line1Text = self.text(curLine + 1)
5914 if line1Text in ["", "\r", "\n", "\r\n"]: 5910 if line1Text in ["", "\r", "\n", "\r\n"]:
5915 return 5911 return
5916 5912
5917 if ( 5913 if line0Text.rstrip("\r\n\\ \t").endswith(
5918 line0Text.rstrip("\r\n\\ \t").endswith(("'", '"')) and 5914 ("'", '"')
5919 line1Text.lstrip().startswith(("'", '"')) 5915 ) and line1Text.lstrip().startswith(("'", '"')):
5920 ):
5921 # merging multi line strings 5916 # merging multi line strings
5922 startChars = "\r\n\\ \t'\"" 5917 startChars = "\r\n\\ \t'\""
5923 endChars = " \t'\"" 5918 endChars = " \t'\""
5924 else: 5919 else:
5925 startChars = "\r\n\\ \t" 5920 startChars = "\r\n\\ \t"
5926 endChars = " \t" 5921 endChars = " \t"
5927 5922
5928 # determine start index 5923 # determine start index
5929 startIndex = len(line0Text) 5924 startIndex = len(line0Text)
5930 while startIndex > 0 and line0Text[startIndex - 1] in startChars: 5925 while startIndex > 0 and line0Text[startIndex - 1] in startChars:
5931 startIndex -= 1 5926 startIndex -= 1
5932 if startIndex == 0: 5927 if startIndex == 0:
5933 return 5928 return
5934 5929
5935 # determine end index 5930 # determine end index
5936 endIndex = 0 5931 endIndex = 0
5937 while line1Text[endIndex] in endChars: 5932 while line1Text[endIndex] in endChars:
5938 endIndex += 1 5933 endIndex += 1
5939 5934
5940 self.setSelection(curLine, startIndex, curLine + 1, endIndex) 5935 self.setSelection(curLine, startIndex, curLine + 1, endIndex)
5941 self.beginUndoAction() 5936 self.beginUndoAction()
5942 self.removeSelectedText() 5937 self.removeSelectedText()
5943 self.insertAt(" ", curLine, startIndex) 5938 self.insertAt(" ", curLine, startIndex)
5944 self.endUndoAction() 5939 self.endUndoAction()
5945 5940
5946 def shortenEmptyLines(self): 5941 def shortenEmptyLines(self):
5947 """ 5942 """
5948 Public slot to compress lines consisting solely of whitespace 5943 Public slot to compress lines consisting solely of whitespace
5949 characters. 5944 characters.
5950 """ 5945 """
5951 searchRE = r"^[ \t]+$" 5946 searchRE = r"^[ \t]+$"
5952 5947
5953 ok = self.findFirstTarget(searchRE, True, False, False, 0, 0) 5948 ok = self.findFirstTarget(searchRE, True, False, False, 0, 0)
5954 self.beginUndoAction() 5949 self.beginUndoAction()
5955 while ok: 5950 while ok:
5956 self.replaceTarget("") 5951 self.replaceTarget("")
5957 ok = self.findNextTarget() 5952 ok = self.findNextTarget()
5958 self.endUndoAction() 5953 self.endUndoAction()
5959 5954
5960 def __autosaveEnable(self): 5955 def __autosaveEnable(self):
5961 """ 5956 """
5962 Private slot handling the autosave enable context menu action. 5957 Private slot handling the autosave enable context menu action.
5963 """ 5958 """
5964 if self.menuActs["AutosaveEnable"].isChecked(): 5959 if self.menuActs["AutosaveEnable"].isChecked():
5965 self.autosaveManuallyDisabled = False 5960 self.autosaveManuallyDisabled = False
5966 else: 5961 else:
5967 self.autosaveManuallyDisabled = True 5962 self.autosaveManuallyDisabled = True
5968 5963
5969 def shouldAutosave(self): 5964 def shouldAutosave(self):
5970 """ 5965 """
5971 Public slot to check the autosave flags. 5966 Public slot to check the autosave flags.
5972 5967
5973 @return flag indicating this editor should be saved (boolean) 5968 @return flag indicating this editor should be saved (boolean)
5974 """ 5969 """
5975 return ( 5970 return (
5976 bool(self.fileName) and 5971 bool(self.fileName)
5977 not self.autosaveManuallyDisabled and 5972 and not self.autosaveManuallyDisabled
5978 not self.isReadOnly() 5973 and not self.isReadOnly()
5979 ) 5974 )
5980 5975
5981 def checkSyntax(self): 5976 def checkSyntax(self):
5982 """ 5977 """
5983 Public method to perform an automatic syntax check of the file. 5978 Public method to perform an automatic syntax check of the file.
5984 """ 5979 """
5985 fileType = self.filetype 5980 fileType = self.filetype
5986 if fileType == "MicroPython": 5981 if fileType == "MicroPython":
5987 # adjustment for MicroPython 5982 # adjustment for MicroPython
5988 fileType = "Python3" 5983 fileType = "Python3"
5989 5984
5990 if ( 5985 if (
5991 self.syntaxCheckService is None or 5986 self.syntaxCheckService is None
5992 fileType not in self.syntaxCheckService.getLanguages() 5987 or fileType not in self.syntaxCheckService.getLanguages()
5993 ): 5988 ):
5994 return 5989 return
5995 5990
5996 if Preferences.getEditor("AutoCheckSyntax"): 5991 if Preferences.getEditor("AutoCheckSyntax"):
5997 if Preferences.getEditor("OnlineSyntaxCheck"): 5992 if Preferences.getEditor("OnlineSyntaxCheck"):
5998 self.__onlineSyntaxCheckTimer.stop() 5993 self.__onlineSyntaxCheckTimer.stop()
5999 5994
6000 self.syntaxCheckService.syntaxCheck( 5995 self.syntaxCheckService.syntaxCheck(
6001 fileType, self.fileName or "(Unnamed)", self.text()) 5996 fileType, self.fileName or "(Unnamed)", self.text()
5997 )
6002 5998
6003 def __processSyntaxCheckError(self, fn, msg): 5999 def __processSyntaxCheckError(self, fn, msg):
6004 """ 6000 """
6005 Private slot to report an error message of a syntax check. 6001 Private slot to report an error message of a syntax check.
6006 6002
6007 @param fn filename of the file 6003 @param fn filename of the file
6008 @type str 6004 @type str
6009 @param msg error message 6005 @param msg error message
6010 @type str 6006 @type str
6011 """ 6007 """
6012 if fn != self.fileName and ( 6008 if fn != self.fileName and (bool(self.fileName) or fn != "(Unnamed)"):
6013 bool(self.fileName) or fn != "(Unnamed)"):
6014 return 6009 return
6015 6010
6016 self.clearSyntaxError() 6011 self.clearSyntaxError()
6017 self.clearFlakesWarnings() 6012 self.clearFlakesWarnings()
6018 6013
6019 self.toggleWarning(0, 0, True, msg) 6014 self.toggleWarning(0, 0, True, msg)
6020 6015
6021 self.updateVerticalScrollBar() 6016 self.updateVerticalScrollBar()
6022 6017
6023 def __processSyntaxCheckResult(self, fn, problems): 6018 def __processSyntaxCheckResult(self, fn, problems):
6024 """ 6019 """
6025 Private slot to report the resulting messages of a syntax check. 6020 Private slot to report the resulting messages of a syntax check.
6026 6021
6027 @param fn filename of the checked file (str) 6022 @param fn filename of the checked file (str)
6028 @param problems dictionary with the keys 'error' and 'warnings' which 6023 @param problems dictionary with the keys 'error' and 'warnings' which
6029 hold a list containing details about the error/ warnings 6024 hold a list containing details about the error/ warnings
6030 (file name, line number, column, codestring (only at syntax 6025 (file name, line number, column, codestring (only at syntax
6031 errors), the message) (dict) 6026 errors), the message) (dict)
6032 """ 6027 """
6033 # Check if it's the requested file, otherwise ignore signal 6028 # Check if it's the requested file, otherwise ignore signal
6034 if fn != self.fileName and ( 6029 if fn != self.fileName and (bool(self.fileName) or fn != "(Unnamed)"):
6035 bool(self.fileName) or fn != "(Unnamed)"):
6036 return 6030 return
6037 6031
6038 self.clearSyntaxError() 6032 self.clearSyntaxError()
6039 self.clearFlakesWarnings() 6033 self.clearFlakesWarnings()
6040 6034
6041 error = problems.get('error') 6035 error = problems.get("error")
6042 if error: 6036 if error:
6043 _fn, lineno, col, code, msg = error 6037 _fn, lineno, col, code, msg = error
6044 self.toggleSyntaxError(lineno, col, True, msg) 6038 self.toggleSyntaxError(lineno, col, True, msg)
6045 6039
6046 warnings = problems.get('warnings', []) 6040 warnings = problems.get("warnings", [])
6047 for _fn, lineno, col, _code, msg in warnings: 6041 for _fn, lineno, col, _code, msg in warnings:
6048 self.toggleWarning(lineno, col, True, msg) 6042 self.toggleWarning(lineno, col, True, msg)
6049 6043
6050 self.updateVerticalScrollBar() 6044 self.updateVerticalScrollBar()
6051 6045
6052 def __initOnlineSyntaxCheck(self): 6046 def __initOnlineSyntaxCheck(self):
6053 """ 6047 """
6054 Private slot to initialize the online syntax check. 6048 Private slot to initialize the online syntax check.
6055 """ 6049 """
6056 self.__onlineSyntaxCheckTimer = QTimer(self) 6050 self.__onlineSyntaxCheckTimer = QTimer(self)
6057 self.__onlineSyntaxCheckTimer.setSingleShot(True) 6051 self.__onlineSyntaxCheckTimer.setSingleShot(True)
6058 self.__onlineSyntaxCheckTimer.setInterval( 6052 self.__onlineSyntaxCheckTimer.setInterval(
6059 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000) 6053 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000
6054 )
6060 self.__onlineSyntaxCheckTimer.timeout.connect(self.checkSyntax) 6055 self.__onlineSyntaxCheckTimer.timeout.connect(self.checkSyntax)
6061 self.textChanged.connect(self.__resetOnlineSyntaxCheckTimer) 6056 self.textChanged.connect(self.__resetOnlineSyntaxCheckTimer)
6062 6057
6063 def __resetOnlineSyntaxCheckTimer(self): 6058 def __resetOnlineSyntaxCheckTimer(self):
6064 """ 6059 """
6065 Private method to reset the online syntax check timer. 6060 Private method to reset the online syntax check timer.
6066 """ 6061 """
6067 if Preferences.getEditor("OnlineSyntaxCheck"): 6062 if Preferences.getEditor("OnlineSyntaxCheck"):
6068 self.__onlineSyntaxCheckTimer.stop() 6063 self.__onlineSyntaxCheckTimer.stop()
6069 self.__onlineSyntaxCheckTimer.start() 6064 self.__onlineSyntaxCheckTimer.start()
6070 6065
6071 def __showCodeMetrics(self): 6066 def __showCodeMetrics(self):
6072 """ 6067 """
6073 Private method to handle the code metrics context menu action. 6068 Private method to handle the code metrics context menu action.
6074 """ 6069 """
6075 if not self.checkDirty(): 6070 if not self.checkDirty():
6076 return 6071 return
6077 6072
6078 from DataViews.CodeMetricsDialog import CodeMetricsDialog 6073 from DataViews.CodeMetricsDialog import CodeMetricsDialog
6074
6079 self.codemetrics = CodeMetricsDialog() 6075 self.codemetrics = CodeMetricsDialog()
6080 self.codemetrics.show() 6076 self.codemetrics.show()
6081 self.codemetrics.start(self.fileName) 6077 self.codemetrics.start(self.fileName)
6082 6078
6083 def __getCodeCoverageFile(self): 6079 def __getCodeCoverageFile(self):
6084 """ 6080 """
6085 Private method to get the file name of the file containing coverage 6081 Private method to get the file name of the file containing coverage
6086 info. 6082 info.
6087 6083
6088 @return file name of the coverage file 6084 @return file name of the coverage file
6089 @rtype str 6085 @rtype str
6090 """ 6086 """
6091 files = set() 6087 files = set()
6092 6088
6093 if bool(self.__coverageFile): 6089 if bool(self.__coverageFile):
6094 # return the path of a previously used coverage file 6090 # return the path of a previously used coverage file
6095 return self.__coverageFile 6091 return self.__coverageFile
6096 6092
6097 # first check if the file belongs to a project and there is 6093 # first check if the file belongs to a project and there is
6098 # a project coverage file 6094 # a project coverage file
6099 if ( 6095 if self.project.isOpen() and self.project.isProjectSource(self.fileName):
6100 self.project.isOpen() and
6101 self.project.isProjectSource(self.fileName)
6102 ):
6103 pfn = self.project.getMainScript(True) 6096 pfn = self.project.getMainScript(True)
6104 if pfn is not None: 6097 if pfn is not None:
6105 files |= set(Utilities.getCoverageFileNames(pfn)) 6098 files |= set(Utilities.getCoverageFileNames(pfn))
6106 6099
6107 # now check, if there are coverage files belonging to ourselves 6100 # now check, if there are coverage files belonging to ourselves
6108 fn = self.getFileName() 6101 fn = self.getFileName()
6109 if fn is not None: 6102 if fn is not None:
6110 files |= set(Utilities.getCoverageFileNames(fn)) 6103 files |= set(Utilities.getCoverageFileNames(fn))
6111 6104
6112 files = list(files) 6105 files = list(files)
6113 if files: 6106 if files:
6114 if len(files) > 1: 6107 if len(files) > 1:
6115 cfn, ok = QInputDialog.getItem( 6108 cfn, ok = QInputDialog.getItem(
6116 self, 6109 self,
6117 self.tr("Code Coverage"), 6110 self.tr("Code Coverage"),
6118 self.tr("Please select a coverage file"), 6111 self.tr("Please select a coverage file"),
6119 files, 6112 files,
6120 0, False) 6113 0,
6114 False,
6115 )
6121 if not ok: 6116 if not ok:
6122 return "" 6117 return ""
6123 else: 6118 else:
6124 cfn = files[0] 6119 cfn = files[0]
6125 else: 6120 else:
6126 cfn = None 6121 cfn = None
6127 6122
6128 return cfn 6123 return cfn
6129 6124
6130 def __showCodeCoverage(self): 6125 def __showCodeCoverage(self):
6131 """ 6126 """
6132 Private method to handle the code coverage context menu action. 6127 Private method to handle the code coverage context menu action.
6133 """ 6128 """
6134 fn = self.__getCodeCoverageFile() 6129 fn = self.__getCodeCoverageFile()
6135 self.__coverageFile = fn 6130 self.__coverageFile = fn
6136 if fn: 6131 if fn:
6137 from DataViews.PyCoverageDialog import PyCoverageDialog 6132 from DataViews.PyCoverageDialog import PyCoverageDialog
6133
6138 self.codecoverage = PyCoverageDialog() 6134 self.codecoverage = PyCoverageDialog()
6139 self.codecoverage.show() 6135 self.codecoverage.show()
6140 self.codecoverage.start(fn, self.fileName) 6136 self.codecoverage.start(fn, self.fileName)
6141 6137
6142 def refreshCoverageAnnotations(self): 6138 def refreshCoverageAnnotations(self):
6143 """ 6139 """
6144 Public method to refresh the code coverage annotations. 6140 Public method to refresh the code coverage annotations.
6145 """ 6141 """
6146 if self.showingNotcoveredMarkers: 6142 if self.showingNotcoveredMarkers:
6147 self.codeCoverageShowAnnotations(silent=True) 6143 self.codeCoverageShowAnnotations(silent=True)
6148 6144
6149 def codeCoverageShowAnnotations(self, silent=False, coverageFile=None): 6145 def codeCoverageShowAnnotations(self, silent=False, coverageFile=None):
6150 """ 6146 """
6151 Public method to handle the show code coverage annotations context 6147 Public method to handle the show code coverage annotations context
6152 menu action. 6148 menu action.
6153 6149
6154 @param silent flag indicating to not show any dialog (defaults to 6150 @param silent flag indicating to not show any dialog (defaults to
6155 False) 6151 False)
6156 @type bool (optional) 6152 @type bool (optional)
6157 @param coverageFile path of the file containing the code coverage data 6153 @param coverageFile path of the file containing the code coverage data
6158 (defaults to None) 6154 (defaults to None)
6159 @type str (optional) 6155 @type str (optional)
6160 """ 6156 """
6161 self.__codeCoverageHideAnnotations() 6157 self.__codeCoverageHideAnnotations()
6162 6158
6163 fn = ( 6159 fn = coverageFile if bool(coverageFile) else self.__getCodeCoverageFile()
6164 coverageFile
6165 if bool(coverageFile) else
6166 self.__getCodeCoverageFile()
6167 )
6168 self.__coverageFile = fn 6160 self.__coverageFile = fn
6169 6161
6170 if fn: 6162 if fn:
6171 from coverage import Coverage 6163 from coverage import Coverage
6164
6172 cover = Coverage(data_file=fn) 6165 cover = Coverage(data_file=fn)
6173 cover.load() 6166 cover.load()
6174 missing = cover.analysis2(self.fileName)[3] 6167 missing = cover.analysis2(self.fileName)[3]
6175 if missing: 6168 if missing:
6176 for line in missing: 6169 for line in missing:
6181 else: 6174 else:
6182 if not silent: 6175 if not silent:
6183 EricMessageBox.information( 6176 EricMessageBox.information(
6184 self, 6177 self,
6185 self.tr("Show Code Coverage Annotations"), 6178 self.tr("Show Code Coverage Annotations"),
6186 self.tr("""All lines have been covered.""")) 6179 self.tr("""All lines have been covered."""),
6180 )
6187 self.showingNotcoveredMarkers = True 6181 self.showingNotcoveredMarkers = True
6188 else: 6182 else:
6189 if not silent: 6183 if not silent:
6190 EricMessageBox.warning( 6184 EricMessageBox.warning(
6191 self, 6185 self,
6192 self.tr("Show Code Coverage Annotations"), 6186 self.tr("Show Code Coverage Annotations"),
6193 self.tr("""There is no coverage file available.""")) 6187 self.tr("""There is no coverage file available."""),
6194 6188 )
6189
6195 def __codeCoverageHideAnnotations(self): 6190 def __codeCoverageHideAnnotations(self):
6196 """ 6191 """
6197 Private method to handle the hide code coverage annotations context 6192 Private method to handle the hide code coverage annotations context
6198 menu action. 6193 menu action.
6199 """ 6194 """
6201 self.markerDeleteHandle(handle) 6196 self.markerDeleteHandle(handle)
6202 self.notcoveredMarkers.clear() 6197 self.notcoveredMarkers.clear()
6203 self.coverageMarkersShown.emit(False) 6198 self.coverageMarkersShown.emit(False)
6204 self.showingNotcoveredMarkers = False 6199 self.showingNotcoveredMarkers = False
6205 self.__markerMap.update() 6200 self.__markerMap.update()
6206 6201
6207 def getCoverageLines(self): 6202 def getCoverageLines(self):
6208 """ 6203 """
6209 Public method to get the lines containing a coverage marker. 6204 Public method to get the lines containing a coverage marker.
6210 6205
6211 @return list of lines containing a coverage marker (list of integer) 6206 @return list of lines containing a coverage marker (list of integer)
6212 """ 6207 """
6213 lines = [] 6208 lines = []
6214 line = -1 6209 line = -1
6215 while True: 6210 while True:
6217 if line < 0: 6212 if line < 0:
6218 break 6213 break
6219 else: 6214 else:
6220 lines.append(line) 6215 lines.append(line)
6221 return lines 6216 return lines
6222 6217
6223 def hasCoverageMarkers(self): 6218 def hasCoverageMarkers(self):
6224 """ 6219 """
6225 Public method to test, if there are coverage markers. 6220 Public method to test, if there are coverage markers.
6226 6221
6227 @return flag indicating the presence of coverage markers (boolean) 6222 @return flag indicating the presence of coverage markers (boolean)
6228 """ 6223 """
6229 return len(self.notcoveredMarkers) > 0 6224 return len(self.notcoveredMarkers) > 0
6230 6225
6231 def nextUncovered(self): 6226 def nextUncovered(self):
6232 """ 6227 """
6233 Public slot to handle the 'Next uncovered' context menu action. 6228 Public slot to handle the 'Next uncovered' context menu action.
6234 """ 6229 """
6235 line, index = self.getCursorPosition() 6230 line, index = self.getCursorPosition()
6242 # wrap around 6237 # wrap around
6243 ucline = self.markerFindNext(0, 1 << self.notcovered) 6238 ucline = self.markerFindNext(0, 1 << self.notcovered)
6244 if ucline >= 0: 6239 if ucline >= 0:
6245 self.setCursorPosition(ucline, 0) 6240 self.setCursorPosition(ucline, 0)
6246 self.ensureLineVisible(ucline) 6241 self.ensureLineVisible(ucline)
6247 6242
6248 def previousUncovered(self): 6243 def previousUncovered(self):
6249 """ 6244 """
6250 Public slot to handle the 'Previous uncovered' context menu action. 6245 Public slot to handle the 'Previous uncovered' context menu action.
6251 """ 6246 """
6252 line, index = self.getCursorPosition() 6247 line, index = self.getCursorPosition()
6255 else: 6250 else:
6256 line -= 1 6251 line -= 1
6257 ucline = self.markerFindPrevious(line, 1 << self.notcovered) 6252 ucline = self.markerFindPrevious(line, 1 << self.notcovered)
6258 if ucline < 0: 6253 if ucline < 0:
6259 # wrap around 6254 # wrap around
6260 ucline = self.markerFindPrevious( 6255 ucline = self.markerFindPrevious(self.lines() - 1, 1 << self.notcovered)
6261 self.lines() - 1, 1 << self.notcovered)
6262 if ucline >= 0: 6256 if ucline >= 0:
6263 self.setCursorPosition(ucline, 0) 6257 self.setCursorPosition(ucline, 0)
6264 self.ensureLineVisible(ucline) 6258 self.ensureLineVisible(ucline)
6265 6259
6266 def __showProfileData(self): 6260 def __showProfileData(self):
6267 """ 6261 """
6268 Private method to handle the show profile data context menu action. 6262 Private method to handle the show profile data context menu action.
6269 """ 6263 """
6270 files = set() 6264 files = set()
6271 6265
6272 # first check if the file belongs to a project and there is 6266 # first check if the file belongs to a project and there is
6273 # a project profile file 6267 # a project profile file
6274 if ( 6268 if self.project.isOpen() and self.project.isProjectSource(self.fileName):
6275 self.project.isOpen() and
6276 self.project.isProjectSource(self.fileName)
6277 ):
6278 fn = self.project.getMainScript(True) 6269 fn = self.project.getMainScript(True)
6279 if fn is not None: 6270 if fn is not None:
6280 files |= set(Utilities.getProfileFileNames(fn)) 6271 files |= set(Utilities.getProfileFileNames(fn))
6281 6272
6282 # now check, if there are profile files belonging to ourselves 6273 # now check, if there are profile files belonging to ourselves
6283 fn = self.getFileName() 6274 fn = self.getFileName()
6284 if fn is not None: 6275 if fn is not None:
6285 files |= set(Utilities.getProfileFileNames(fn)) 6276 files |= set(Utilities.getProfileFileNames(fn))
6286 6277
6287 files = list(files) 6278 files = list(files)
6288 if files: 6279 if files:
6289 if len(files) > 1: 6280 if len(files) > 1:
6290 fn, ok = QInputDialog.getItem( 6281 fn, ok = QInputDialog.getItem(
6291 self, 6282 self,
6292 self.tr("Profile Data"), 6283 self.tr("Profile Data"),
6293 self.tr("Please select a profile file"), 6284 self.tr("Please select a profile file"),
6294 files, 6285 files,
6295 0, False) 6286 0,
6287 False,
6288 )
6296 if not ok: 6289 if not ok:
6297 return 6290 return
6298 else: 6291 else:
6299 fn = files[0] 6292 fn = files[0]
6300 else: 6293 else:
6301 return 6294 return
6302 6295
6303 from DataViews.PyProfileDialog import PyProfileDialog 6296 from DataViews.PyProfileDialog import PyProfileDialog
6297
6304 self.profiledata = PyProfileDialog() 6298 self.profiledata = PyProfileDialog()
6305 self.profiledata.show() 6299 self.profiledata.show()
6306 self.profiledata.start(fn, self.fileName) 6300 self.profiledata.start(fn, self.fileName)
6307 6301
6308 def __lmBbookmarks(self): 6302 def __lmBbookmarks(self):
6309 """ 6303 """
6310 Private method to handle the 'LMB toggles bookmark' context menu 6304 Private method to handle the 'LMB toggles bookmark' context menu
6311 action. 6305 action.
6312 """ 6306 """
6313 self.marginMenuActs["LMBbookmarks"].setChecked(True) 6307 self.marginMenuActs["LMBbookmarks"].setChecked(True)
6314 self.marginMenuActs["LMBbreakpoints"].setChecked(False) 6308 self.marginMenuActs["LMBbreakpoints"].setChecked(False)
6315 6309
6316 def __lmBbreakpoints(self): 6310 def __lmBbreakpoints(self):
6317 """ 6311 """
6318 Private method to handle the 'LMB toggles breakpoint' context menu 6312 Private method to handle the 'LMB toggles breakpoint' context menu
6319 action. 6313 action.
6320 """ 6314 """
6321 self.marginMenuActs["LMBbookmarks"].setChecked(True) 6315 self.marginMenuActs["LMBbookmarks"].setChecked(True)
6322 self.marginMenuActs["LMBbreakpoints"].setChecked(False) 6316 self.marginMenuActs["LMBbreakpoints"].setChecked(False)
6323 6317
6324 ########################################################################### 6318 ###########################################################################
6325 ## Syntax error handling methods below 6319 ## Syntax error handling methods below
6326 ########################################################################### 6320 ###########################################################################
6327 6321
6328 def toggleSyntaxError(self, line, index, error, msg="", show=False): 6322 def toggleSyntaxError(self, line, index, error, msg="", show=False):
6329 """ 6323 """
6330 Public method to toggle a syntax error indicator. 6324 Public method to toggle a syntax error indicator.
6331 6325
6332 @param line line number of the syntax error (integer) 6326 @param line line number of the syntax error (integer)
6333 @param index index number of the syntax error (integer) 6327 @param index index number of the syntax error (integer)
6334 @param error flag indicating if the error marker should be 6328 @param error flag indicating if the error marker should be
6335 set or deleted (boolean) 6329 set or deleted (boolean)
6336 @param msg error message (string) 6330 @param msg error message (string)
6349 self.syntaxerrors[handle] = [(msg, index)] 6343 self.syntaxerrors[handle] = [(msg, index)]
6350 self.syntaxerrorToggled.emit(self) 6344 self.syntaxerrorToggled.emit(self)
6351 else: 6345 else:
6352 for handle in list(self.syntaxerrors.keys()): 6346 for handle in list(self.syntaxerrors.keys()):
6353 if ( 6347 if (
6354 self.markerLine(handle) == line - 1 and 6348 self.markerLine(handle) == line - 1
6355 (msg, index) not in self.syntaxerrors[handle] 6349 and (msg, index) not in self.syntaxerrors[handle]
6356 ): 6350 ):
6357 self.syntaxerrors[handle].append((msg, index)) 6351 self.syntaxerrors[handle].append((msg, index))
6358 if show: 6352 if show:
6359 self.setCursorPosition(line - 1, index) 6353 self.setCursorPosition(line - 1, index)
6360 self.ensureLineVisible(line - 1) 6354 self.ensureLineVisible(line - 1)
6362 for handle in list(self.syntaxerrors.keys()): 6356 for handle in list(self.syntaxerrors.keys()):
6363 if self.markerLine(handle) == line - 1: 6357 if self.markerLine(handle) == line - 1:
6364 del self.syntaxerrors[handle] 6358 del self.syntaxerrors[handle]
6365 self.markerDeleteHandle(handle) 6359 self.markerDeleteHandle(handle)
6366 self.syntaxerrorToggled.emit(self) 6360 self.syntaxerrorToggled.emit(self)
6367 6361
6368 self.__setAnnotation(line - 1) 6362 self.__setAnnotation(line - 1)
6369 self.__markerMap.update() 6363 self.__markerMap.update()
6370 6364
6371 def getSyntaxErrors(self): 6365 def getSyntaxErrors(self):
6372 """ 6366 """
6373 Public method to retrieve the syntax error markers. 6367 Public method to retrieve the syntax error markers.
6374 6368
6375 @return sorted list of all lines containing a syntax error 6369 @return sorted list of all lines containing a syntax error
6376 (list of integer) 6370 (list of integer)
6377 """ 6371 """
6378 selist = [] 6372 selist = []
6379 for handle in list(self.syntaxerrors.keys()): 6373 for handle in list(self.syntaxerrors.keys()):
6380 selist.append(self.markerLine(handle) + 1) 6374 selist.append(self.markerLine(handle) + 1)
6381 6375
6382 selist.sort() 6376 selist.sort()
6383 return selist 6377 return selist
6384 6378
6385 def getSyntaxErrorLines(self): 6379 def getSyntaxErrorLines(self):
6386 """ 6380 """
6387 Public method to get the lines containing a syntax error. 6381 Public method to get the lines containing a syntax error.
6388 6382
6389 @return list of lines containing a syntax error (list of integer) 6383 @return list of lines containing a syntax error (list of integer)
6390 """ 6384 """
6391 lines = [] 6385 lines = []
6392 line = -1 6386 line = -1
6393 while True: 6387 while True:
6395 if line < 0: 6389 if line < 0:
6396 break 6390 break
6397 else: 6391 else:
6398 lines.append(line) 6392 lines.append(line)
6399 return lines 6393 return lines
6400 6394
6401 def hasSyntaxErrors(self): 6395 def hasSyntaxErrors(self):
6402 """ 6396 """
6403 Public method to check for the presence of syntax errors. 6397 Public method to check for the presence of syntax errors.
6404 6398
6405 @return flag indicating the presence of syntax errors (boolean) 6399 @return flag indicating the presence of syntax errors (boolean)
6406 """ 6400 """
6407 return len(self.syntaxerrors) > 0 6401 return len(self.syntaxerrors) > 0
6408 6402
6409 def gotoSyntaxError(self): 6403 def gotoSyntaxError(self):
6410 """ 6404 """
6411 Public slot to handle the 'Goto syntax error' context menu action. 6405 Public slot to handle the 'Goto syntax error' context menu action.
6412 """ 6406 """
6413 seline = self.markerFindNext(0, 1 << self.syntaxerror) 6407 seline = self.markerFindNext(0, 1 << self.syntaxerror)
6416 for handle in self.syntaxerrors: 6410 for handle in self.syntaxerrors:
6417 if self.markerLine(handle) == seline: 6411 if self.markerLine(handle) == seline:
6418 index = self.syntaxerrors[handle][0][1] 6412 index = self.syntaxerrors[handle][0][1]
6419 self.setCursorPosition(seline, index) 6413 self.setCursorPosition(seline, index)
6420 self.ensureLineVisible(seline) 6414 self.ensureLineVisible(seline)
6421 6415
6422 def clearSyntaxError(self): 6416 def clearSyntaxError(self):
6423 """ 6417 """
6424 Public slot to handle the 'Clear all syntax error' context menu action. 6418 Public slot to handle the 'Clear all syntax error' context menu action.
6425 """ 6419 """
6426 for handle in list(self.syntaxerrors.keys()): 6420 for handle in list(self.syntaxerrors.keys()):
6427 line = self.markerLine(handle) + 1 6421 line = self.markerLine(handle) + 1
6428 self.toggleSyntaxError(line, 0, False) 6422 self.toggleSyntaxError(line, 0, False)
6429 6423
6430 self.syntaxerrors.clear() 6424 self.syntaxerrors.clear()
6431 self.syntaxerrorToggled.emit(self) 6425 self.syntaxerrorToggled.emit(self)
6432 6426
6433 def __showSyntaxError(self, line=-1): 6427 def __showSyntaxError(self, line=-1):
6434 """ 6428 """
6435 Private slot to handle the 'Show syntax error message' 6429 Private slot to handle the 'Show syntax error message'
6436 context menu action. 6430 context menu action.
6437 6431
6438 @param line line number to show the syntax error for (integer) 6432 @param line line number to show the syntax error for (integer)
6439 """ 6433 """
6440 if line == -1: 6434 if line == -1:
6441 line = self.line 6435 line = self.line
6442 6436
6443 for handle in list(self.syntaxerrors.keys()): 6437 for handle in list(self.syntaxerrors.keys()):
6444 if self.markerLine(handle) == line: 6438 if self.markerLine(handle) == line:
6445 errors = [e[0] for e in self.syntaxerrors[handle]] 6439 errors = [e[0] for e in self.syntaxerrors[handle]]
6446 EricMessageBox.critical( 6440 EricMessageBox.critical(
6447 self, 6441 self, self.tr("Syntax Error"), "\n".join(errors)
6448 self.tr("Syntax Error"), 6442 )
6449 "\n".join(errors))
6450 break 6443 break
6451 else: 6444 else:
6452 EricMessageBox.critical( 6445 EricMessageBox.critical(
6453 self, 6446 self,
6454 self.tr("Syntax Error"), 6447 self.tr("Syntax Error"),
6455 self.tr("No syntax error message available.")) 6448 self.tr("No syntax error message available."),
6456 6449 )
6450
6457 ########################################################################### 6451 ###########################################################################
6458 ## VCS conflict marker handling methods below 6452 ## VCS conflict marker handling methods below
6459 ########################################################################### 6453 ###########################################################################
6460 6454
6461 def getVcsConflictMarkerLines(self): 6455 def getVcsConflictMarkerLines(self):
6462 """ 6456 """
6463 Public method to determine the lines containing a VCS conflict marker. 6457 Public method to determine the lines containing a VCS conflict marker.
6464 6458
6465 @return list of line numbers containg a VCS conflict marker 6459 @return list of line numbers containg a VCS conflict marker
6466 @rtype list of int 6460 @rtype list of int
6467 """ 6461 """
6468 conflictMarkerLines = [] 6462 conflictMarkerLines = []
6469 6463
6470 regExp = re.compile("|".join(Editor.VcsConflictMarkerLineRegExpList), 6464 regExp = re.compile(
6471 re.MULTILINE) 6465 "|".join(Editor.VcsConflictMarkerLineRegExpList), re.MULTILINE
6466 )
6472 matches = [m for m in regExp.finditer(self.text())] 6467 matches = [m for m in regExp.finditer(self.text())]
6473 for match in matches: 6468 for match in matches:
6474 line, _ = self.lineIndexFromPosition(match.start()) 6469 line, _ = self.lineIndexFromPosition(match.start())
6475 conflictMarkerLines.append(line) 6470 conflictMarkerLines.append(line)
6476 6471
6477 return conflictMarkerLines 6472 return conflictMarkerLines
6478 6473
6479 ########################################################################### 6474 ###########################################################################
6480 ## Warning handling methods below 6475 ## Warning handling methods below
6481 ########################################################################### 6476 ###########################################################################
6482 6477
6483 def toggleWarning( 6478 def toggleWarning(self, line, col, warning, msg="", warningType=WarningCode):
6484 self, line, col, warning, msg="", warningType=WarningCode):
6485 """ 6479 """
6486 Public method to toggle a warning indicator. 6480 Public method to toggle a warning indicator.
6487 6481
6488 Note: This method is used to set pyflakes and code style warnings. 6482 Note: This method is used to set pyflakes and code style warnings.
6489 6483
6490 @param line line number of the warning 6484 @param line line number of the warning
6491 @param col column of the warning 6485 @param col column of the warning
6492 @param warning flag indicating if the warning marker should be 6486 @param warning flag indicating if the warning marker should be
6493 set or deleted (boolean) 6487 set or deleted (boolean)
6494 @param msg warning message (string) 6488 @param msg warning message (string)
6506 self.warnings[handle] = [warn] 6500 self.warnings[handle] = [warn]
6507 self.syntaxerrorToggled.emit(self) 6501 self.syntaxerrorToggled.emit(self)
6508 else: 6502 else:
6509 for handle in list(self.warnings.keys()): 6503 for handle in list(self.warnings.keys()):
6510 if ( 6504 if (
6511 self.markerLine(handle) == line - 1 and 6505 self.markerLine(handle) == line - 1
6512 warn not in self.warnings[handle] 6506 and warn not in self.warnings[handle]
6513 ): 6507 ):
6514 self.warnings[handle].append(warn) 6508 self.warnings[handle].append(warn)
6515 else: 6509 else:
6516 for handle in list(self.warnings.keys()): 6510 for handle in list(self.warnings.keys()):
6517 if self.markerLine(handle) == line - 1: 6511 if self.markerLine(handle) == line - 1:
6518 del self.warnings[handle] 6512 del self.warnings[handle]
6519 self.markerDeleteHandle(handle) 6513 self.markerDeleteHandle(handle)
6520 self.syntaxerrorToggled.emit(self) 6514 self.syntaxerrorToggled.emit(self)
6521 6515
6522 self.__setAnnotation(line - 1) 6516 self.__setAnnotation(line - 1)
6523 self.__markerMap.update() 6517 self.__markerMap.update()
6524 6518
6525 def getWarnings(self): 6519 def getWarnings(self):
6526 """ 6520 """
6527 Public method to retrieve the warning markers. 6521 Public method to retrieve the warning markers.
6528 6522
6529 @return sorted list of all lines containing a warning 6523 @return sorted list of all lines containing a warning
6530 (list of integer) 6524 (list of integer)
6531 """ 6525 """
6532 fwlist = [] 6526 fwlist = []
6533 for handle in list(self.warnings.keys()): 6527 for handle in list(self.warnings.keys()):
6534 fwlist.append(self.markerLine(handle) + 1) 6528 fwlist.append(self.markerLine(handle) + 1)
6535 6529
6536 fwlist.sort() 6530 fwlist.sort()
6537 return fwlist 6531 return fwlist
6538 6532
6539 def getWarningLines(self): 6533 def getWarningLines(self):
6540 """ 6534 """
6541 Public method to get the lines containing a warning. 6535 Public method to get the lines containing a warning.
6542 6536
6543 @return list of lines containing a warning (list of integer) 6537 @return list of lines containing a warning (list of integer)
6544 """ 6538 """
6545 lines = [] 6539 lines = []
6546 line = -1 6540 line = -1
6547 while True: 6541 while True:
6549 if line < 0: 6543 if line < 0:
6550 break 6544 break
6551 else: 6545 else:
6552 lines.append(line) 6546 lines.append(line)
6553 return lines 6547 return lines
6554 6548
6555 def hasWarnings(self): 6549 def hasWarnings(self):
6556 """ 6550 """
6557 Public method to check for the presence of warnings. 6551 Public method to check for the presence of warnings.
6558 6552
6559 @return flag indicating the presence of warnings (boolean) 6553 @return flag indicating the presence of warnings (boolean)
6560 """ 6554 """
6561 return len(self.warnings) > 0 6555 return len(self.warnings) > 0
6562 6556
6563 def nextWarning(self): 6557 def nextWarning(self):
6564 """ 6558 """
6565 Public slot to handle the 'Next warning' context menu action. 6559 Public slot to handle the 'Next warning' context menu action.
6566 """ 6560 """
6567 line, index = self.getCursorPosition() 6561 line, index = self.getCursorPosition()
6574 # wrap around 6568 # wrap around
6575 fwline = self.markerFindNext(0, 1 << self.warning) 6569 fwline = self.markerFindNext(0, 1 << self.warning)
6576 if fwline >= 0: 6570 if fwline >= 0:
6577 self.setCursorPosition(fwline, 0) 6571 self.setCursorPosition(fwline, 0)
6578 self.ensureLineVisible(fwline) 6572 self.ensureLineVisible(fwline)
6579 6573
6580 def previousWarning(self): 6574 def previousWarning(self):
6581 """ 6575 """
6582 Public slot to handle the 'Previous warning' context menu action. 6576 Public slot to handle the 'Previous warning' context menu action.
6583 """ 6577 """
6584 line, index = self.getCursorPosition() 6578 line, index = self.getCursorPosition()
6587 else: 6581 else:
6588 line -= 1 6582 line -= 1
6589 fwline = self.markerFindPrevious(line, 1 << self.warning) 6583 fwline = self.markerFindPrevious(line, 1 << self.warning)
6590 if fwline < 0: 6584 if fwline < 0:
6591 # wrap around 6585 # wrap around
6592 fwline = self.markerFindPrevious( 6586 fwline = self.markerFindPrevious(self.lines() - 1, 1 << self.warning)
6593 self.lines() - 1, 1 << self.warning)
6594 if fwline >= 0: 6587 if fwline >= 0:
6595 self.setCursorPosition(fwline, 0) 6588 self.setCursorPosition(fwline, 0)
6596 self.ensureLineVisible(fwline) 6589 self.ensureLineVisible(fwline)
6597 6590
6598 def clearFlakesWarnings(self): 6591 def clearFlakesWarnings(self):
6599 """ 6592 """
6600 Public slot to clear all pyflakes warnings. 6593 Public slot to clear all pyflakes warnings.
6601 """ 6594 """
6602 self.__clearTypedWarning(Editor.WarningCode) 6595 self.__clearTypedWarning(Editor.WarningCode)
6603 6596
6604 def clearStyleWarnings(self): 6597 def clearStyleWarnings(self):
6605 """ 6598 """
6606 Public slot to clear all style warnings. 6599 Public slot to clear all style warnings.
6607 """ 6600 """
6608 self.__clearTypedWarning(Editor.WarningStyle) 6601 self.__clearTypedWarning(Editor.WarningStyle)
6609 6602
6610 def __clearTypedWarning(self, warningKind): 6603 def __clearTypedWarning(self, warningKind):
6611 """ 6604 """
6612 Private method to clear warnings of a specific kind. 6605 Private method to clear warnings of a specific kind.
6613 6606
6614 @param warningKind kind of warning to clear (Editor.WarningCode, 6607 @param warningKind kind of warning to clear (Editor.WarningCode,
6615 Editor.WarningStyle) 6608 Editor.WarningStyle)
6616 """ 6609 """
6617 for handle in list(self.warnings.keys()): 6610 for handle in list(self.warnings.keys()):
6618 warnings = [] 6611 warnings = []
6619 for msg, warningType in self.warnings[handle]: 6612 for msg, warningType in self.warnings[handle]:
6620 if warningType == warningKind: 6613 if warningType == warningKind:
6621 continue 6614 continue
6622 6615
6623 warnings.append((msg, warningType)) 6616 warnings.append((msg, warningType))
6624 6617
6625 if warnings: 6618 if warnings:
6626 self.warnings[handle] = warnings 6619 self.warnings[handle] = warnings
6627 self.__setAnnotation(self.markerLine(handle)) 6620 self.__setAnnotation(self.markerLine(handle))
6628 else: 6621 else:
6629 del self.warnings[handle] 6622 del self.warnings[handle]
6630 self.__setAnnotation(self.markerLine(handle)) 6623 self.__setAnnotation(self.markerLine(handle))
6631 self.markerDeleteHandle(handle) 6624 self.markerDeleteHandle(handle)
6632 self.syntaxerrorToggled.emit(self) 6625 self.syntaxerrorToggled.emit(self)
6633 self.__markerMap.update() 6626 self.__markerMap.update()
6634 6627
6635 def clearWarnings(self): 6628 def clearWarnings(self):
6636 """ 6629 """
6637 Public slot to clear all warnings. 6630 Public slot to clear all warnings.
6638 """ 6631 """
6639 for handle in self.warnings: 6632 for handle in self.warnings:
6641 self.__setAnnotation(self.markerLine(handle)) 6634 self.__setAnnotation(self.markerLine(handle))
6642 self.markerDeleteHandle(handle) 6635 self.markerDeleteHandle(handle)
6643 self.warnings.clear() 6636 self.warnings.clear()
6644 self.syntaxerrorToggled.emit(self) 6637 self.syntaxerrorToggled.emit(self)
6645 self.__markerMap.update() 6638 self.__markerMap.update()
6646 6639
6647 def __showWarning(self, line=-1): 6640 def __showWarning(self, line=-1):
6648 """ 6641 """
6649 Private slot to handle the 'Show warning' context menu action. 6642 Private slot to handle the 'Show warning' context menu action.
6650 6643
6651 @param line line number to show the warning for (integer) 6644 @param line line number to show the warning for (integer)
6652 """ 6645 """
6653 if line == -1: 6646 if line == -1:
6654 line = self.line 6647 line = self.line
6655 6648
6656 for handle in list(self.warnings.keys()): 6649 for handle in list(self.warnings.keys()):
6657 if self.markerLine(handle) == line: 6650 if self.markerLine(handle) == line:
6658 EricMessageBox.warning( 6651 EricMessageBox.warning(
6659 self, 6652 self,
6660 self.tr("Warning"), 6653 self.tr("Warning"),
6661 '\n'.join([w[0] for w in self.warnings[handle]])) 6654 "\n".join([w[0] for w in self.warnings[handle]]),
6655 )
6662 break 6656 break
6663 else: 6657 else:
6664 EricMessageBox.warning( 6658 EricMessageBox.warning(
6665 self, 6659 self, self.tr("Warning"), self.tr("No warning messages available.")
6666 self.tr("Warning"), 6660 )
6667 self.tr("No warning messages available.")) 6661
6668
6669 ########################################################################### 6662 ###########################################################################
6670 ## Annotation handling methods below 6663 ## Annotation handling methods below
6671 ########################################################################### 6664 ###########################################################################
6672 6665
6673 def __setAnnotationStyles(self): 6666 def __setAnnotationStyles(self):
6674 """ 6667 """
6675 Private slot to define the style used by inline annotations. 6668 Private slot to define the style used by inline annotations.
6676 """ 6669 """
6677 if hasattr(QsciScintilla, "annotate"): 6670 if hasattr(QsciScintilla, "annotate"):
6678 self.annotationWarningStyle = ( 6671 self.annotationWarningStyle = QsciScintilla.STYLE_LASTPREDEFINED + 1
6679 QsciScintilla.STYLE_LASTPREDEFINED + 1
6680 )
6681 self.SendScintilla( 6672 self.SendScintilla(
6682 QsciScintilla.SCI_STYLESETFORE, 6673 QsciScintilla.SCI_STYLESETFORE,
6683 self.annotationWarningStyle, 6674 self.annotationWarningStyle,
6684 Preferences.getEditorColour("AnnotationsWarningForeground")) 6675 Preferences.getEditorColour("AnnotationsWarningForeground"),
6676 )
6685 self.SendScintilla( 6677 self.SendScintilla(
6686 QsciScintilla.SCI_STYLESETBACK, 6678 QsciScintilla.SCI_STYLESETBACK,
6687 self.annotationWarningStyle, 6679 self.annotationWarningStyle,
6688 Preferences.getEditorColour("AnnotationsWarningBackground")) 6680 Preferences.getEditorColour("AnnotationsWarningBackground"),
6689 6681 )
6682
6690 self.annotationErrorStyle = self.annotationWarningStyle + 1 6683 self.annotationErrorStyle = self.annotationWarningStyle + 1
6691 self.SendScintilla( 6684 self.SendScintilla(
6692 QsciScintilla.SCI_STYLESETFORE, 6685 QsciScintilla.SCI_STYLESETFORE,
6693 self.annotationErrorStyle, 6686 self.annotationErrorStyle,
6694 Preferences.getEditorColour("AnnotationsErrorForeground")) 6687 Preferences.getEditorColour("AnnotationsErrorForeground"),
6688 )
6695 self.SendScintilla( 6689 self.SendScintilla(
6696 QsciScintilla.SCI_STYLESETBACK, 6690 QsciScintilla.SCI_STYLESETBACK,
6697 self.annotationErrorStyle, 6691 self.annotationErrorStyle,
6698 Preferences.getEditorColour("AnnotationsErrorBackground")) 6692 Preferences.getEditorColour("AnnotationsErrorBackground"),
6699 6693 )
6694
6700 self.annotationStyleStyle = self.annotationErrorStyle + 1 6695 self.annotationStyleStyle = self.annotationErrorStyle + 1
6701 self.SendScintilla( 6696 self.SendScintilla(
6702 QsciScintilla.SCI_STYLESETFORE, 6697 QsciScintilla.SCI_STYLESETFORE,
6703 self.annotationStyleStyle, 6698 self.annotationStyleStyle,
6704 Preferences.getEditorColour("AnnotationsStyleForeground")) 6699 Preferences.getEditorColour("AnnotationsStyleForeground"),
6700 )
6705 self.SendScintilla( 6701 self.SendScintilla(
6706 QsciScintilla.SCI_STYLESETBACK, 6702 QsciScintilla.SCI_STYLESETBACK,
6707 self.annotationStyleStyle, 6703 self.annotationStyleStyle,
6708 Preferences.getEditorColour("AnnotationsStyleBackground")) 6704 Preferences.getEditorColour("AnnotationsStyleBackground"),
6709 6705 )
6706
6710 def __setAnnotation(self, line): 6707 def __setAnnotation(self, line):
6711 """ 6708 """
6712 Private method to set the annotations for the given line. 6709 Private method to set the annotations for the given line.
6713 6710
6714 @param line number of the line that needs annotation (integer) 6711 @param line number of the line that needs annotation (integer)
6715 """ 6712 """
6716 if hasattr(QsciScintilla, "annotate"): 6713 if hasattr(QsciScintilla, "annotate"):
6717 warningAnnotations = [] 6714 warningAnnotations = []
6718 errorAnnotations = [] 6715 errorAnnotations = []
6719 styleAnnotations = [] 6716 styleAnnotations = []
6720 6717
6721 # step 1: do warnings 6718 # step 1: do warnings
6722 for handle in self.warnings: 6719 for handle in self.warnings:
6723 if self.markerLine(handle) == line: 6720 if self.markerLine(handle) == line:
6724 for msg, warningType in self.warnings[handle]: 6721 for msg, warningType in self.warnings[handle]:
6725 if warningType == self.WarningStyle: 6722 if warningType == self.WarningStyle:
6726 styleAnnotations.append( 6723 styleAnnotations.append(self.tr("Style: {0}").format(msg))
6727 self.tr("Style: {0}").format(msg))
6728 else: 6724 else:
6729 warningAnnotations.append( 6725 warningAnnotations.append(
6730 self.tr("Warning: {0}").format(msg)) 6726 self.tr("Warning: {0}").format(msg)
6731 6727 )
6728
6732 # step 2: do syntax errors 6729 # step 2: do syntax errors
6733 for handle in self.syntaxerrors: 6730 for handle in self.syntaxerrors:
6734 if self.markerLine(handle) == line: 6731 if self.markerLine(handle) == line:
6735 for msg, _ in self.syntaxerrors[handle]: 6732 for msg, _ in self.syntaxerrors[handle]:
6736 errorAnnotations.append( 6733 errorAnnotations.append(self.tr("Error: {0}").format(msg))
6737 self.tr("Error: {0}").format(msg)) 6734
6738
6739 annotations = [] 6735 annotations = []
6740 if styleAnnotations: 6736 if styleAnnotations:
6741 annotationStyleTxt = "\n".join(styleAnnotations) 6737 annotationStyleTxt = "\n".join(styleAnnotations)
6742 if warningAnnotations or errorAnnotations: 6738 if warningAnnotations or errorAnnotations:
6743 annotationStyleTxt += "\n" 6739 annotationStyleTxt += "\n"
6744 annotations.append(QsciStyledText( 6740 annotations.append(
6745 annotationStyleTxt, self.annotationStyleStyle)) 6741 QsciStyledText(annotationStyleTxt, self.annotationStyleStyle)
6746 6742 )
6743
6747 if warningAnnotations: 6744 if warningAnnotations:
6748 annotationWarningTxt = "\n".join(warningAnnotations) 6745 annotationWarningTxt = "\n".join(warningAnnotations)
6749 if errorAnnotations: 6746 if errorAnnotations:
6750 annotationWarningTxt += "\n" 6747 annotationWarningTxt += "\n"
6751 annotations.append(QsciStyledText( 6748 annotations.append(
6752 annotationWarningTxt, self.annotationWarningStyle)) 6749 QsciStyledText(annotationWarningTxt, self.annotationWarningStyle)
6753 6750 )
6751
6754 if errorAnnotations: 6752 if errorAnnotations:
6755 annotationErrorTxt = "\n".join(errorAnnotations) 6753 annotationErrorTxt = "\n".join(errorAnnotations)
6756 annotations.append(QsciStyledText( 6754 annotations.append(
6757 annotationErrorTxt, self.annotationErrorStyle)) 6755 QsciStyledText(annotationErrorTxt, self.annotationErrorStyle)
6758 6756 )
6757
6759 if annotations: 6758 if annotations:
6760 self.annotate(line, annotations) 6759 self.annotate(line, annotations)
6761 else: 6760 else:
6762 self.clearAnnotations(line) 6761 self.clearAnnotations(line)
6763 6762
6764 def __refreshAnnotations(self): 6763 def __refreshAnnotations(self):
6765 """ 6764 """
6766 Private method to refresh the annotations. 6765 Private method to refresh the annotations.
6767 """ 6766 """
6768 if hasattr(QsciScintilla, "annotate"): 6767 if hasattr(QsciScintilla, "annotate"):
6769 self.clearAnnotations() 6768 self.clearAnnotations()
6770 for handle in ( 6769 for handle in list(self.warnings.keys()) + list(self.syntaxerrors.keys()):
6771 list(self.warnings.keys()) +
6772 list(self.syntaxerrors.keys())
6773 ):
6774 line = self.markerLine(handle) 6770 line = self.markerLine(handle)
6775 self.__setAnnotation(line) 6771 self.__setAnnotation(line)
6776 6772
6777 ################################################################# 6773 #################################################################
6778 ## Fold handling methods 6774 ## Fold handling methods
6779 ################################################################# 6775 #################################################################
6780 6776
6781 def toggleCurrentFold(self): 6777 def toggleCurrentFold(self):
6782 """ 6778 """
6783 Public slot to toggle the fold containing the current line. 6779 Public slot to toggle the fold containing the current line.
6784 """ 6780 """
6785 line, index = self.getCursorPosition() 6781 line, index = self.getCursorPosition()
6786 self.foldLine(line) 6782 self.foldLine(line)
6787 6783
6788 def expandFoldWithChildren(self, line=-1): 6784 def expandFoldWithChildren(self, line=-1):
6789 """ 6785 """
6790 Public slot to expand the current fold including its children. 6786 Public slot to expand the current fold including its children.
6791 6787
6792 @param line number of line to be expanded 6788 @param line number of line to be expanded
6793 @type int 6789 @type int
6794 """ 6790 """
6795 if line == -1: 6791 if line == -1:
6796 line, index = self.getCursorPosition() 6792 line, index = self.getCursorPosition()
6797 6793
6798 self.SendScintilla(QsciScintilla.SCI_FOLDCHILDREN, line, 6794 self.SendScintilla(
6799 QsciScintilla.SC_FOLDACTION_EXPAND) 6795 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_EXPAND
6800 6796 )
6797
6801 def collapseFoldWithChildren(self, line=-1): 6798 def collapseFoldWithChildren(self, line=-1):
6802 """ 6799 """
6803 Public slot to collapse the current fold including its children. 6800 Public slot to collapse the current fold including its children.
6804 6801
6805 @param line number of line to be expanded 6802 @param line number of line to be expanded
6806 @type int 6803 @type int
6807 """ 6804 """
6808 if line == -1: 6805 if line == -1:
6809 line, index = self.getCursorPosition() 6806 line, index = self.getCursorPosition()
6810 6807
6811 self.SendScintilla(QsciScintilla.SCI_FOLDCHILDREN, line, 6808 self.SendScintilla(
6812 QsciScintilla.SC_FOLDACTION_CONTRACT) 6809 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_CONTRACT
6813 6810 )
6811
6814 def __contextMenuExpandFoldWithChildren(self): 6812 def __contextMenuExpandFoldWithChildren(self):
6815 """ 6813 """
6816 Private slot to handle the context menu expand with children action. 6814 Private slot to handle the context menu expand with children action.
6817 """ 6815 """
6818 self.expandFoldWithChildren(self.line) 6816 self.expandFoldWithChildren(self.line)
6819 6817
6820 def __contextMenuCollapseFoldWithChildren(self): 6818 def __contextMenuCollapseFoldWithChildren(self):
6821 """ 6819 """
6822 Private slot to handle the context menu collapse with children action. 6820 Private slot to handle the context menu collapse with children action.
6823 """ 6821 """
6824 self.collapseFoldWithChildren(self.line) 6822 self.collapseFoldWithChildren(self.line)
6825 6823
6826 ################################################################# 6824 #################################################################
6827 ## Macro handling methods 6825 ## Macro handling methods
6828 ################################################################# 6826 #################################################################
6829 6827
6830 def __getMacroName(self): 6828 def __getMacroName(self):
6831 """ 6829 """
6832 Private method to select a macro name from the list of macros. 6830 Private method to select a macro name from the list of macros.
6833 6831
6834 @return Tuple of macro name and a flag, indicating, if the user 6832 @return Tuple of macro name and a flag, indicating, if the user
6835 pressed ok or canceled the operation. (string, boolean) 6833 pressed ok or canceled the operation. (string, boolean)
6836 """ 6834 """
6837 qs = [] 6835 qs = []
6838 for s in list(self.macros.keys()): 6836 for s in list(self.macros.keys()):
6839 qs.append(s) 6837 qs.append(s)
6840 qs.sort() 6838 qs.sort()
6841 return QInputDialog.getItem( 6839 return QInputDialog.getItem(
6842 self, 6840 self, self.tr("Macro Name"), self.tr("Select a macro name:"), qs, 0, False
6843 self.tr("Macro Name"), 6841 )
6844 self.tr("Select a macro name:"), 6842
6845 qs,
6846 0, False)
6847
6848 def macroRun(self): 6843 def macroRun(self):
6849 """ 6844 """
6850 Public method to execute a macro. 6845 Public method to execute a macro.
6851 """ 6846 """
6852 name, ok = self.__getMacroName() 6847 name, ok = self.__getMacroName()
6853 if ok and name: 6848 if ok and name:
6854 self.macros[name].play() 6849 self.macros[name].play()
6855 6850
6856 def macroDelete(self): 6851 def macroDelete(self):
6857 """ 6852 """
6858 Public method to delete a macro. 6853 Public method to delete a macro.
6859 """ 6854 """
6860 name, ok = self.__getMacroName() 6855 name, ok = self.__getMacroName()
6861 if ok and name: 6856 if ok and name:
6862 del self.macros[name] 6857 del self.macros[name]
6863 6858
6864 def macroLoad(self): 6859 def macroLoad(self):
6865 """ 6860 """
6866 Public method to load a macro from a file. 6861 Public method to load a macro from a file.
6867 """ 6862 """
6868 configDir = Utilities.getConfigDir() 6863 configDir = Utilities.getConfigDir()
6869 fname = EricFileDialog.getOpenFileName( 6864 fname = EricFileDialog.getOpenFileName(
6870 self, 6865 self,
6871 self.tr("Load macro file"), 6866 self.tr("Load macro file"),
6872 configDir, 6867 configDir,
6873 self.tr("Macro files (*.macro)")) 6868 self.tr("Macro files (*.macro)"),
6874 6869 )
6870
6875 if not fname: 6871 if not fname:
6876 return # user aborted 6872 return # user aborted
6877 6873
6878 try: 6874 try:
6879 with open(fname, "r", encoding="utf-8") as f: 6875 with open(fname, "r", encoding="utf-8") as f:
6880 lines = f.readlines() 6876 lines = f.readlines()
6881 except OSError: 6877 except OSError:
6882 EricMessageBox.critical( 6878 EricMessageBox.critical(
6883 self, 6879 self,
6884 self.tr("Error loading macro"), 6880 self.tr("Error loading macro"),
6885 self.tr( 6881 self.tr("<p>The macro file <b>{0}</b> could not be read.</p>").format(
6886 "<p>The macro file <b>{0}</b> could not be read.</p>") 6882 fname
6887 .format(fname)) 6883 ),
6884 )
6888 return 6885 return
6889 6886
6890 if len(lines) != 2: 6887 if len(lines) != 2:
6891 EricMessageBox.critical( 6888 EricMessageBox.critical(
6892 self, 6889 self,
6893 self.tr("Error loading macro"), 6890 self.tr("Error loading macro"),
6894 self.tr("<p>The macro file <b>{0}</b> is corrupt.</p>") 6891 self.tr("<p>The macro file <b>{0}</b> is corrupt.</p>").format(fname),
6895 .format(fname)) 6892 )
6896 return 6893 return
6897 6894
6898 macro = QsciMacro(lines[1], self) 6895 macro = QsciMacro(lines[1], self)
6899 self.macros[lines[0].strip()] = macro 6896 self.macros[lines[0].strip()] = macro
6900 6897
6901 def macroSave(self): 6898 def macroSave(self):
6902 """ 6899 """
6903 Public method to save a macro to a file. 6900 Public method to save a macro to a file.
6904 """ 6901 """
6905 configDir = Utilities.getConfigDir() 6902 configDir = Utilities.getConfigDir()
6906 6903
6907 name, ok = self.__getMacroName() 6904 name, ok = self.__getMacroName()
6908 if not ok or not name: 6905 if not ok or not name:
6909 return # user abort 6906 return # user abort
6910 6907
6911 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 6908 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
6912 self, 6909 self,
6913 self.tr("Save macro file"), 6910 self.tr("Save macro file"),
6914 configDir, 6911 configDir,
6915 self.tr("Macro files (*.macro)"), 6912 self.tr("Macro files (*.macro)"),
6916 "", 6913 "",
6917 EricFileDialog.DontConfirmOverwrite) 6914 EricFileDialog.DontConfirmOverwrite,
6918 6915 )
6916
6919 if not fname: 6917 if not fname:
6920 return # user aborted 6918 return # user aborted
6921 6919
6922 fpath = pathlib.Path(fname) 6920 fpath = pathlib.Path(fname)
6923 if not fpath.suffix: 6921 if not fpath.suffix:
6924 ex = selectedFilter.split("(*")[1].split(")")[0] 6922 ex = selectedFilter.split("(*")[1].split(")")[0]
6925 if ex: 6923 if ex:
6926 fpath = fpath.with_suffix(ex) 6924 fpath = fpath.with_suffix(ex)
6927 if fpath.exists(): 6925 if fpath.exists():
6928 res = EricMessageBox.yesNo( 6926 res = EricMessageBox.yesNo(
6929 self, 6927 self,
6930 self.tr("Save macro"), 6928 self.tr("Save macro"),
6931 self.tr("<p>The macro file <b>{0}</b> already exists." 6929 self.tr(
6932 " Overwrite it?</p>").format(fpath), 6930 "<p>The macro file <b>{0}</b> already exists." " Overwrite it?</p>"
6933 icon=EricMessageBox.Warning) 6931 ).format(fpath),
6932 icon=EricMessageBox.Warning,
6933 )
6934 if not res: 6934 if not res:
6935 return 6935 return
6936 6936
6937 try: 6937 try:
6938 with fpath.open("w", encoding="utf-8") as f: 6938 with fpath.open("w", encoding="utf-8") as f:
6939 f.write("{0}{1}".format(name, "\n")) 6939 f.write("{0}{1}".format(name, "\n"))
6940 f.write(self.macros[name].save()) 6940 f.write(self.macros[name].save())
6941 except OSError: 6941 except OSError:
6942 EricMessageBox.critical( 6942 EricMessageBox.critical(
6943 self, 6943 self,
6944 self.tr("Error saving macro"), 6944 self.tr("Error saving macro"),
6945 self.tr( 6945 self.tr(
6946 "<p>The macro file <b>{0}</b> could not be written.</p>") 6946 "<p>The macro file <b>{0}</b> could not be written.</p>"
6947 .format(fpath)) 6947 ).format(fpath),
6948 )
6948 return 6949 return
6949 6950
6950 def macroRecordingStart(self): 6951 def macroRecordingStart(self):
6951 """ 6952 """
6952 Public method to start macro recording. 6953 Public method to start macro recording.
6953 """ 6954 """
6954 if self.recording: 6955 if self.recording:
6955 res = EricMessageBox.yesNo( 6956 res = EricMessageBox.yesNo(
6956 self, 6957 self,
6957 self.tr("Start Macro Recording"), 6958 self.tr("Start Macro Recording"),
6958 self.tr("Macro recording is already active. Start new?"), 6959 self.tr("Macro recording is already active. Start new?"),
6959 icon=EricMessageBox.Warning, 6960 icon=EricMessageBox.Warning,
6960 yesDefault=True) 6961 yesDefault=True,
6962 )
6961 if res: 6963 if res:
6962 self.macroRecordingStop() 6964 self.macroRecordingStop()
6963 else: 6965 else:
6964 return 6966 return
6965 else: 6967 else:
6966 self.recording = True 6968 self.recording = True
6967 6969
6968 self.curMacro = QsciMacro(self) 6970 self.curMacro = QsciMacro(self)
6969 self.curMacro.startRecording() 6971 self.curMacro.startRecording()
6970 6972
6971 def macroRecordingStop(self): 6973 def macroRecordingStop(self):
6972 """ 6974 """
6973 Public method to stop macro recording. 6975 Public method to stop macro recording.
6974 """ 6976 """
6975 if not self.recording: 6977 if not self.recording:
6976 return # we are not recording 6978 return # we are not recording
6977 6979
6978 self.curMacro.endRecording() 6980 self.curMacro.endRecording()
6979 self.recording = False 6981 self.recording = False
6980 6982
6981 name, ok = QInputDialog.getText( 6983 name, ok = QInputDialog.getText(
6982 self, 6984 self,
6983 self.tr("Macro Recording"), 6985 self.tr("Macro Recording"),
6984 self.tr("Enter name of the macro:"), 6986 self.tr("Enter name of the macro:"),
6985 QLineEdit.EchoMode.Normal) 6987 QLineEdit.EchoMode.Normal,
6986 6988 )
6989
6987 if ok and name: 6990 if ok and name:
6988 self.macros[name] = self.curMacro 6991 self.macros[name] = self.curMacro
6989 6992
6990 self.curMacro = None 6993 self.curMacro = None
6991 6994
6992 ################################################################# 6995 #################################################################
6993 ## Overwritten methods 6996 ## Overwritten methods
6994 ################################################################# 6997 #################################################################
6995 6998
6996 def undo(self): 6999 def undo(self):
6997 """ 7000 """
6998 Public method to undo the last recorded change. 7001 Public method to undo the last recorded change.
6999 """ 7002 """
7000 super().undo() 7003 super().undo()
7001 self.undoAvailable.emit(self.isUndoAvailable()) 7004 self.undoAvailable.emit(self.isUndoAvailable())
7002 self.redoAvailable.emit(self.isRedoAvailable()) 7005 self.redoAvailable.emit(self.isRedoAvailable())
7003 7006
7004 def redo(self): 7007 def redo(self):
7005 """ 7008 """
7006 Public method to redo the last recorded change. 7009 Public method to redo the last recorded change.
7007 """ 7010 """
7008 super().redo() 7011 super().redo()
7009 self.undoAvailable.emit(self.isUndoAvailable()) 7012 self.undoAvailable.emit(self.isUndoAvailable())
7010 self.redoAvailable.emit(self.isRedoAvailable()) 7013 self.redoAvailable.emit(self.isRedoAvailable())
7011 7014
7012 def close(self, alsoDelete=False): 7015 def close(self, alsoDelete=False):
7013 """ 7016 """
7014 Public method called when the window gets closed. 7017 Public method called when the window gets closed.
7015 7018
7016 This overwritten method redirects the action to our 7019 This overwritten method redirects the action to our
7017 ViewManager.closeEditor, which in turn calls our closeIt 7020 ViewManager.closeEditor, which in turn calls our closeIt
7018 method. 7021 method.
7019 7022
7020 @param alsoDelete ignored 7023 @param alsoDelete ignored
7021 @return flag indicating a successful close of the editor (boolean) 7024 @return flag indicating a successful close of the editor (boolean)
7022 """ 7025 """
7023 return self.vm.closeEditor(self) 7026 return self.vm.closeEditor(self)
7024 7027
7025 def closeIt(self): 7028 def closeIt(self):
7026 """ 7029 """
7027 Public method called by the viewmanager to finally get rid of us. 7030 Public method called by the viewmanager to finally get rid of us.
7028 """ 7031 """
7029 if Preferences.getEditor("ClearBreaksOnClose") and not self.__clones: 7032 if Preferences.getEditor("ClearBreaksOnClose") and not self.__clones:
7030 self.__menuClearBreakpoints() 7033 self.__menuClearBreakpoints()
7031 7034
7032 for clone in self.__clones[:]: 7035 for clone in self.__clones[:]:
7033 self.removeClone(clone) 7036 self.removeClone(clone)
7034 clone.removeClone(self) 7037 clone.removeClone(self)
7035 7038
7036 self.breakpointModel.rowsAboutToBeRemoved.disconnect( 7039 self.breakpointModel.rowsAboutToBeRemoved.disconnect(self.__deleteBreakPoints)
7037 self.__deleteBreakPoints)
7038 self.breakpointModel.dataAboutToBeChanged.disconnect( 7040 self.breakpointModel.dataAboutToBeChanged.disconnect(
7039 self.__breakPointDataAboutToBeChanged) 7041 self.__breakPointDataAboutToBeChanged
7040 self.breakpointModel.dataChanged.disconnect( 7042 )
7041 self.__changeBreakPoints) 7043 self.breakpointModel.dataChanged.disconnect(self.__changeBreakPoints)
7042 self.breakpointModel.rowsInserted.disconnect( 7044 self.breakpointModel.rowsInserted.disconnect(self.__addBreakPoints)
7043 self.__addBreakPoints) 7045
7044
7045 if self.syntaxCheckService is not None: 7046 if self.syntaxCheckService is not None:
7046 self.syntaxCheckService.syntaxChecked.disconnect( 7047 self.syntaxCheckService.syntaxChecked.disconnect(
7047 self.__processSyntaxCheckResult) 7048 self.__processSyntaxCheckResult
7048 self.syntaxCheckService.error.disconnect( 7049 )
7049 self.__processSyntaxCheckError) 7050 self.syntaxCheckService.error.disconnect(self.__processSyntaxCheckError)
7050 7051
7051 if self.spell: 7052 if self.spell:
7052 self.spell.stopIncrementalCheck() 7053 self.spell.stopIncrementalCheck()
7053 7054
7054 with contextlib.suppress(TypeError): 7055 with contextlib.suppress(TypeError):
7055 self.project.projectPropertiesChanged.disconnect( 7056 self.project.projectPropertiesChanged.disconnect(
7056 self.__projectPropertiesChanged) 7057 self.__projectPropertiesChanged
7057 7058 )
7059
7058 if self.fileName: 7060 if self.fileName:
7059 self.taskViewer.clearFileTasks(self.fileName, True) 7061 self.taskViewer.clearFileTasks(self.fileName, True)
7060 7062
7061 super().close() 7063 super().close()
7062 7064
7063 def keyPressEvent(self, ev): 7065 def keyPressEvent(self, ev):
7064 """ 7066 """
7065 Protected method to handle the user input a key at a time. 7067 Protected method to handle the user input a key at a time.
7066 7068
7067 @param ev key event 7069 @param ev key event
7068 @type QKeyEvent 7070 @type QKeyEvent
7069 """ 7071 """
7072
7070 def encloseSelectedText(encString): 7073 def encloseSelectedText(encString):
7071 """ 7074 """
7072 Local function to enclose the current selection with some 7075 Local function to enclose the current selection with some
7073 characters. 7076 characters.
7074 7077
7075 @param encString string to use to enclose the selection 7078 @param encString string to use to enclose the selection
7076 (one or two characters) 7079 (one or two characters)
7077 @type str 7080 @type str
7078 """ 7081 """
7079 startChar = encString[0] 7082 startChar = encString[0]
7080 endChar = encString[1] if len(encString) == 2 else startChar 7083 endChar = encString[1] if len(encString) == 2 else startChar
7081 7084
7082 sline, sindex, eline, eindex = self.getSelection() 7085 sline, sindex, eline, eindex = self.getSelection()
7083 replaceText = startChar + self.selectedText() + endChar 7086 replaceText = startChar + self.selectedText() + endChar
7084 self.beginUndoAction() 7087 self.beginUndoAction()
7085 self.replaceSelectedText(replaceText) 7088 self.replaceSelectedText(replaceText)
7086 self.endUndoAction() 7089 self.endUndoAction()
7087 self.setSelection(sline, sindex + 1, eline, eindex + 1) 7090 self.setSelection(sline, sindex + 1, eline, eindex + 1)
7088 7091
7089 txt = ev.text() 7092 txt = ev.text()
7090 7093
7091 # See it is text to insert. 7094 # See it is text to insert.
7092 if len(txt) and txt >= " ": 7095 if len(txt) and txt >= " ":
7093 if ( 7096 if self.hasSelectedText() and txt in Editor.EncloseChars:
7094 self.hasSelectedText() and
7095 txt in Editor.EncloseChars
7096 ):
7097 encloseSelectedText(Editor.EncloseChars[txt]) 7097 encloseSelectedText(Editor.EncloseChars[txt])
7098 ev.accept() 7098 ev.accept()
7099 return 7099 return
7100 7100
7101 super().keyPressEvent(ev) 7101 super().keyPressEvent(ev)
7102 else: 7102 else:
7103 ev.ignore() 7103 ev.ignore()
7104 7104
7105 def focusInEvent(self, event): 7105 def focusInEvent(self, event):
7106 """ 7106 """
7107 Protected method called when the editor receives focus. 7107 Protected method called when the editor receives focus.
7108 7108
7109 This method checks for modifications of the current file and 7109 This method checks for modifications of the current file and
7110 rereads it upon request. The cursor is placed at the current position 7110 rereads it upon request. The cursor is placed at the current position
7111 assuming, that it is in the vicinity of the old position after the 7111 assuming, that it is in the vicinity of the old position after the
7112 reread. 7112 reread.
7113 7113
7114 @param event the event object 7114 @param event the event object
7115 @type QFocusEvent 7115 @type QFocusEvent
7116 """ 7116 """
7117 self.recolor() 7117 self.recolor()
7118 self.vm.editActGrp.setEnabled(True) 7118 self.vm.editActGrp.setEnabled(True)
7122 self.vm.searchActGrp.setEnabled(True) 7122 self.vm.searchActGrp.setEnabled(True)
7123 with contextlib.suppress(AttributeError): 7123 with contextlib.suppress(AttributeError):
7124 self.setCaretWidth(self.caretWidth) 7124 self.setCaretWidth(self.caretWidth)
7125 self.__updateReadOnly(False) 7125 self.__updateReadOnly(False)
7126 if ( 7126 if (
7127 self.vm.editorsCheckFocusInEnabled() and 7127 self.vm.editorsCheckFocusInEnabled()
7128 not self.inReopenPrompt and self.fileName and 7128 and not self.inReopenPrompt
7129 pathlib.Path(self.fileName).exists() and 7129 and self.fileName
7130 pathlib.Path(self.fileName).stat().st_mtime != self.lastModified 7130 and pathlib.Path(self.fileName).exists()
7131 and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified
7131 ): 7132 ):
7132 self.inReopenPrompt = True 7133 self.inReopenPrompt = True
7133 if Preferences.getEditor("AutoReopen") and not self.isModified(): 7134 if Preferences.getEditor("AutoReopen") and not self.isModified():
7134 self.refresh() 7135 self.refresh()
7135 else: 7136 else:
7139 ).format(self.fileName) 7140 ).format(self.fileName)
7140 yesDefault = True 7141 yesDefault = True
7141 if self.isModified(): 7142 if self.isModified():
7142 msg += self.tr( 7143 msg += self.tr(
7143 """<br><b>Warning:</b> You will lose""" 7144 """<br><b>Warning:</b> You will lose"""
7144 """ your changes upon reopening it.""") 7145 """ your changes upon reopening it."""
7146 )
7145 yesDefault = False 7147 yesDefault = False
7146 res = EricMessageBox.yesNo( 7148 res = EricMessageBox.yesNo(
7147 self, 7149 self,
7148 self.tr("File changed"), msg, 7150 self.tr("File changed"),
7151 msg,
7149 icon=EricMessageBox.Warning, 7152 icon=EricMessageBox.Warning,
7150 yesDefault=yesDefault) 7153 yesDefault=yesDefault,
7154 )
7151 if res: 7155 if res:
7152 self.refresh() 7156 self.refresh()
7153 else: 7157 else:
7154 # do not prompt for this change again... 7158 # do not prompt for this change again...
7155 self.lastModified = ( 7159 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
7156 pathlib.Path(self.fileName).stat().st_mtime
7157 )
7158 self.inReopenPrompt = False 7160 self.inReopenPrompt = False
7159 7161
7160 self.setCursorFlashTime(QApplication.cursorFlashTime()) 7162 self.setCursorFlashTime(QApplication.cursorFlashTime())
7161 7163
7162 super().focusInEvent(event) 7164 super().focusInEvent(event)
7163 7165
7164 def focusOutEvent(self, event): 7166 def focusOutEvent(self, event):
7165 """ 7167 """
7166 Protected method called when the editor loses focus. 7168 Protected method called when the editor loses focus.
7167 7169
7168 @param event the event object 7170 @param event the event object
7169 @type QFocusEvent 7171 @type QFocusEvent
7170 """ 7172 """
7171 self.vm.editorActGrp.setEnabled(False) 7173 self.vm.editorActGrp.setEnabled(False)
7172 self.setCaretWidth(0) 7174 self.setCaretWidth(0)
7173 7175
7174 self.cancelCallTips() 7176 self.cancelCallTips()
7175 7177
7176 super().focusOutEvent(event) 7178 super().focusOutEvent(event)
7177 7179
7178 def changeEvent(self, evt): 7180 def changeEvent(self, evt):
7179 """ 7181 """
7180 Protected method called to process an event. 7182 Protected method called to process an event.
7181 7183
7182 This implements special handling for the events showMaximized, 7184 This implements special handling for the events showMaximized,
7183 showMinimized and showNormal. The windows caption is shortened 7185 showMinimized and showNormal. The windows caption is shortened
7184 for the minimized mode and reset to the full filename for the 7186 for the minimized mode and reset to the full filename for the
7185 other modes. This is to make the editor windows work nicer 7187 other modes. This is to make the editor windows work nicer
7186 with the QWorkspace. 7188 with the QWorkspace.
7187 7189
7188 @param evt the event, that was generated 7190 @param evt the event, that was generated
7189 @type QEvent 7191 @type QEvent
7190 """ 7192 """
7191 if ( 7193 if evt.type() == QEvent.Type.WindowStateChange and bool(self.fileName):
7192 evt.type() == QEvent.Type.WindowStateChange and
7193 bool(self.fileName)
7194 ):
7195 cap = ( 7194 cap = (
7196 os.path.basename(self.fileName) 7195 os.path.basename(self.fileName)
7197 if self.windowState() == Qt.WindowState.WindowMinimized else 7196 if self.windowState() == Qt.WindowState.WindowMinimized
7198 self.fileName 7197 else self.fileName
7199 ) 7198 )
7200 if self.isReadOnly(): 7199 if self.isReadOnly():
7201 cap = self.tr("{0} (ro)").format(cap) 7200 cap = self.tr("{0} (ro)").format(cap)
7202 self.setWindowTitle(cap) 7201 self.setWindowTitle(cap)
7203 7202
7204 super().changeEvent(evt) 7203 super().changeEvent(evt)
7205 7204
7206 def mousePressEvent(self, event): 7205 def mousePressEvent(self, event):
7207 """ 7206 """
7208 Protected method to handle the mouse press event. 7207 Protected method to handle the mouse press event.
7209 7208
7210 @param event the mouse press event 7209 @param event the mouse press event
7211 @type QMouseEvent 7210 @type QMouseEvent
7212 """ 7211 """
7213 if event.button() == Qt.MouseButton.XButton1: 7212 if event.button() == Qt.MouseButton.XButton1:
7214 self.undo() 7213 self.undo()
7215 event.accept() 7214 event.accept()
7216 elif event.button() == Qt.MouseButton.XButton2: 7215 elif event.button() == Qt.MouseButton.XButton2:
7217 self.redo() 7216 self.redo()
7218 event.accept() 7217 event.accept()
7219 elif ( 7218 elif event.button() == Qt.MouseButton.LeftButton and bool(
7220 event.button() == Qt.MouseButton.LeftButton and 7219 event.modifiers()
7221 bool(event.modifiers() & ( 7220 & (Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.AltModifier)
7222 Qt.KeyboardModifier.MetaModifier |
7223 Qt.KeyboardModifier.AltModifier
7224 ))
7225 ): 7221 ):
7226 line, index = self.lineIndexFromPoint(event.position().toPoint()) 7222 line, index = self.lineIndexFromPoint(event.position().toPoint())
7227 self.addCursor(line, index) 7223 self.addCursor(line, index)
7228 event.accept() 7224 event.accept()
7229 else: 7225 else:
7230 self.vm.eventFilter(self, event) 7226 self.vm.eventFilter(self, event)
7231 super().mousePressEvent(event) 7227 super().mousePressEvent(event)
7232 7228
7233 def mouseDoubleClickEvent(self, evt): 7229 def mouseDoubleClickEvent(self, evt):
7234 """ 7230 """
7235 Protected method to handle mouse double click events. 7231 Protected method to handle mouse double click events.
7236 7232
7237 @param evt reference to the mouse event 7233 @param evt reference to the mouse event
7238 @type QMouseEvent 7234 @type QMouseEvent
7239 """ 7235 """
7240 super().mouseDoubleClickEvent(evt) 7236 super().mouseDoubleClickEvent(evt)
7241 7237
7242 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons()) 7238 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons())
7243 7239
7244 def wheelEvent(self, evt): 7240 def wheelEvent(self, evt):
7245 """ 7241 """
7246 Protected method to handle wheel events. 7242 Protected method to handle wheel events.
7247 7243
7248 @param evt reference to the wheel event 7244 @param evt reference to the wheel event
7249 @type QWheelEvent 7245 @type QWheelEvent
7250 """ 7246 """
7251 delta = evt.angleDelta().y() 7247 delta = evt.angleDelta().y()
7252 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier: 7248 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
7254 self.zoomOut() 7250 self.zoomOut()
7255 elif delta > 0: 7251 elif delta > 0:
7256 self.zoomIn() 7252 self.zoomIn()
7257 evt.accept() 7253 evt.accept()
7258 return 7254 return
7259 7255
7260 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier: 7256 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
7261 if delta < 0: 7257 if delta < 0:
7262 self.gotoMethodClass(False) 7258 self.gotoMethodClass(False)
7263 elif delta > 0: 7259 elif delta > 0:
7264 self.gotoMethodClass(True) 7260 self.gotoMethodClass(True)
7265 evt.accept() 7261 evt.accept()
7266 return 7262 return
7267 7263
7268 super().wheelEvent(evt) 7264 super().wheelEvent(evt)
7269 7265
7270 def event(self, evt): 7266 def event(self, evt):
7271 """ 7267 """
7272 Public method handling events. 7268 Public method handling events.
7273 7269
7274 @param evt reference to the event 7270 @param evt reference to the event
7275 @type QEvent 7271 @type QEvent
7276 @return flag indicating, if the event was handled 7272 @return flag indicating, if the event was handled
7277 @rtype bool 7273 @rtype bool
7278 """ 7274 """
7279 if evt.type() == QEvent.Type.Gesture: 7275 if evt.type() == QEvent.Type.Gesture:
7280 self.gestureEvent(evt) 7276 self.gestureEvent(evt)
7281 return True 7277 return True
7282 7278
7283 return super().event(evt) 7279 return super().event(evt)
7284 7280
7285 def gestureEvent(self, evt): 7281 def gestureEvent(self, evt):
7286 """ 7282 """
7287 Protected method handling gesture events. 7283 Protected method handling gesture events.
7288 7284
7289 @param evt reference to the gesture event 7285 @param evt reference to the gesture event
7290 @type QGestureEvent 7286 @type QGestureEvent
7291 """ 7287 """
7292 pinch = evt.gesture(Qt.GestureType.PinchGesture) 7288 pinch = evt.gesture(Qt.GestureType.PinchGesture)
7293 if pinch: 7289 if pinch:
7302 elif zoom >= 20: 7298 elif zoom >= 20:
7303 zoom = 20 7299 zoom = 20
7304 pinch.setTotalScaleFactor(3.0) 7300 pinch.setTotalScaleFactor(3.0)
7305 self.zoomTo(zoom) 7301 self.zoomTo(zoom)
7306 evt.accept() 7302 evt.accept()
7307 7303
7308 def resizeEvent(self, evt): 7304 def resizeEvent(self, evt):
7309 """ 7305 """
7310 Protected method handling resize events. 7306 Protected method handling resize events.
7311 7307
7312 @param evt reference to the resize event 7308 @param evt reference to the resize event
7313 @type QResizeEvent 7309 @type QResizeEvent
7314 """ 7310 """
7315 super().resizeEvent(evt) 7311 super().resizeEvent(evt)
7316 self.__markerMap.calculateGeometry() 7312 self.__markerMap.calculateGeometry()
7317 7313
7318 def viewportEvent(self, evt): 7314 def viewportEvent(self, evt):
7319 """ 7315 """
7320 Protected method handling event of the viewport. 7316 Protected method handling event of the viewport.
7321 7317
7322 @param evt reference to the event 7318 @param evt reference to the event
7323 @type QEvent 7319 @type QEvent
7324 @return flag indiating that the event was handled 7320 @return flag indiating that the event was handled
7325 @rtype bool 7321 @rtype bool
7326 """ 7322 """
7327 with contextlib.suppress(AttributeError): 7323 with contextlib.suppress(AttributeError):
7328 self.__markerMap.calculateGeometry() 7324 self.__markerMap.calculateGeometry()
7329 return super().viewportEvent(evt) 7325 return super().viewportEvent(evt)
7330 7326
7331 def __updateReadOnly(self, bForce=True): 7327 def __updateReadOnly(self, bForce=True):
7332 """ 7328 """
7333 Private method to update the readOnly information for this editor. 7329 Private method to update the readOnly information for this editor.
7334 7330
7335 If bForce is True, then updates everything regardless if 7331 If bForce is True, then updates everything regardless if
7336 the attributes have actually changed, such as during 7332 the attributes have actually changed, such as during
7337 initialization time. A signal is emitted after the 7333 initialization time. A signal is emitted after the
7338 caption change. 7334 caption change.
7339 7335
7340 @param bForce True to force change, False to only update and emit 7336 @param bForce True to force change, False to only update and emit
7341 signal if there was an attribute change. 7337 signal if there was an attribute change.
7342 """ 7338 """
7343 if self.fileName == "": 7339 if self.fileName == "":
7344 return 7340 return
7345 7341
7346 readOnly = ( 7342 readOnly = not os.access(self.fileName, os.W_OK) or self.isReadOnly()
7347 not os.access(self.fileName, os.W_OK) or
7348 self.isReadOnly()
7349 )
7350 if not bForce and (readOnly == self.isReadOnly()): 7343 if not bForce and (readOnly == self.isReadOnly()):
7351 return 7344 return
7352 7345
7353 cap = self.fileName 7346 cap = self.fileName
7354 if readOnly: 7347 if readOnly:
7355 cap = self.tr("{0} (ro)".format(cap)) 7348 cap = self.tr("{0} (ro)".format(cap))
7356 self.setReadOnly(readOnly) 7349 self.setReadOnly(readOnly)
7357 self.setWindowTitle(cap) 7350 self.setWindowTitle(cap)
7358 self.captionChanged.emit(cap, self) 7351 self.captionChanged.emit(cap, self)
7359 7352
7360 def refresh(self): 7353 def refresh(self):
7361 """ 7354 """
7362 Public slot to refresh the editor contents. 7355 Public slot to refresh the editor contents.
7363 """ 7356 """
7364 # save cursor position 7357 # save cursor position
7365 cline, cindex = self.getCursorPosition() 7358 cline, cindex = self.getCursorPosition()
7366 7359
7367 # save bookmarks and breakpoints and clear them 7360 # save bookmarks and breakpoints and clear them
7368 bmlist = self.getBookmarks() 7361 bmlist = self.getBookmarks()
7369 self.clearBookmarks() 7362 self.clearBookmarks()
7370 7363
7371 # clear syntax error markers 7364 # clear syntax error markers
7372 self.clearSyntaxError() 7365 self.clearSyntaxError()
7373 7366
7374 # clear flakes warning markers 7367 # clear flakes warning markers
7375 self.clearWarnings() 7368 self.clearWarnings()
7376 7369
7377 # clear breakpoint markers 7370 # clear breakpoint markers
7378 for handle in list(self.breaks.keys()): 7371 for handle in list(self.breaks.keys()):
7379 self.markerDeleteHandle(handle) 7372 self.markerDeleteHandle(handle)
7380 self.breaks.clear() 7373 self.breaks.clear()
7381 7374
7382 if not os.path.exists(self.fileName): 7375 if not os.path.exists(self.fileName):
7383 # close the file, if it was deleted in the background 7376 # close the file, if it was deleted in the background
7384 self.close() 7377 self.close()
7385 return 7378 return
7386 7379
7387 # reread the file 7380 # reread the file
7388 try: 7381 try:
7389 self.readFile(self.fileName) 7382 self.readFile(self.fileName)
7390 except OSError: 7383 except OSError:
7391 # do not prompt for this change again... 7384 # do not prompt for this change again...
7392 self.lastModified = QDateTime.currentDateTime() 7385 self.lastModified = QDateTime.currentDateTime()
7393 self.setModified(False) 7386 self.setModified(False)
7394 self.__convertTabs() 7387 self.__convertTabs()
7395 7388
7396 # re-initialize the online change tracer 7389 # re-initialize the online change tracer
7397 self.__reinitOnlineChangeTrace() 7390 self.__reinitOnlineChangeTrace()
7398 7391
7399 # reset cursor position 7392 # reset cursor position
7400 self.setCursorPosition(cline, cindex) 7393 self.setCursorPosition(cline, cindex)
7401 self.ensureCursorVisible() 7394 self.ensureCursorVisible()
7402 7395
7403 # reset bookmarks and breakpoints to their old position 7396 # reset bookmarks and breakpoints to their old position
7404 if bmlist: 7397 if bmlist:
7405 for bm in bmlist: 7398 for bm in bmlist:
7406 self.toggleBookmark(bm) 7399 self.toggleBookmark(bm)
7407 self.__restoreBreakpoints() 7400 self.__restoreBreakpoints()
7408 7401
7409 self.editorSaved.emit(self.fileName) 7402 self.editorSaved.emit(self.fileName)
7410 self.checkSyntax() 7403 self.checkSyntax()
7411 7404
7412 self.__markerMap.update() 7405 self.__markerMap.update()
7413 7406
7414 self.refreshed.emit() 7407 self.refreshed.emit()
7415 7408
7416 def setMonospaced(self, on): 7409 def setMonospaced(self, on):
7417 """ 7410 """
7418 Public method to set/reset a monospaced font. 7411 Public method to set/reset a monospaced font.
7419 7412
7420 @param on flag to indicate usage of a monospace font (boolean) 7413 @param on flag to indicate usage of a monospace font (boolean)
7421 """ 7414 """
7422 if on: 7415 if on:
7423 if not self.lexer_: 7416 if not self.lexer_:
7424 f = Preferences.getEditorOtherFonts("MonospacedFont") 7417 f = Preferences.getEditorOtherFonts("MonospacedFont")
7426 else: 7419 else:
7427 if not self.lexer_: 7420 if not self.lexer_:
7428 self.clearStyles() 7421 self.clearStyles()
7429 self.__setMarginsDisplay() 7422 self.__setMarginsDisplay()
7430 self.setFont(Preferences.getEditorOtherFonts("DefaultFont")) 7423 self.setFont(Preferences.getEditorOtherFonts("DefaultFont"))
7431 7424
7432 self.useMonospaced = on 7425 self.useMonospaced = on
7433 7426
7434 def clearStyles(self): 7427 def clearStyles(self):
7435 """ 7428 """
7436 Public method to set the styles according the selected Qt style 7429 Public method to set the styles according the selected Qt style
7437 or the selected editor colours. 7430 or the selected editor colours.
7438 """ 7431 """
7439 super().clearStyles() 7432 super().clearStyles()
7440 if Preferences.getEditor("OverrideEditAreaColours"): 7433 if Preferences.getEditor("OverrideEditAreaColours"):
7441 self.setColor(Preferences.getEditorColour("EditAreaForeground")) 7434 self.setColor(Preferences.getEditorColour("EditAreaForeground"))
7442 self.setPaper(Preferences.getEditorColour("EditAreaBackground")) 7435 self.setPaper(Preferences.getEditorColour("EditAreaBackground"))
7443 7436
7444 ################################################################# 7437 #################################################################
7445 ## Drag and Drop Support 7438 ## Drag and Drop Support
7446 ################################################################# 7439 #################################################################
7447 7440
7448 def dragEnterEvent(self, event): 7441 def dragEnterEvent(self, event):
7449 """ 7442 """
7450 Protected method to handle the drag enter event. 7443 Protected method to handle the drag enter event.
7451 7444
7452 @param event the drag enter event (QDragEnterEvent) 7445 @param event the drag enter event (QDragEnterEvent)
7453 """ 7446 """
7454 self.inDragDrop = event.mimeData().hasUrls() 7447 self.inDragDrop = event.mimeData().hasUrls()
7455 if self.inDragDrop: 7448 if self.inDragDrop:
7456 event.acceptProposedAction() 7449 event.acceptProposedAction()
7457 else: 7450 else:
7458 super().dragEnterEvent(event) 7451 super().dragEnterEvent(event)
7459 7452
7460 def dragMoveEvent(self, event): 7453 def dragMoveEvent(self, event):
7461 """ 7454 """
7462 Protected method to handle the drag move event. 7455 Protected method to handle the drag move event.
7463 7456
7464 @param event the drag move event (QDragMoveEvent) 7457 @param event the drag move event (QDragMoveEvent)
7465 """ 7458 """
7466 if self.inDragDrop: 7459 if self.inDragDrop:
7467 event.accept() 7460 event.accept()
7468 else: 7461 else:
7469 super().dragMoveEvent(event) 7462 super().dragMoveEvent(event)
7470 7463
7471 def dragLeaveEvent(self, event): 7464 def dragLeaveEvent(self, event):
7472 """ 7465 """
7473 Protected method to handle the drag leave event. 7466 Protected method to handle the drag leave event.
7474 7467
7475 @param event the drag leave event (QDragLeaveEvent) 7468 @param event the drag leave event (QDragLeaveEvent)
7476 """ 7469 """
7477 if self.inDragDrop: 7470 if self.inDragDrop:
7478 self.inDragDrop = False 7471 self.inDragDrop = False
7479 event.accept() 7472 event.accept()
7480 else: 7473 else:
7481 super().dragLeaveEvent(event) 7474 super().dragLeaveEvent(event)
7482 7475
7483 def dropEvent(self, event): 7476 def dropEvent(self, event):
7484 """ 7477 """
7485 Protected method to handle the drop event. 7478 Protected method to handle the drop event.
7486 7479
7487 @param event the drop event (QDropEvent) 7480 @param event the drop event (QDropEvent)
7488 """ 7481 """
7489 if event.mimeData().hasUrls(): 7482 if event.mimeData().hasUrls():
7490 for url in event.mimeData().urls(): 7483 for url in event.mimeData().urls():
7491 fname = url.toLocalFile() 7484 fname = url.toLocalFile()
7494 self.vm.openSourceFile(fname) 7487 self.vm.openSourceFile(fname)
7495 else: 7488 else:
7496 EricMessageBox.information( 7489 EricMessageBox.information(
7497 self, 7490 self,
7498 self.tr("Drop Error"), 7491 self.tr("Drop Error"),
7499 self.tr("""<p><b>{0}</b> is not a file.</p>""") 7492 self.tr("""<p><b>{0}</b> is not a file.</p>""").format(
7500 .format(fname)) 7493 fname
7494 ),
7495 )
7501 event.acceptProposedAction() 7496 event.acceptProposedAction()
7502 else: 7497 else:
7503 super().dropEvent(event) 7498 super().dropEvent(event)
7504 7499
7505 self.inDragDrop = False 7500 self.inDragDrop = False
7506 7501
7507 ################################################################# 7502 #################################################################
7508 ## Support for Qt resources files 7503 ## Support for Qt resources files
7509 ################################################################# 7504 #################################################################
7510 7505
7511 def __initContextMenuResources(self): 7506 def __initContextMenuResources(self):
7512 """ 7507 """
7513 Private method used to setup the Resources context sub menu. 7508 Private method used to setup the Resources context sub menu.
7514 7509
7515 @return reference to the generated menu (QMenu) 7510 @return reference to the generated menu (QMenu)
7516 """ 7511 """
7517 menu = QMenu(self.tr('Resources')) 7512 menu = QMenu(self.tr("Resources"))
7518 7513
7514 menu.addAction(self.tr("Add file..."), self.__addFileResource)
7515 menu.addAction(self.tr("Add files..."), self.__addFileResources)
7516 menu.addAction(self.tr("Add aliased file..."), self.__addFileAliasResource)
7519 menu.addAction( 7517 menu.addAction(
7520 self.tr('Add file...'), self.__addFileResource) 7518 self.tr("Add localized resource..."), self.__addLocalizedResource
7521 menu.addAction( 7519 )
7522 self.tr('Add files...'), self.__addFileResources)
7523 menu.addAction(
7524 self.tr('Add aliased file...'),
7525 self.__addFileAliasResource)
7526 menu.addAction(
7527 self.tr('Add localized resource...'),
7528 self.__addLocalizedResource)
7529 menu.addSeparator() 7520 menu.addSeparator()
7530 menu.addAction( 7521 menu.addAction(self.tr("Add resource frame"), self.__addResourceFrame)
7531 self.tr('Add resource frame'), self.__addResourceFrame) 7522
7532
7533 menu.aboutToShow.connect(self.__showContextMenuResources) 7523 menu.aboutToShow.connect(self.__showContextMenuResources)
7534 7524
7535 return menu 7525 return menu
7536 7526
7537 def __showContextMenuResources(self): 7527 def __showContextMenuResources(self):
7538 """ 7528 """
7539 Private slot handling the aboutToShow signal of the resources context 7529 Private slot handling the aboutToShow signal of the resources context
7540 menu. 7530 menu.
7541 """ 7531 """
7542 self.showMenu.emit("Resources", self.resourcesMenu, self) 7532 self.showMenu.emit("Resources", self.resourcesMenu, self)
7543 7533
7544 def __addFileResource(self): 7534 def __addFileResource(self):
7545 """ 7535 """
7546 Private method to handle the Add file context menu action. 7536 Private method to handle the Add file context menu action.
7547 """ 7537 """
7548 dirStr = os.path.dirname(self.fileName) 7538 dirStr = os.path.dirname(self.fileName)
7549 file = EricFileDialog.getOpenFileName( 7539 file = EricFileDialog.getOpenFileName(
7550 self, 7540 self, self.tr("Add file resource"), dirStr, ""
7551 self.tr("Add file resource"), 7541 )
7552 dirStr,
7553 "")
7554 if file: 7542 if file:
7555 relFile = QDir(dirStr).relativeFilePath(file) 7543 relFile = QDir(dirStr).relativeFilePath(file)
7556 line, index = self.getCursorPosition() 7544 line, index = self.getCursorPosition()
7557 self.insert(" <file>{0}</file>\n".format(relFile)) 7545 self.insert(" <file>{0}</file>\n".format(relFile))
7558 self.setCursorPosition(line + 1, index) 7546 self.setCursorPosition(line + 1, index)
7559 7547
7560 def __addFileResources(self): 7548 def __addFileResources(self):
7561 """ 7549 """
7562 Private method to handle the Add files context menu action. 7550 Private method to handle the Add files context menu action.
7563 """ 7551 """
7564 dirStr = os.path.dirname(self.fileName) 7552 dirStr = os.path.dirname(self.fileName)
7565 files = EricFileDialog.getOpenFileNames( 7553 files = EricFileDialog.getOpenFileNames(
7566 self, 7554 self, self.tr("Add file resources"), dirStr, ""
7567 self.tr("Add file resources"), 7555 )
7568 dirStr,
7569 "")
7570 if files: 7556 if files:
7571 myDir = QDir(dirStr) 7557 myDir = QDir(dirStr)
7572 filesText = "" 7558 filesText = ""
7573 for file in files: 7559 for file in files:
7574 relFile = myDir.relativeFilePath(file) 7560 relFile = myDir.relativeFilePath(file)
7575 filesText += " <file>{0}</file>\n".format(relFile) 7561 filesText += " <file>{0}</file>\n".format(relFile)
7576 line, index = self.getCursorPosition() 7562 line, index = self.getCursorPosition()
7577 self.insert(filesText) 7563 self.insert(filesText)
7578 self.setCursorPosition(line + len(files), index) 7564 self.setCursorPosition(line + len(files), index)
7579 7565
7580 def __addFileAliasResource(self): 7566 def __addFileAliasResource(self):
7581 """ 7567 """
7582 Private method to handle the Add aliased file context menu action. 7568 Private method to handle the Add aliased file context menu action.
7583 """ 7569 """
7584 dirStr = os.path.dirname(self.fileName) 7570 dirStr = os.path.dirname(self.fileName)
7585 file = EricFileDialog.getOpenFileName( 7571 file = EricFileDialog.getOpenFileName(
7586 self, 7572 self, self.tr("Add aliased file resource"), dirStr, ""
7587 self.tr("Add aliased file resource"), 7573 )
7588 dirStr,
7589 "")
7590 if file: 7574 if file:
7591 relFile = QDir(dirStr).relativeFilePath(file) 7575 relFile = QDir(dirStr).relativeFilePath(file)
7592 alias, ok = QInputDialog.getText( 7576 alias, ok = QInputDialog.getText(
7593 self, 7577 self,
7594 self.tr("Add aliased file resource"), 7578 self.tr("Add aliased file resource"),
7595 self.tr("Alias for file <b>{0}</b>:").format(relFile), 7579 self.tr("Alias for file <b>{0}</b>:").format(relFile),
7596 QLineEdit.EchoMode.Normal, 7580 QLineEdit.EchoMode.Normal,
7597 relFile) 7581 relFile,
7582 )
7598 if ok and alias: 7583 if ok and alias:
7599 line, index = self.getCursorPosition() 7584 line, index = self.getCursorPosition()
7600 self.insert(' <file alias="{1}">{0}</file>\n' 7585 self.insert(' <file alias="{1}">{0}</file>\n'.format(relFile, alias))
7601 .format(relFile, alias))
7602 self.setCursorPosition(line + 1, index) 7586 self.setCursorPosition(line + 1, index)
7603 7587
7604 def __addLocalizedResource(self): 7588 def __addLocalizedResource(self):
7605 """ 7589 """
7606 Private method to handle the Add localized resource context menu 7590 Private method to handle the Add localized resource context menu
7607 action. 7591 action.
7608 """ 7592 """
7609 from Project.AddLanguageDialog import AddLanguageDialog 7593 from Project.AddLanguageDialog import AddLanguageDialog
7594
7610 dlg = AddLanguageDialog(self) 7595 dlg = AddLanguageDialog(self)
7611 if dlg.exec() == QDialog.DialogCode.Accepted: 7596 if dlg.exec() == QDialog.DialogCode.Accepted:
7612 lang = dlg.getSelectedLanguage() 7597 lang = dlg.getSelectedLanguage()
7613 line, index = self.getCursorPosition() 7598 line, index = self.getCursorPosition()
7614 self.insert('<qresource lang="{0}">\n</qresource>\n'.format(lang)) 7599 self.insert('<qresource lang="{0}">\n</qresource>\n'.format(lang))
7615 self.setCursorPosition(line + 2, index) 7600 self.setCursorPosition(line + 2, index)
7616 7601
7617 def __addResourceFrame(self): 7602 def __addResourceFrame(self):
7618 """ 7603 """
7619 Private method to handle the Add resource frame context menu action. 7604 Private method to handle the Add resource frame context menu action.
7620 """ 7605 """
7621 line, index = self.getCursorPosition() 7606 line, index = self.getCursorPosition()
7622 self.insert('<!DOCTYPE RCC>\n' 7607 self.insert(
7623 '<RCC version="1.0">\n' 7608 "<!DOCTYPE RCC>\n"
7624 '<qresource>\n' 7609 '<RCC version="1.0">\n'
7625 '</qresource>\n' 7610 "<qresource>\n"
7626 '</RCC>\n') 7611 "</qresource>\n"
7612 "</RCC>\n"
7613 )
7627 self.setCursorPosition(line + 5, index) 7614 self.setCursorPosition(line + 5, index)
7628 7615
7629 ################################################################# 7616 #################################################################
7630 ## Support for diagrams below 7617 ## Support for diagrams below
7631 ################################################################# 7618 #################################################################
7632 7619
7633 def __showClassDiagram(self): 7620 def __showClassDiagram(self):
7634 """ 7621 """
7635 Private method to handle the Class Diagram context menu action. 7622 Private method to handle the Class Diagram context menu action.
7636 """ 7623 """
7637 from Graphics.UMLDialog import UMLDialog, UMLDialogType 7624 from Graphics.UMLDialog import UMLDialog, UMLDialogType
7625
7638 if not self.checkDirty(): 7626 if not self.checkDirty():
7639 return 7627 return
7640 7628
7641 self.classDiagram = UMLDialog( 7629 self.classDiagram = UMLDialog(
7642 UMLDialogType.CLASS_DIAGRAM, self.project, self.fileName, 7630 UMLDialogType.CLASS_DIAGRAM,
7643 self, noAttrs=False) 7631 self.project,
7632 self.fileName,
7633 self,
7634 noAttrs=False,
7635 )
7644 self.classDiagram.show() 7636 self.classDiagram.show()
7645 7637
7646 def __showPackageDiagram(self): 7638 def __showPackageDiagram(self):
7647 """ 7639 """
7648 Private method to handle the Package Diagram context menu action. 7640 Private method to handle the Package Diagram context menu action.
7649 """ 7641 """
7650 from Graphics.UMLDialog import UMLDialog, UMLDialogType 7642 from Graphics.UMLDialog import UMLDialog, UMLDialogType
7643
7651 if not self.checkDirty(): 7644 if not self.checkDirty():
7652 return 7645 return
7653 7646
7654 package = ( 7647 package = (
7655 os.path.isdir(self.fileName) and 7648 os.path.isdir(self.fileName)
7656 self.fileName or os.path.dirname(self.fileName) 7649 and self.fileName
7650 or os.path.dirname(self.fileName)
7657 ) 7651 )
7658 res = EricMessageBox.yesNo( 7652 res = EricMessageBox.yesNo(
7659 self, 7653 self,
7660 self.tr("Package Diagram"), 7654 self.tr("Package Diagram"),
7661 self.tr("""Include class attributes?"""), 7655 self.tr("""Include class attributes?"""),
7662 yesDefault=True) 7656 yesDefault=True,
7657 )
7663 self.packageDiagram = UMLDialog( 7658 self.packageDiagram = UMLDialog(
7664 UMLDialogType.PACKAGE_DIAGRAM, self.project, package, 7659 UMLDialogType.PACKAGE_DIAGRAM, self.project, package, self, noAttrs=not res
7665 self, noAttrs=not res) 7660 )
7666 self.packageDiagram.show() 7661 self.packageDiagram.show()
7667 7662
7668 def __showImportsDiagram(self): 7663 def __showImportsDiagram(self):
7669 """ 7664 """
7670 Private method to handle the Imports Diagram context menu action. 7665 Private method to handle the Imports Diagram context menu action.
7671 """ 7666 """
7672 from Graphics.UMLDialog import UMLDialog, UMLDialogType 7667 from Graphics.UMLDialog import UMLDialog, UMLDialogType
7668
7673 if not self.checkDirty(): 7669 if not self.checkDirty():
7674 return 7670 return
7675 7671
7676 package = os.path.dirname(self.fileName) 7672 package = os.path.dirname(self.fileName)
7677 res = EricMessageBox.yesNo( 7673 res = EricMessageBox.yesNo(
7678 self, 7674 self,
7679 self.tr("Imports Diagram"), 7675 self.tr("Imports Diagram"),
7680 self.tr("""Include imports from external modules?""")) 7676 self.tr("""Include imports from external modules?"""),
7677 )
7681 self.importsDiagram = UMLDialog( 7678 self.importsDiagram = UMLDialog(
7682 UMLDialogType.IMPORTS_DIAGRAM, self.project, package, 7679 UMLDialogType.IMPORTS_DIAGRAM,
7683 self, showExternalImports=res) 7680 self.project,
7681 package,
7682 self,
7683 showExternalImports=res,
7684 )
7684 self.importsDiagram.show() 7685 self.importsDiagram.show()
7685 7686
7686 def __showApplicationDiagram(self): 7687 def __showApplicationDiagram(self):
7687 """ 7688 """
7688 Private method to handle the Imports Diagram context menu action. 7689 Private method to handle the Imports Diagram context menu action.
7689 """ 7690 """
7690 from Graphics.UMLDialog import UMLDialog, UMLDialogType 7691 from Graphics.UMLDialog import UMLDialog, UMLDialogType
7692
7691 res = EricMessageBox.yesNo( 7693 res = EricMessageBox.yesNo(
7692 self, 7694 self,
7693 self.tr("Application Diagram"), 7695 self.tr("Application Diagram"),
7694 self.tr("""Include module names?"""), 7696 self.tr("""Include module names?"""),
7695 yesDefault=True) 7697 yesDefault=True,
7698 )
7696 self.applicationDiagram = UMLDialog( 7699 self.applicationDiagram = UMLDialog(
7697 UMLDialogType.APPLICATION_DIAGRAM, self.project, 7700 UMLDialogType.APPLICATION_DIAGRAM, self.project, self, noModules=not res
7698 self, noModules=not res) 7701 )
7699 self.applicationDiagram.show() 7702 self.applicationDiagram.show()
7700 7703
7701 def __loadDiagram(self): 7704 def __loadDiagram(self):
7702 """ 7705 """
7703 Private slot to load a diagram from file. 7706 Private slot to load a diagram from file.
7704 """ 7707 """
7705 from Graphics.UMLDialog import UMLDialog, UMLDialogType 7708 from Graphics.UMLDialog import UMLDialog, UMLDialogType
7709
7706 self.loadedDiagram = UMLDialog( 7710 self.loadedDiagram = UMLDialog(
7707 UMLDialogType.NO_DIAGRAM, self.project, parent=self) 7711 UMLDialogType.NO_DIAGRAM, self.project, parent=self
7712 )
7708 if self.loadedDiagram.load(): 7713 if self.loadedDiagram.load():
7709 self.loadedDiagram.show(fromFile=True) 7714 self.loadedDiagram.show(fromFile=True)
7710 else: 7715 else:
7711 self.loadedDiagram = None 7716 self.loadedDiagram = None
7712 7717
7713 ####################################################################### 7718 #######################################################################
7714 ## Typing aids related methods below 7719 ## Typing aids related methods below
7715 ####################################################################### 7720 #######################################################################
7716 7721
7717 def __toggleTypingAids(self): 7722 def __toggleTypingAids(self):
7718 """ 7723 """
7719 Private slot to toggle the typing aids. 7724 Private slot to toggle the typing aids.
7720 """ 7725 """
7721 if self.menuActs["TypingAidsEnabled"].isChecked(): 7726 if self.menuActs["TypingAidsEnabled"].isChecked():
7722 self.completer.setEnabled(True) 7727 self.completer.setEnabled(True)
7723 else: 7728 else:
7724 self.completer.setEnabled(False) 7729 self.completer.setEnabled(False)
7725 7730
7726 ####################################################################### 7731 #######################################################################
7727 ## Auto-completing templates 7732 ## Auto-completing templates
7728 ####################################################################### 7733 #######################################################################
7729 7734
7730 def editorCommand(self, cmd): 7735 def editorCommand(self, cmd):
7731 """ 7736 """
7732 Public method to perform a simple editor command. 7737 Public method to perform a simple editor command.
7733 7738
7734 @param cmd the scintilla command to be performed 7739 @param cmd the scintilla command to be performed
7735 """ 7740 """
7736 if cmd == QsciScintilla.SCI_TAB: 7741 if cmd == QsciScintilla.SCI_TAB:
7737 try: 7742 try:
7738 templateViewer = ericApp().getObject("TemplateViewer") 7743 templateViewer = ericApp().getObject("TemplateViewer")
7739 except KeyError: 7744 except KeyError:
7740 # template viewer is not active 7745 # template viewer is not active
7741 templateViewer = None 7746 templateViewer = None
7742 7747
7743 if templateViewer is not None: 7748 if templateViewer is not None:
7744 line, index = self.getCursorPosition() 7749 line, index = self.getCursorPosition()
7745 tmplName = self.getWordLeft(line, index) 7750 tmplName = self.getWordLeft(line, index)
7746 if tmplName: 7751 if tmplName:
7747 if templateViewer.hasTemplate(tmplName, 7752 if templateViewer.hasTemplate(tmplName, self.getLanguage()):
7748 self.getLanguage()):
7749 self.__applyTemplate(tmplName, self.getLanguage()) 7753 self.__applyTemplate(tmplName, self.getLanguage())
7750 return 7754 return
7751 else: 7755 else:
7752 templateNames = templateViewer.getTemplateNames( 7756 templateNames = templateViewer.getTemplateNames(
7753 tmplName, self.getLanguage()) 7757 tmplName, self.getLanguage()
7758 )
7754 if len(templateNames) == 1: 7759 if len(templateNames) == 1:
7755 self.__applyTemplate(templateNames[0], 7760 self.__applyTemplate(templateNames[0], self.getLanguage())
7756 self.getLanguage())
7757 return 7761 return
7758 elif len(templateNames) > 1: 7762 elif len(templateNames) > 1:
7759 self.showUserList( 7763 self.showUserList(
7760 TemplateCompletionListID, 7764 TemplateCompletionListID,
7761 ["{0}?{1:d}".format(t, self.TemplateImageID) 7765 [
7762 for t in templateNames]) 7766 "{0}?{1:d}".format(t, self.TemplateImageID)
7767 for t in templateNames
7768 ],
7769 )
7763 return 7770 return
7764 7771
7765 elif cmd == QsciScintilla.SCI_DELETEBACK: 7772 elif cmd == QsciScintilla.SCI_DELETEBACK:
7766 line, index = self.getCursorPosition() 7773 line, index = self.getCursorPosition()
7767 text = self.text(line)[index - 1:index + 1] 7774 text = self.text(line)[index - 1 : index + 1]
7768 matchingPairs = ['()', '[]', '{}', '<>', "''", '""'] 7775 matchingPairs = ["()", "[]", "{}", "<>", "''", '""']
7769 # __IGNORE_WARNING_M613__ 7776 # __IGNORE_WARNING_M613__
7770 if text in matchingPairs: 7777 if text in matchingPairs:
7771 self.delete() 7778 self.delete()
7772 7779
7773 super().editorCommand(cmd) 7780 super().editorCommand(cmd)
7774 7781
7775 def __applyTemplate(self, templateName, language): 7782 def __applyTemplate(self, templateName, language):
7776 """ 7783 """
7777 Private method to apply a template by name. 7784 Private method to apply a template by name.
7778 7785
7779 @param templateName name of the template to apply (string) 7786 @param templateName name of the template to apply (string)
7780 @param language name of the language (group) to get the template 7787 @param language name of the language (group) to get the template
7781 from (string) 7788 from (string)
7782 """ 7789 """
7783 try: 7790 try:
7784 templateViewer = ericApp().getObject("TemplateViewer") 7791 templateViewer = ericApp().getObject("TemplateViewer")
7785 except KeyError: 7792 except KeyError:
7786 # template viewer is not active 7793 # template viewer is not active
7787 return 7794 return
7788 7795
7789 if templateViewer.hasTemplate(templateName, self.getLanguage()): 7796 if templateViewer.hasTemplate(templateName, self.getLanguage()):
7790 self.extendSelectionWordLeft() 7797 self.extendSelectionWordLeft()
7791 templateViewer.applyNamedTemplate(templateName, 7798 templateViewer.applyNamedTemplate(templateName, self.getLanguage())
7792 self.getLanguage()) 7799
7793
7794 ####################################################################### 7800 #######################################################################
7795 ## Project related methods 7801 ## Project related methods
7796 ####################################################################### 7802 #######################################################################
7797 7803
7798 def __projectPropertiesChanged(self): 7804 def __projectPropertiesChanged(self):
7799 """ 7805 """
7800 Private slot to handle changes of the project properties. 7806 Private slot to handle changes of the project properties.
7801 """ 7807 """
7802 if self.spell: 7808 if self.spell:
7803 pwl, pel = self.project.getProjectDictionaries() 7809 pwl, pel = self.project.getProjectDictionaries()
7804 self.__setSpellingLanguage(self.project.getProjectSpellLanguage(), 7810 self.__setSpellingLanguage(
7805 pwl=pwl, pel=pel) 7811 self.project.getProjectSpellLanguage(), pwl=pwl, pel=pel
7806 7812 )
7813
7807 editorConfigEol = self.__getEditorConfig("EOLMode", nodefault=True) 7814 editorConfigEol = self.__getEditorConfig("EOLMode", nodefault=True)
7808 if editorConfigEol is not None: 7815 if editorConfigEol is not None:
7809 self.setEolMode(editorConfigEol) 7816 self.setEolMode(editorConfigEol)
7810 else: 7817 else:
7811 self.setEolModeByEolString(self.project.getEolString()) 7818 self.setEolModeByEolString(self.project.getEolString())
7812 self.convertEols(self.eolMode()) 7819 self.convertEols(self.eolMode())
7813 7820
7814 def addedToProject(self): 7821 def addedToProject(self):
7815 """ 7822 """
7816 Public method to signal, that this editor has been added to a project. 7823 Public method to signal, that this editor has been added to a project.
7817 """ 7824 """
7818 if self.spell: 7825 if self.spell:
7819 pwl, pel = self.project.getProjectDictionaries() 7826 pwl, pel = self.project.getProjectDictionaries()
7820 self.__setSpellingLanguage(self.project.getProjectSpellLanguage(), 7827 self.__setSpellingLanguage(
7821 pwl=pwl, pel=pel) 7828 self.project.getProjectSpellLanguage(), pwl=pwl, pel=pel
7822 7829 )
7823 self.project.projectPropertiesChanged.connect( 7830
7824 self.__projectPropertiesChanged) 7831 self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged)
7825 7832
7826 def projectOpened(self): 7833 def projectOpened(self):
7827 """ 7834 """
7828 Public slot to handle the opening of a project. 7835 Public slot to handle the opening of a project.
7829 """ 7836 """
7830 if ( 7837 if self.fileName and self.project.isProjectSource(self.fileName):
7831 self.fileName and
7832 self.project.isProjectSource(self.fileName)
7833 ):
7834 self.project.projectPropertiesChanged.connect( 7838 self.project.projectPropertiesChanged.connect(
7835 self.__projectPropertiesChanged) 7839 self.__projectPropertiesChanged
7840 )
7836 self.setSpellingForProject() 7841 self.setSpellingForProject()
7837 7842
7838 def projectClosed(self): 7843 def projectClosed(self):
7839 """ 7844 """
7840 Public slot to handle the closing of a project. 7845 Public slot to handle the closing of a project.
7841 """ 7846 """
7842 with contextlib.suppress(TypeError): 7847 with contextlib.suppress(TypeError):
7843 self.project.projectPropertiesChanged.disconnect( 7848 self.project.projectPropertiesChanged.disconnect(
7844 self.__projectPropertiesChanged) 7849 self.__projectPropertiesChanged
7845 7850 )
7851
7846 ####################################################################### 7852 #######################################################################
7847 ## Spell checking related methods 7853 ## Spell checking related methods
7848 ####################################################################### 7854 #######################################################################
7849 7855
7850 def getSpellingLanguage(self): 7856 def getSpellingLanguage(self):
7851 """ 7857 """
7852 Public method to get the current spelling language. 7858 Public method to get the current spelling language.
7853 7859
7854 @return current spelling language 7860 @return current spelling language
7855 @rtype str 7861 @rtype str
7856 """ 7862 """
7857 if self.spell: 7863 if self.spell:
7858 return self.spell.getLanguage() 7864 return self.spell.getLanguage()
7859 7865
7860 return "" 7866 return ""
7861 7867
7862 def __setSpellingLanguage(self, language, pwl="", pel=""): 7868 def __setSpellingLanguage(self, language, pwl="", pel=""):
7863 """ 7869 """
7864 Private slot to set the spell checking language. 7870 Private slot to set the spell checking language.
7865 7871
7866 @param language spell checking language to be set (string) 7872 @param language spell checking language to be set (string)
7867 @param pwl name of the personal/project word list (string) 7873 @param pwl name of the personal/project word list (string)
7868 @param pel name of the personal/project exclude list (string) 7874 @param pel name of the personal/project exclude list (string)
7869 """ 7875 """
7870 if self.spell and self.spell.getLanguage() != language: 7876 if self.spell and self.spell.getLanguage() != language:
7871 self.spell.setLanguage(language, pwl=pwl, pel=pel) 7877 self.spell.setLanguage(language, pwl=pwl, pel=pel)
7872 self.spell.checkDocumentIncrementally() 7878 self.spell.checkDocumentIncrementally()
7873 7879
7874 def __setSpelling(self): 7880 def __setSpelling(self):
7875 """ 7881 """
7876 Private method to initialize the spell checking functionality. 7882 Private method to initialize the spell checking functionality.
7877 """ 7883 """
7878 if Preferences.getEditor("SpellCheckingEnabled"): 7884 if Preferences.getEditor("SpellCheckingEnabled"):
7879 self.__spellCheckStringsOnly = Preferences.getEditor( 7885 self.__spellCheckStringsOnly = Preferences.getEditor(
7880 "SpellCheckStringsOnly") 7886 "SpellCheckStringsOnly"
7887 )
7881 if self.spell is None: 7888 if self.spell is None:
7882 self.spell = SpellChecker(self, self.spellingIndicator, 7889 self.spell = SpellChecker(
7883 checkRegion=self.isSpellCheckRegion) 7890 self, self.spellingIndicator, checkRegion=self.isSpellCheckRegion
7891 )
7884 self.setSpellingForProject() 7892 self.setSpellingForProject()
7885 self.spell.setMinimumWordSize( 7893 self.spell.setMinimumWordSize(
7886 Preferences.getEditor("SpellCheckingMinWordSize")) 7894 Preferences.getEditor("SpellCheckingMinWordSize")
7887 7895 )
7896
7888 self.setAutoSpellChecking() 7897 self.setAutoSpellChecking()
7889 else: 7898 else:
7890 self.spell = None 7899 self.spell = None
7891 self.clearAllIndicators(self.spellingIndicator) 7900 self.clearAllIndicators(self.spellingIndicator)
7892 7901
7894 """ 7903 """
7895 Public method to set the spell checking options for files belonging 7904 Public method to set the spell checking options for files belonging
7896 to the current project. 7905 to the current project.
7897 """ 7906 """
7898 if ( 7907 if (
7899 self.fileName and 7908 self.fileName
7900 self.project.isOpen() and 7909 and self.project.isOpen()
7901 self.project.isProjectSource(self.fileName) 7910 and self.project.isProjectSource(self.fileName)
7902 ): 7911 ):
7903 pwl, pel = self.project.getProjectDictionaries() 7912 pwl, pel = self.project.getProjectDictionaries()
7904 self.__setSpellingLanguage(self.project.getProjectSpellLanguage(), 7913 self.__setSpellingLanguage(
7905 pwl=pwl, pel=pel) 7914 self.project.getProjectSpellLanguage(), pwl=pwl, pel=pel
7906 7915 )
7916
7907 def setAutoSpellChecking(self): 7917 def setAutoSpellChecking(self):
7908 """ 7918 """
7909 Public method to set the automatic spell checking. 7919 Public method to set the automatic spell checking.
7910 """ 7920 """
7911 if Preferences.getEditor("AutoSpellCheckingEnabled"): 7921 if Preferences.getEditor("AutoSpellCheckingEnabled"):
7912 with contextlib.suppress(TypeError): 7922 with contextlib.suppress(TypeError):
7913 self.SCN_CHARADDED.connect( 7923 self.SCN_CHARADDED.connect(
7914 self.__spellCharAdded, Qt.ConnectionType.UniqueConnection) 7924 self.__spellCharAdded, Qt.ConnectionType.UniqueConnection
7925 )
7915 self.spell.checkDocumentIncrementally() 7926 self.spell.checkDocumentIncrementally()
7916 else: 7927 else:
7917 with contextlib.suppress(TypeError): 7928 with contextlib.suppress(TypeError):
7918 self.SCN_CHARADDED.disconnect(self.__spellCharAdded) 7929 self.SCN_CHARADDED.disconnect(self.__spellCharAdded)
7919 self.clearAllIndicators(self.spellingIndicator) 7930 self.clearAllIndicators(self.spellingIndicator)
7920 7931
7921 def isSpellCheckRegion(self, pos): 7932 def isSpellCheckRegion(self, pos):
7922 """ 7933 """
7923 Public method to check, if the given position is within a region, that 7934 Public method to check, if the given position is within a region, that
7924 should be spell checked. 7935 should be spell checked.
7925 7936
7926 For files with a configured full text file extension all regions will 7937 For files with a configured full text file extension all regions will
7927 be regarded as to be checked. Depending on configuration, all unknown 7938 be regarded as to be checked. Depending on configuration, all unknown
7928 files (i.e. those without a file extension) will be checked fully as 7939 files (i.e. those without a file extension) will be checked fully as
7929 well. 7940 well.
7930 7941
7931 @param pos position to be checked 7942 @param pos position to be checked
7932 @type int 7943 @type int
7933 @return flag indicating pos is in a spell check region 7944 @return flag indicating pos is in a spell check region
7934 @rtype bool 7945 @rtype bool
7935 """ 7946 """
7936 if self.__spellCheckStringsOnly: 7947 if self.__spellCheckStringsOnly:
7937 if ( 7948 if (
7938 (self.__fileNameExtension in 7949 self.__fileNameExtension
7939 Preferences.getEditor("FullSpellCheckExtensions")) or 7950 in Preferences.getEditor("FullSpellCheckExtensions")
7940 (not self.__fileNameExtension and 7951 ) or (
7941 Preferences.getEditor("FullSpellCheckUnknown")) 7952 not self.__fileNameExtension
7953 and Preferences.getEditor("FullSpellCheckUnknown")
7942 ): 7954 ):
7943 return True 7955 return True
7944 else: 7956 else:
7945 style = self.styleAt(pos) 7957 style = self.styleAt(pos)
7946 if self.lexer_ is not None: 7958 if self.lexer_ is not None:
7947 return ( 7959 return self.lexer_.isCommentStyle(
7948 self.lexer_.isCommentStyle(style) or 7960 style
7949 self.lexer_.isStringStyle(style) 7961 ) or self.lexer_.isStringStyle(style)
7950 ) 7962
7951
7952 return True 7963 return True
7953 7964
7954 @pyqtSlot(int) 7965 @pyqtSlot(int)
7955 def __spellCharAdded(self, charNumber): 7966 def __spellCharAdded(self, charNumber):
7956 """ 7967 """
7957 Private slot called to handle the user entering a character. 7968 Private slot called to handle the user entering a character.
7958 7969
7959 @param charNumber value of the character entered (integer) 7970 @param charNumber value of the character entered (integer)
7960 """ 7971 """
7961 if self.spell: 7972 if self.spell:
7962 if not chr(charNumber).isalnum(): 7973 if not chr(charNumber).isalnum():
7963 self.spell.checkWord( 7974 self.spell.checkWord(self.positionBefore(self.currentPosition()), True)
7964 self.positionBefore(self.currentPosition()), True) 7975 elif self.hasIndicator(self.spellingIndicator, self.currentPosition()):
7965 elif self.hasIndicator(
7966 self.spellingIndicator, self.currentPosition()):
7967 self.spell.checkWord(self.currentPosition()) 7976 self.spell.checkWord(self.currentPosition())
7968 7977
7969 def checkSpelling(self): 7978 def checkSpelling(self):
7970 """ 7979 """
7971 Public slot to perform an interactive spell check of the document. 7980 Public slot to perform an interactive spell check of the document.
7972 """ 7981 """
7973 if self.spell: 7982 if self.spell:
7974 cline, cindex = self.getCursorPosition() 7983 cline, cindex = self.getCursorPosition()
7975 from .SpellCheckingDialog import SpellCheckingDialog 7984 from .SpellCheckingDialog import SpellCheckingDialog
7985
7976 dlg = SpellCheckingDialog(self.spell, 0, self.length(), self) 7986 dlg = SpellCheckingDialog(self.spell, 0, self.length(), self)
7977 dlg.exec() 7987 dlg.exec()
7978 self.setCursorPosition(cline, cindex) 7988 self.setCursorPosition(cline, cindex)
7979 if Preferences.getEditor("AutoSpellCheckingEnabled"): 7989 if Preferences.getEditor("AutoSpellCheckingEnabled"):
7980 self.spell.checkDocumentIncrementally() 7990 self.spell.checkDocumentIncrementally()
7981 7991
7982 def __checkSpellingSelection(self): 7992 def __checkSpellingSelection(self):
7983 """ 7993 """
7984 Private slot to spell check the current selection. 7994 Private slot to spell check the current selection.
7985 """ 7995 """
7986 from .SpellCheckingDialog import SpellCheckingDialog 7996 from .SpellCheckingDialog import SpellCheckingDialog
7997
7987 sline, sindex, eline, eindex = self.getSelection() 7998 sline, sindex, eline, eindex = self.getSelection()
7988 startPos = self.positionFromLineIndex(sline, sindex) 7999 startPos = self.positionFromLineIndex(sline, sindex)
7989 endPos = self.positionFromLineIndex(eline, eindex) 8000 endPos = self.positionFromLineIndex(eline, eindex)
7990 dlg = SpellCheckingDialog(self.spell, startPos, endPos, self) 8001 dlg = SpellCheckingDialog(self.spell, startPos, endPos, self)
7991 dlg.exec() 8002 dlg.exec()
7992 8003
7993 def __checkSpellingWord(self): 8004 def __checkSpellingWord(self):
7994 """ 8005 """
7995 Private slot to check the word below the spelling context menu. 8006 Private slot to check the word below the spelling context menu.
7996 """ 8007 """
7997 from .SpellCheckingDialog import SpellCheckingDialog 8008 from .SpellCheckingDialog import SpellCheckingDialog
8009
7998 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8010 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
7999 wordStart, wordEnd = self.getWordBoundaries(line, index) 8011 wordStart, wordEnd = self.getWordBoundaries(line, index)
8000 wordStartPos = self.positionFromLineIndex(line, wordStart) 8012 wordStartPos = self.positionFromLineIndex(line, wordStart)
8001 wordEndPos = self.positionFromLineIndex(line, wordEnd) 8013 wordEndPos = self.positionFromLineIndex(line, wordEnd)
8002 dlg = SpellCheckingDialog(self.spell, wordStartPos, wordEndPos, self) 8014 dlg = SpellCheckingDialog(self.spell, wordStartPos, wordEndPos, self)
8003 dlg.exec() 8015 dlg.exec()
8004 8016
8005 def __showContextMenuSpelling(self): 8017 def __showContextMenuSpelling(self):
8006 """ 8018 """
8007 Private slot to set up the spelling menu before it is shown. 8019 Private slot to set up the spelling menu before it is shown.
8008 """ 8020 """
8009 self.spellingMenu.clear() 8021 self.spellingMenu.clear()
8010 self.spellingSuggActs = [] 8022 self.spellingSuggActs = []
8011 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8023 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
8012 word = self.getWord(line, index) 8024 word = self.getWord(line, index)
8013 suggestions = self.spell.getSuggestions(word) 8025 suggestions = self.spell.getSuggestions(word)
8014 for suggestion in suggestions[:5]: 8026 for suggestion in suggestions[:5]:
8015 self.spellingSuggActs.append( 8027 self.spellingSuggActs.append(self.spellingMenu.addAction(suggestion))
8016 self.spellingMenu.addAction(suggestion))
8017 if suggestions: 8028 if suggestions:
8018 self.spellingMenu.addSeparator() 8029 self.spellingMenu.addSeparator()
8019 self.spellingMenu.addAction( 8030 self.spellingMenu.addAction(
8020 UI.PixmapCache.getIcon("spellchecking"), 8031 UI.PixmapCache.getIcon("spellchecking"),
8021 self.tr("Check spelling..."), self.__checkSpellingWord) 8032 self.tr("Check spelling..."),
8033 self.__checkSpellingWord,
8034 )
8022 self.spellingMenu.addAction( 8035 self.spellingMenu.addAction(
8023 self.tr("Add to dictionary"), self.__addToSpellingDictionary) 8036 self.tr("Add to dictionary"), self.__addToSpellingDictionary
8024 self.spellingMenu.addAction( 8037 )
8025 self.tr("Ignore All"), self.__ignoreSpellingAlways) 8038 self.spellingMenu.addAction(self.tr("Ignore All"), self.__ignoreSpellingAlways)
8026 8039
8027 self.showMenu.emit("Spelling", self.spellingMenu, self) 8040 self.showMenu.emit("Spelling", self.spellingMenu, self)
8028 8041
8029 def __contextMenuSpellingTriggered(self, action): 8042 def __contextMenuSpellingTriggered(self, action):
8030 """ 8043 """
8031 Private slot to handle the selection of a suggestion of the spelling 8044 Private slot to handle the selection of a suggestion of the spelling
8032 context menu. 8045 context menu.
8033 8046
8034 @param action reference to the action that was selected (QAction) 8047 @param action reference to the action that was selected (QAction)
8035 """ 8048 """
8036 if action in self.spellingSuggActs: 8049 if action in self.spellingSuggActs:
8037 replacement = action.text() 8050 replacement = action.text()
8038 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8051 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
8040 self.setSelection(line, wordStart, line, wordEnd) 8053 self.setSelection(line, wordStart, line, wordEnd)
8041 self.beginUndoAction() 8054 self.beginUndoAction()
8042 self.removeSelectedText() 8055 self.removeSelectedText()
8043 self.insert(replacement) 8056 self.insert(replacement)
8044 self.endUndoAction() 8057 self.endUndoAction()
8045 8058
8046 def __addToSpellingDictionary(self): 8059 def __addToSpellingDictionary(self):
8047 """ 8060 """
8048 Private slot to add the word below the spelling context menu to the 8061 Private slot to add the word below the spelling context menu to the
8049 dictionary. 8062 dictionary.
8050 """ 8063 """
8051 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8064 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
8052 word = self.getWord(line, index) 8065 word = self.getWord(line, index)
8053 self.spell.add(word) 8066 self.spell.add(word)
8054 8067
8055 wordStart, wordEnd = self.getWordBoundaries(line, index) 8068 wordStart, wordEnd = self.getWordBoundaries(line, index)
8056 self.clearIndicator(self.spellingIndicator, line, wordStart, 8069 self.clearIndicator(self.spellingIndicator, line, wordStart, line, wordEnd)
8057 line, wordEnd)
8058 if Preferences.getEditor("AutoSpellCheckingEnabled"): 8070 if Preferences.getEditor("AutoSpellCheckingEnabled"):
8059 self.spell.checkDocumentIncrementally() 8071 self.spell.checkDocumentIncrementally()
8060 8072
8061 def __removeFromSpellingDictionary(self): 8073 def __removeFromSpellingDictionary(self):
8062 """ 8074 """
8063 Private slot to remove the word below the context menu to the 8075 Private slot to remove the word below the context menu to the
8064 dictionary. 8076 dictionary.
8065 """ 8077 """
8066 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8078 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
8067 word = self.getWord(line, index) 8079 word = self.getWord(line, index)
8068 self.spell.remove(word) 8080 self.spell.remove(word)
8069 8081
8070 if Preferences.getEditor("AutoSpellCheckingEnabled"): 8082 if Preferences.getEditor("AutoSpellCheckingEnabled"):
8071 self.spell.checkDocumentIncrementally() 8083 self.spell.checkDocumentIncrementally()
8072 8084
8073 def __ignoreSpellingAlways(self): 8085 def __ignoreSpellingAlways(self):
8074 """ 8086 """
8075 Private to always ignore the word below the spelling context menu. 8087 Private to always ignore the word below the spelling context menu.
8076 """ 8088 """
8077 line, index = self.lineIndexFromPosition(self.spellingMenuPos) 8089 line, index = self.lineIndexFromPosition(self.spellingMenuPos)
8078 word = self.getWord(line, index) 8090 word = self.getWord(line, index)
8079 self.spell.ignoreAlways(word) 8091 self.spell.ignoreAlways(word)
8080 if Preferences.getEditor("AutoSpellCheckingEnabled"): 8092 if Preferences.getEditor("AutoSpellCheckingEnabled"):
8081 self.spell.checkDocumentIncrementally() 8093 self.spell.checkDocumentIncrementally()
8082 8094
8083 ####################################################################### 8095 #######################################################################
8084 ## Cooperation related methods 8096 ## Cooperation related methods
8085 ####################################################################### 8097 #######################################################################
8086 8098
8087 def getSharingStatus(self): 8099 def getSharingStatus(self):
8088 """ 8100 """
8089 Public method to get some share status info. 8101 Public method to get some share status info.
8090 8102
8091 @return tuple indicating, if the editor is sharable, the sharing 8103 @return tuple indicating, if the editor is sharable, the sharing
8092 status, if it is inside a locally initiated shared edit session 8104 status, if it is inside a locally initiated shared edit session
8093 and if it is inside a remotely initiated shared edit session 8105 and if it is inside a remotely initiated shared edit session
8094 (boolean, boolean, boolean, boolean) 8106 (boolean, boolean, boolean, boolean)
8095 """ 8107 """
8096 return ( 8108 return (
8097 (bool(self.fileName) and 8109 (
8098 self.project.isOpen() and 8110 bool(self.fileName)
8099 self.project.isProjectFile(self.fileName)), 8111 and self.project.isOpen()
8112 and self.project.isProjectFile(self.fileName)
8113 ),
8100 self.__isShared, 8114 self.__isShared,
8101 self.__inSharedEdit, 8115 self.__inSharedEdit,
8102 self.__inRemoteSharedEdit 8116 self.__inRemoteSharedEdit,
8103 ) 8117 )
8104 8118
8105 def shareConnected(self, connected): 8119 def shareConnected(self, connected):
8106 """ 8120 """
8107 Public slot to handle a change of the connected state. 8121 Public slot to handle a change of the connected state.
8108 8122
8109 @param connected flag indicating the connected state (boolean) 8123 @param connected flag indicating the connected state (boolean)
8110 """ 8124 """
8111 if not connected: 8125 if not connected:
8112 self.__inRemoteSharedEdit = False 8126 self.__inRemoteSharedEdit = False
8113 self.setReadOnly(False) 8127 self.setReadOnly(False)
8114 self.__updateReadOnly() 8128 self.__updateReadOnly()
8115 self.cancelSharedEdit(send=False) 8129 self.cancelSharedEdit(send=False)
8116 self.__isSyncing = False 8130 self.__isSyncing = False
8117 self.__receivedWhileSyncing = [] 8131 self.__receivedWhileSyncing = []
8118 8132
8119 def shareEditor(self, share): 8133 def shareEditor(self, share):
8120 """ 8134 """
8121 Public slot to set the shared status of the editor. 8135 Public slot to set the shared status of the editor.
8122 8136
8123 @param share flag indicating the share status (boolean) 8137 @param share flag indicating the share status (boolean)
8124 """ 8138 """
8125 self.__isShared = share 8139 self.__isShared = share
8126 if not share: 8140 if not share:
8127 self.shareConnected(False) 8141 self.shareConnected(False)
8128 8142
8129 def startSharedEdit(self): 8143 def startSharedEdit(self):
8130 """ 8144 """
8131 Public slot to start a shared edit session for the editor. 8145 Public slot to start a shared edit session for the editor.
8132 """ 8146 """
8133 self.__inSharedEdit = True 8147 self.__inSharedEdit = True
8134 self.__savedText = self.text() 8148 self.__savedText = self.text()
8135 hashStr = str( 8149 hashStr = str(
8136 QCryptographicHash.hash( 8150 QCryptographicHash.hash(
8137 Utilities.encode(self.__savedText, self.encoding)[0], 8151 Utilities.encode(self.__savedText, self.encoding)[0],
8138 QCryptographicHash.Algorithm.Sha1).toHex(), 8152 QCryptographicHash.Algorithm.Sha1,
8139 encoding="utf-8") 8153 ).toHex(),
8154 encoding="utf-8",
8155 )
8140 self.__send(Editor.StartEditToken, hashStr) 8156 self.__send(Editor.StartEditToken, hashStr)
8141 8157
8142 def sendSharedEdit(self): 8158 def sendSharedEdit(self):
8143 """ 8159 """
8144 Public slot to end a shared edit session for the editor and 8160 Public slot to end a shared edit session for the editor and
8145 send the changes. 8161 send the changes.
8146 """ 8162 """
8147 commands = self.__calculateChanges(self.__savedText, self.text()) 8163 commands = self.__calculateChanges(self.__savedText, self.text())
8148 self.__send(Editor.EndEditToken, commands) 8164 self.__send(Editor.EndEditToken, commands)
8149 self.__inSharedEdit = False 8165 self.__inSharedEdit = False
8150 self.__savedText = "" 8166 self.__savedText = ""
8151 8167
8152 def cancelSharedEdit(self, send=True): 8168 def cancelSharedEdit(self, send=True):
8153 """ 8169 """
8154 Public slot to cancel a shared edit session for the editor. 8170 Public slot to cancel a shared edit session for the editor.
8155 8171
8156 @param send flag indicating to send the CancelEdit command (boolean) 8172 @param send flag indicating to send the CancelEdit command (boolean)
8157 """ 8173 """
8158 self.__inSharedEdit = False 8174 self.__inSharedEdit = False
8159 self.__savedText = "" 8175 self.__savedText = ""
8160 if send: 8176 if send:
8161 self.__send(Editor.CancelEditToken) 8177 self.__send(Editor.CancelEditToken)
8162 8178
8163 def __send(self, token, args=None): 8179 def __send(self, token, args=None):
8164 """ 8180 """
8165 Private method to send an editor command to remote editors. 8181 Private method to send an editor command to remote editors.
8166 8182
8167 @param token command token (string) 8183 @param token command token (string)
8168 @param args arguments for the command (string) 8184 @param args arguments for the command (string)
8169 """ 8185 """
8170 if self.vm.isConnected(): 8186 if self.vm.isConnected():
8171 msg = "" 8187 msg = ""
8172 if token in (Editor.StartEditToken, 8188 if token in (
8173 Editor.EndEditToken, 8189 Editor.StartEditToken,
8174 Editor.RequestSyncToken, 8190 Editor.EndEditToken,
8175 Editor.SyncToken): 8191 Editor.RequestSyncToken,
8176 msg = "{0}{1}{2}".format( 8192 Editor.SyncToken,
8177 token, 8193 ):
8178 Editor.Separator, 8194 msg = "{0}{1}{2}".format(token, Editor.Separator, args)
8179 args
8180 )
8181 elif token == Editor.CancelEditToken: 8195 elif token == Editor.CancelEditToken:
8182 msg = "{0}{1}c".format( 8196 msg = "{0}{1}c".format(token, Editor.Separator)
8183 token, 8197
8184 Editor.Separator
8185 )
8186
8187 self.vm.send(self.fileName, msg) 8198 self.vm.send(self.fileName, msg)
8188 8199
8189 def receive(self, command): 8200 def receive(self, command):
8190 """ 8201 """
8191 Public slot to handle received editor commands. 8202 Public slot to handle received editor commands.
8192 8203
8193 @param command command string (string) 8204 @param command command string (string)
8194 """ 8205 """
8195 if self.__isShared: 8206 if self.__isShared:
8196 if ( 8207 if self.__isSyncing and not command.startswith(
8197 self.__isSyncing and 8208 Editor.SyncToken + Editor.Separator
8198 not command.startswith(Editor.SyncToken + Editor.Separator)
8199 ): 8209 ):
8200 self.__receivedWhileSyncing.append(command) 8210 self.__receivedWhileSyncing.append(command)
8201 else: 8211 else:
8202 self.__dispatchCommand(command) 8212 self.__dispatchCommand(command)
8203 8213
8204 def __dispatchCommand(self, command): 8214 def __dispatchCommand(self, command):
8205 """ 8215 """
8206 Private method to dispatch received commands. 8216 Private method to dispatch received commands.
8207 8217
8208 @param command command to be processed (string) 8218 @param command command to be processed (string)
8209 """ 8219 """
8210 token, argsString = command.split(Editor.Separator, 1) 8220 token, argsString = command.split(Editor.Separator, 1)
8211 if token == Editor.StartEditToken: 8221 if token == Editor.StartEditToken:
8212 self.__processStartEditCommand(argsString) 8222 self.__processStartEditCommand(argsString)
8216 self.__processEndEditCommand(argsString) 8226 self.__processEndEditCommand(argsString)
8217 elif token == Editor.RequestSyncToken: 8227 elif token == Editor.RequestSyncToken:
8218 self.__processRequestSyncCommand(argsString) 8228 self.__processRequestSyncCommand(argsString)
8219 elif token == Editor.SyncToken: 8229 elif token == Editor.SyncToken:
8220 self.__processSyncCommand(argsString) 8230 self.__processSyncCommand(argsString)
8221 8231
8222 def __processStartEditCommand(self, argsString): 8232 def __processStartEditCommand(self, argsString):
8223 """ 8233 """
8224 Private slot to process a remote StartEdit command. 8234 Private slot to process a remote StartEdit command.
8225 8235
8226 @param argsString string containing the command parameters (string) 8236 @param argsString string containing the command parameters (string)
8227 """ 8237 """
8228 if not self.__inSharedEdit and not self.__inRemoteSharedEdit: 8238 if not self.__inSharedEdit and not self.__inRemoteSharedEdit:
8229 self.__inRemoteSharedEdit = True 8239 self.__inRemoteSharedEdit = True
8230 self.setReadOnly(True) 8240 self.setReadOnly(True)
8231 self.__updateReadOnly() 8241 self.__updateReadOnly()
8232 hashStr = str( 8242 hashStr = str(
8233 QCryptographicHash.hash( 8243 QCryptographicHash.hash(
8234 Utilities.encode(self.text(), self.encoding)[0], 8244 Utilities.encode(self.text(), self.encoding)[0],
8235 QCryptographicHash.Algorithm.Sha1).toHex(), 8245 QCryptographicHash.Algorithm.Sha1,
8236 encoding="utf-8") 8246 ).toHex(),
8247 encoding="utf-8",
8248 )
8237 if hashStr != argsString: 8249 if hashStr != argsString:
8238 # text is different to the remote site, request to sync it 8250 # text is different to the remote site, request to sync it
8239 self.__isSyncing = True 8251 self.__isSyncing = True
8240 self.__send(Editor.RequestSyncToken, argsString) 8252 self.__send(Editor.RequestSyncToken, argsString)
8241 8253
8242 def __calculateChanges(self, old, new): 8254 def __calculateChanges(self, old, new):
8243 """ 8255 """
8244 Private method to determine change commands to convert old text into 8256 Private method to determine change commands to convert old text into
8245 new text. 8257 new text.
8246 8258
8247 @param old old text (string) 8259 @param old old text (string)
8248 @param new new text (string) 8260 @param new new text (string)
8249 @return commands to change old into new (string) 8261 @return commands to change old into new (string)
8250 """ 8262 """
8251 oldL = old.splitlines() 8263 oldL = old.splitlines()
8252 newL = new.splitlines() 8264 newL = new.splitlines()
8253 matcher = difflib.SequenceMatcher(None, oldL, newL) 8265 matcher = difflib.SequenceMatcher(None, oldL, newL)
8254 8266
8255 formatStr = "@@{0} {1} {2} {3}" 8267 formatStr = "@@{0} {1} {2} {3}"
8256 commands = [] 8268 commands = []
8257 for token, i1, i2, j1, j2 in matcher.get_opcodes(): 8269 for token, i1, i2, j1, j2 in matcher.get_opcodes():
8258 if token == "insert": # secok 8270 if token == "insert": # secok
8259 commands.append(formatStr.format("i", j1, j2 - j1, -1)) 8271 commands.append(formatStr.format("i", j1, j2 - j1, -1))
8260 commands.extend(newL[j1:j2]) 8272 commands.extend(newL[j1:j2])
8261 elif token == "delete": # secok 8273 elif token == "delete": # secok
8262 commands.append(formatStr.format("d", j1, i2 - i1, -1)) 8274 commands.append(formatStr.format("d", j1, i2 - i1, -1))
8263 elif token == "replace": # secok 8275 elif token == "replace": # secok
8264 commands.append(formatStr.format("r", j1, i2 - i1, j2 - j1)) 8276 commands.append(formatStr.format("r", j1, i2 - i1, j2 - j1))
8265 commands.extend(newL[j1:j2]) 8277 commands.extend(newL[j1:j2])
8266 8278
8267 return "\n".join(commands) + "\n" 8279 return "\n".join(commands) + "\n"
8268 8280
8269 def __processEndEditCommand(self, argsString): 8281 def __processEndEditCommand(self, argsString):
8270 """ 8282 """
8271 Private slot to process a remote EndEdit command. 8283 Private slot to process a remote EndEdit command.
8272 8284
8273 @param argsString string containing the command parameters (string) 8285 @param argsString string containing the command parameters (string)
8274 """ 8286 """
8275 commands = argsString.splitlines() 8287 commands = argsString.splitlines()
8276 sep = self.getLineSeparator() 8288 sep = self.getLineSeparator()
8277 cur = self.getCursorPosition() 8289 cur = self.getCursorPosition()
8278 8290
8279 self.setReadOnly(False) 8291 self.setReadOnly(False)
8280 self.beginUndoAction() 8292 self.beginUndoAction()
8281 while commands: 8293 while commands:
8282 commandLine = commands.pop(0) 8294 commandLine = commands.pop(0)
8283 if not commandLine.startswith("@@"): 8295 if not commandLine.startswith("@@"):
8284 continue 8296 continue
8285 8297
8286 args = commandLine.split() 8298 args = commandLine.split()
8287 command = args.pop(0) 8299 command = args.pop(0)
8288 pos, l1, l2 = [int(arg) for arg in args] 8300 pos, l1, l2 = [int(arg) for arg in args]
8289 if command == "@@i": 8301 if command == "@@i":
8290 txt = sep.join(commands[0:l1]) + sep 8302 txt = sep.join(commands[0:l1]) + sep
8300 self.insertAt(txt, pos, 0) 8312 self.insertAt(txt, pos, 0)
8301 del commands[0:l2] 8313 del commands[0:l2]
8302 self.endUndoAction() 8314 self.endUndoAction()
8303 self.__updateReadOnly() 8315 self.__updateReadOnly()
8304 self.__inRemoteSharedEdit = False 8316 self.__inRemoteSharedEdit = False
8305 8317
8306 self.setCursorPosition(*cur) 8318 self.setCursorPosition(*cur)
8307 8319
8308 def __processRequestSyncCommand(self, argsString): 8320 def __processRequestSyncCommand(self, argsString):
8309 """ 8321 """
8310 Private slot to process a remote RequestSync command. 8322 Private slot to process a remote RequestSync command.
8311 8323
8312 @param argsString string containing the command parameters (string) 8324 @param argsString string containing the command parameters (string)
8313 """ 8325 """
8314 if self.__inSharedEdit: 8326 if self.__inSharedEdit:
8315 hashStr = str( 8327 hashStr = str(
8316 QCryptographicHash.hash( 8328 QCryptographicHash.hash(
8317 Utilities.encode(self.__savedText, self.encoding)[0], 8329 Utilities.encode(self.__savedText, self.encoding)[0],
8318 QCryptographicHash.Algorithm.Sha1).toHex(), 8330 QCryptographicHash.Algorithm.Sha1,
8319 encoding="utf-8") 8331 ).toHex(),
8320 8332 encoding="utf-8",
8333 )
8334
8321 if hashStr == argsString: 8335 if hashStr == argsString:
8322 self.__send(Editor.SyncToken, self.__savedText) 8336 self.__send(Editor.SyncToken, self.__savedText)
8323 8337
8324 def __processSyncCommand(self, argsString): 8338 def __processSyncCommand(self, argsString):
8325 """ 8339 """
8326 Private slot to process a remote Sync command. 8340 Private slot to process a remote Sync command.
8327 8341
8328 @param argsString string containing the command parameters (string) 8342 @param argsString string containing the command parameters (string)
8329 """ 8343 """
8330 if self.__isSyncing: 8344 if self.__isSyncing:
8331 cur = self.getCursorPosition() 8345 cur = self.getCursorPosition()
8332 8346
8333 self.setReadOnly(False) 8347 self.setReadOnly(False)
8334 self.beginUndoAction() 8348 self.beginUndoAction()
8335 self.selectAll() 8349 self.selectAll()
8336 self.removeSelectedText() 8350 self.removeSelectedText()
8337 self.insertAt(argsString, 0, 0) 8351 self.insertAt(argsString, 0, 0)
8338 self.endUndoAction() 8352 self.endUndoAction()
8339 self.setReadOnly(True) 8353 self.setReadOnly(True)
8340 8354
8341 self.setCursorPosition(*cur) 8355 self.setCursorPosition(*cur)
8342 8356
8343 while self.__receivedWhileSyncing: 8357 while self.__receivedWhileSyncing:
8344 command = self.__receivedWhileSyncing.pop(0) 8358 command = self.__receivedWhileSyncing.pop(0)
8345 self.__dispatchCommand(command) 8359 self.__dispatchCommand(command)
8346 8360
8347 self.__isSyncing = False 8361 self.__isSyncing = False
8348 8362
8349 ####################################################################### 8363 #######################################################################
8350 ## Special search related methods 8364 ## Special search related methods
8351 ####################################################################### 8365 #######################################################################
8352 8366
8353 def searchCurrentWordForward(self): 8367 def searchCurrentWordForward(self):
8354 """ 8368 """
8355 Public slot to search the current word forward. 8369 Public slot to search the current word forward.
8356 """ 8370 """
8357 self.__searchCurrentWord(forward=True) 8371 self.__searchCurrentWord(forward=True)
8358 8372
8359 def searchCurrentWordBackward(self): 8373 def searchCurrentWordBackward(self):
8360 """ 8374 """
8361 Public slot to search the current word backward. 8375 Public slot to search the current word backward.
8362 """ 8376 """
8363 self.__searchCurrentWord(forward=False) 8377 self.__searchCurrentWord(forward=False)
8364 8378
8365 def __searchCurrentWord(self, forward=True): 8379 def __searchCurrentWord(self, forward=True):
8366 """ 8380 """
8367 Private slot to search the next occurrence of the current word. 8381 Private slot to search the next occurrence of the current word.
8368 8382
8369 @param forward flag indicating the search direction (boolean) 8383 @param forward flag indicating the search direction (boolean)
8370 """ 8384 """
8371 self.hideFindIndicator() 8385 self.hideFindIndicator()
8372 line, index = self.getCursorPosition() 8386 line, index = self.getCursorPosition()
8373 word = self.getCurrentWord() 8387 word = self.getCurrentWord()
8374 wordStart, wordEnd = self.getCurrentWordBoundaries() 8388 wordStart, wordEnd = self.getCurrentWordBoundaries()
8375 wordStartPos = self.positionFromLineIndex(line, wordStart) 8389 wordStartPos = self.positionFromLineIndex(line, wordStart)
8376 wordEndPos = self.positionFromLineIndex(line, wordEnd) 8390 wordEndPos = self.positionFromLineIndex(line, wordEnd)
8377 8391
8378 regExp = re.compile(r"\b{0}\b".format(word)) 8392 regExp = re.compile(r"\b{0}\b".format(word))
8379 startPos = wordEndPos if forward else wordStartPos 8393 startPos = wordEndPos if forward else wordStartPos
8380 8394
8381 matches = [m for m in regExp.finditer(self.text())] 8395 matches = [m for m in regExp.finditer(self.text())]
8382 if matches: 8396 if matches:
8383 if forward: 8397 if forward:
8384 matchesAfter = [m for m in matches if m.start() >= startPos] 8398 matchesAfter = [m for m in matches if m.start() >= startPos]
8385 if matchesAfter: 8399 if matchesAfter:
8394 else: 8408 else:
8395 # wrap around 8409 # wrap around
8396 match = matches[-1] 8410 match = matches[-1]
8397 line, index = self.lineIndexFromPosition(match.start()) 8411 line, index = self.lineIndexFromPosition(match.start())
8398 self.setSelection(line, index + len(match.group(0)), line, index) 8412 self.setSelection(line, index + len(match.group(0)), line, index)
8399 self.showFindIndicator(line, index, 8413 self.showFindIndicator(line, index, line, index + len(match.group(0)))
8400 line, index + len(match.group(0))) 8414
8401
8402 ####################################################################### 8415 #######################################################################
8403 ## Sort related methods 8416 ## Sort related methods
8404 ####################################################################### 8417 #######################################################################
8405 8418
8406 def sortLines(self): 8419 def sortLines(self):
8407 """ 8420 """
8408 Public slot to sort the lines spanned by a rectangular selection. 8421 Public slot to sort the lines spanned by a rectangular selection.
8409 """ 8422 """
8410 if not self.selectionIsRectangle(): 8423 if not self.selectionIsRectangle():
8411 return 8424 return
8412 8425
8413 from .SortOptionsDialog import SortOptionsDialog 8426 from .SortOptionsDialog import SortOptionsDialog
8427
8414 dlg = SortOptionsDialog() 8428 dlg = SortOptionsDialog()
8415 if dlg.exec() == QDialog.DialogCode.Accepted: 8429 if dlg.exec() == QDialog.DialogCode.Accepted:
8416 ascending, alnum, caseSensitive = dlg.getData() 8430 ascending, alnum, caseSensitive = dlg.getData()
8417 origStartLine, origStartIndex, origEndLine, origEndIndex = ( 8431 (
8418 self.getRectangularSelection() 8432 origStartLine,
8419 ) 8433 origStartIndex,
8434 origEndLine,
8435 origEndIndex,
8436 ) = self.getRectangularSelection()
8420 # convert to upper-left to lower-right 8437 # convert to upper-left to lower-right
8421 startLine = min(origStartLine, origEndLine) 8438 startLine = min(origStartLine, origEndLine)
8422 startIndex = min(origStartIndex, origEndIndex) 8439 startIndex = min(origStartIndex, origEndIndex)
8423 endLine = max(origStartLine, origEndLine) 8440 endLine = max(origStartLine, origEndLine)
8424 endIndex = max(origStartIndex, origEndIndex) 8441 endIndex = max(origStartIndex, origEndIndex)
8425 8442
8426 # step 1: extract the text of the rectangular selection and 8443 # step 1: extract the text of the rectangular selection and
8427 # the lines 8444 # the lines
8428 selText = {} 8445 selText = {}
8429 txtLines = {} 8446 txtLines = {}
8430 for line in range(startLine, endLine + 1): 8447 for line in range(startLine, endLine + 1):
8437 EricMessageBox.critical( 8454 EricMessageBox.critical(
8438 self, 8455 self,
8439 self.tr("Sort Lines"), 8456 self.tr("Sort Lines"),
8440 self.tr( 8457 self.tr(
8441 """The selection contains illegal data for a""" 8458 """The selection contains illegal data for a"""
8442 """ numerical sort.""")) 8459 """ numerical sort."""
8460 ),
8461 )
8443 return 8462 return
8444 8463
8445 if txt in selText: 8464 if txt in selText:
8446 selText[txt].append(line) 8465 selText[txt].append(line)
8447 else: 8466 else:
8448 selText[txt] = [line] 8467 selText[txt] = [line]
8449 8468
8450 # step 2: calculate the sort parameters 8469 # step 2: calculate the sort parameters
8451 reverse = not ascending 8470 reverse = not ascending
8452 if alnum and not caseSensitive: 8471 if alnum and not caseSensitive:
8453 keyFun = str.lower 8472 keyFun = str.lower
8454 else: 8473 else:
8455 keyFun = None 8474 keyFun = None
8456 8475
8457 # step 3: sort the lines 8476 # step 3: sort the lines
8458 eol = self.getLineSeparator() 8477 eol = self.getLineSeparator()
8459 lastWithEol = True 8478 lastWithEol = True
8460 newLines = [] 8479 newLines = []
8461 for txt in sorted(selText.keys(), key=keyFun, reverse=reverse): 8480 for txt in sorted(selText.keys(), key=keyFun, reverse=reverse):
8464 if not txt.endswith(eol): 8483 if not txt.endswith(eol):
8465 lastWithEol = False 8484 lastWithEol = False
8466 txt += eol 8485 txt += eol
8467 newLines.append(txt) 8486 newLines.append(txt)
8468 if not lastWithEol: 8487 if not lastWithEol:
8469 newLines[-1] = newLines[-1][:-len(eol)] 8488 newLines[-1] = newLines[-1][: -len(eol)]
8470 8489
8471 # step 4: replace the lines by the sorted ones 8490 # step 4: replace the lines by the sorted ones
8472 self.setSelection(startLine, 0, endLine + 1, 0) 8491 self.setSelection(startLine, 0, endLine + 1, 0)
8473 self.beginUndoAction() 8492 self.beginUndoAction()
8474 self.replaceSelectedText("".join(newLines)) 8493 self.replaceSelectedText("".join(newLines))
8475 self.endUndoAction() 8494 self.endUndoAction()
8476 8495
8477 # step 5: reset the rectangular selection 8496 # step 5: reset the rectangular selection
8478 self.setRectangularSelection(origStartLine, origStartIndex, 8497 self.setRectangularSelection(
8479 origEndLine, origEndIndex) 8498 origStartLine, origStartIndex, origEndLine, origEndIndex
8499 )
8480 self.selectionChanged.emit() 8500 self.selectionChanged.emit()
8481 8501
8482 ####################################################################### 8502 #######################################################################
8483 ## Mouse click handler related methods 8503 ## Mouse click handler related methods
8484 ####################################################################### 8504 #######################################################################
8485 8505
8486 def mouseReleaseEvent(self, evt): 8506 def mouseReleaseEvent(self, evt):
8487 """ 8507 """
8488 Protected method calling a registered mouse click handler function. 8508 Protected method calling a registered mouse click handler function.
8489 8509
8490 @param evt event object 8510 @param evt event object
8491 @type QMouseEvent 8511 @type QMouseEvent
8492 """ 8512 """
8493 modifiers = evt.modifiers() 8513 modifiers = evt.modifiers()
8494 button = evt.button() 8514 button = evt.button()
8495 key = (modifiers, button) 8515 key = (modifiers, button)
8496 8516
8497 self.vm.eventFilter(self, evt) 8517 self.vm.eventFilter(self, evt)
8498 super().mouseReleaseEvent(evt) 8518 super().mouseReleaseEvent(evt)
8499 8519
8500 if ( 8520 if (
8501 button != Qt.MouseButton.NoButton and 8521 button != Qt.MouseButton.NoButton
8502 Preferences.getEditor("MouseClickHandlersEnabled") and 8522 and Preferences.getEditor("MouseClickHandlersEnabled")
8503 key in self.__mouseClickHandlers 8523 and key in self.__mouseClickHandlers
8504 ): 8524 ):
8505 evt.accept() 8525 evt.accept()
8506 self.__mouseClickHandlers[key][1](self) 8526 self.__mouseClickHandlers[key][1](self)
8507 else: 8527 else:
8508 super().mouseReleaseEvent(evt) 8528 super().mouseReleaseEvent(evt)
8509 8529
8510 def setMouseClickHandler(self, name, modifiers, button, function): 8530 def setMouseClickHandler(self, name, modifiers, button, function):
8511 """ 8531 """
8512 Public method to set a mouse click handler. 8532 Public method to set a mouse click handler.
8513 8533
8514 @param name name of the plug-in (or 'internal') setting this handler 8534 @param name name of the plug-in (or 'internal') setting this handler
8515 @type str 8535 @type str
8516 @param modifiers keyboard modifiers of the handler 8536 @param modifiers keyboard modifiers of the handler
8517 @type Qt.KeyboardModifiers or int 8537 @type Qt.KeyboardModifiers or int
8518 @param button mouse button of the handler 8538 @param button mouse button of the handler
8526 key = (modifiers, button) 8546 key = (modifiers, button)
8527 if key in self.__mouseClickHandlers: 8547 if key in self.__mouseClickHandlers:
8528 EricMessageBox.warning( 8548 EricMessageBox.warning(
8529 self, 8549 self,
8530 self.tr("Register Mouse Click Handler"), 8550 self.tr("Register Mouse Click Handler"),
8531 self.tr("""A mouse click handler for "{0}" was already""" 8551 self.tr(
8532 """ registered by "{1}". Aborting request by""" 8552 """A mouse click handler for "{0}" was already"""
8533 """ "{2}"...""").format( 8553 """ registered by "{1}". Aborting request by"""
8534 MouseUtilities.MouseButtonModifier2String( 8554 """ "{2}"..."""
8535 modifiers, button), 8555 ).format(
8556 MouseUtilities.MouseButtonModifier2String(modifiers, button),
8536 self.__mouseClickHandlers[key][0], 8557 self.__mouseClickHandlers[key][0],
8537 name)) 8558 name,
8559 ),
8560 )
8538 return False 8561 return False
8539 8562
8540 self.__mouseClickHandlers[key] = (name, function) 8563 self.__mouseClickHandlers[key] = (name, function)
8541 return True 8564 return True
8542 8565
8543 return False 8566 return False
8544 8567
8545 def getMouseClickHandler(self, modifiers, button): 8568 def getMouseClickHandler(self, modifiers, button):
8546 """ 8569 """
8547 Public method to get a registered mouse click handler. 8570 Public method to get a registered mouse click handler.
8548 8571
8549 @param modifiers keyboard modifiers of the handler 8572 @param modifiers keyboard modifiers of the handler
8550 @type Qt.KeyboardModifiers 8573 @type Qt.KeyboardModifiers
8551 @param button mouse button of the handler 8574 @param button mouse button of the handler
8552 @type Qt.MouseButton 8575 @type Qt.MouseButton
8553 @return plug-in name and registered function 8576 @return plug-in name and registered function
8556 key = (modifiers, button) 8579 key = (modifiers, button)
8557 if key in self.__mouseClickHandlers: 8580 if key in self.__mouseClickHandlers:
8558 return self.__mouseClickHandlers[key] 8581 return self.__mouseClickHandlers[key]
8559 else: 8582 else:
8560 return ("", None) 8583 return ("", None)
8561 8584
8562 def getMouseClickHandlers(self, name): 8585 def getMouseClickHandlers(self, name):
8563 """ 8586 """
8564 Public method to get all registered mouse click handlers of 8587 Public method to get all registered mouse click handlers of
8565 a plug-in. 8588 a plug-in.
8566 8589
8567 @param name name of the plug-in 8590 @param name name of the plug-in
8568 @type str 8591 @type str
8569 @return registered mouse click handlers as list of modifiers, 8592 @return registered mouse click handlers as list of modifiers,
8570 mouse button and function 8593 mouse button and function
8571 @rtype list of tuple of (Qt.KeyboardModifiers, Qt.MouseButton, func) 8594 @rtype list of tuple of (Qt.KeyboardModifiers, Qt.MouseButton, func)
8573 lst = [] 8596 lst = []
8574 for key, value in self.__mouseClickHandlers.items(): 8597 for key, value in self.__mouseClickHandlers.items():
8575 if value[0] == name: 8598 if value[0] == name:
8576 lst.append((key[0], key[1], value[1])) 8599 lst.append((key[0], key[1], value[1]))
8577 return lst 8600 return lst
8578 8601
8579 def removeMouseClickHandler(self, modifiers, button): 8602 def removeMouseClickHandler(self, modifiers, button):
8580 """ 8603 """
8581 Public method to un-registered a mouse click handler. 8604 Public method to un-registered a mouse click handler.
8582 8605
8583 @param modifiers keyboard modifiers of the handler 8606 @param modifiers keyboard modifiers of the handler
8584 @type Qt.KeyboardModifiers 8607 @type Qt.KeyboardModifiers
8585 @param button mouse button of the handler 8608 @param button mouse button of the handler
8586 @type Qt.MouseButton 8609 @type Qt.MouseButton
8587 """ 8610 """
8588 key = (modifiers, button) 8611 key = (modifiers, button)
8589 if key in self.__mouseClickHandlers: 8612 if key in self.__mouseClickHandlers:
8590 del self.__mouseClickHandlers[key] 8613 del self.__mouseClickHandlers[key]
8591 8614
8592 def removeMouseClickHandlers(self, name): 8615 def removeMouseClickHandlers(self, name):
8593 """ 8616 """
8594 Public method to un-registered all mouse click handlers of 8617 Public method to un-registered all mouse click handlers of
8595 a plug-in. 8618 a plug-in.
8596 8619
8597 @param name name of the plug-in 8620 @param name name of the plug-in
8598 @type str 8621 @type str
8599 """ 8622 """
8600 keys = [] 8623 keys = []
8601 for key in self.__mouseClickHandlers: 8624 for key in self.__mouseClickHandlers:
8602 if self.__mouseClickHandlers[key][0] == name: 8625 if self.__mouseClickHandlers[key][0] == name:
8603 keys.append(key) 8626 keys.append(key)
8604 for key in keys: 8627 for key in keys:
8605 del self.__mouseClickHandlers[key] 8628 del self.__mouseClickHandlers[key]
8606 8629
8607 def gotoReferenceHandler(self, referencesList): 8630 def gotoReferenceHandler(self, referencesList):
8608 """ 8631 """
8609 Public method to handle a list of references to perform a goto. 8632 Public method to handle a list of references to perform a goto.
8610 8633
8611 @param referencesList list of references for a 'goto' action 8634 @param referencesList list of references for a 'goto' action
8612 @type ReferenceItem 8635 @type ReferenceItem
8613 """ 8636 """
8614 references = [] 8637 references = []
8615 referencePositions = [] 8638 referencePositions = []
8616 8639
8617 for reference in referencesList: 8640 for reference in referencesList:
8618 if ( 8641 if (
8619 reference.modulePath != self.getFileName() or 8642 reference.modulePath != self.getFileName()
8620 self.getCursorPosition()[0] + 1 != reference.line 8643 or self.getCursorPosition()[0] + 1 != reference.line
8621 ): 8644 ):
8622 if reference.modulePath == self.getFileName(): 8645 if reference.modulePath == self.getFileName():
8623 references.append( 8646 references.append(
8624 self.tr("{0:4d} {1}", "line number, source code") 8647 self.tr("{0:4d} {1}", "line number, source code").format(
8625 .format(reference.line, reference.codeLine.strip()) 8648 reference.line, reference.codeLine.strip()
8649 )
8626 ) 8650 )
8627 else: 8651 else:
8628 references.append( 8652 references.append(
8629 self.tr("{0:4d} {1}\n => {2}", 8653 self.tr(
8630 "line number, source code, file name") 8654 "{0:4d} {1}\n => {2}",
8631 .format( 8655 "line number, source code, file name",
8632 reference.line, reference.codeLine.strip(), 8656 ).format(
8633 self.project.getRelativePath(reference.modulePath) 8657 reference.line,
8658 reference.codeLine.strip(),
8659 self.project.getRelativePath(reference.modulePath),
8634 ) 8660 )
8635 ) 8661 )
8636 referencePositions.append( 8662 referencePositions.append(
8637 (reference.modulePath, reference.line, reference.column)) 8663 (reference.modulePath, reference.line, reference.column)
8638 8664 )
8665
8639 if references: 8666 if references:
8640 if self.isCallTipActive(): 8667 if self.isCallTipActive():
8641 self.cancelCallTips() 8668 self.cancelCallTips()
8642 self.__referencesList = references 8669 self.__referencesList = references
8643 self.__referencesPositionsList = referencePositions 8670 self.__referencesPositionsList = referencePositions
8644 self.showUserList(ReferencesListID, references) 8671 self.showUserList(ReferencesListID, references)
8645 8672
8646 ####################################################################### 8673 #######################################################################
8647 ## Methods implementing a Shell interface 8674 ## Methods implementing a Shell interface
8648 ####################################################################### 8675 #######################################################################
8649 8676
8650 def __executeSelection(self): 8677 def __executeSelection(self):
8651 """ 8678 """
8652 Private slot to execute the selected text in the shell window. 8679 Private slot to execute the selected text in the shell window.
8653 """ 8680 """
8654 txt = self.selectedText() 8681 txt = self.selectedText()
8655 ericApp().getObject("Shell").executeLines(txt) 8682 ericApp().getObject("Shell").executeLines(txt)
8656 8683
8657 ####################################################################### 8684 #######################################################################
8658 ## Methods implementing the interface to EditorConfig 8685 ## Methods implementing the interface to EditorConfig
8659 ####################################################################### 8686 #######################################################################
8660 8687
8661 def __loadEditorConfig(self, fileName=""): 8688 def __loadEditorConfig(self, fileName=""):
8662 """ 8689 """
8663 Private method to load the EditorConfig properties. 8690 Private method to load the EditorConfig properties.
8664 8691
8665 @param fileName name of the file 8692 @param fileName name of the file
8666 @type str 8693 @type str
8667 """ 8694 """
8668 if not fileName: 8695 if not fileName:
8669 fileName = self.fileName 8696 fileName = self.fileName
8670 8697
8671 self.__editorConfig = self.__loadEditorConfigObject(fileName) 8698 self.__editorConfig = self.__loadEditorConfigObject(fileName)
8672 8699
8673 if fileName: 8700 if fileName:
8674 self.__setTabAndIndent() 8701 self.__setTabAndIndent()
8675 8702
8676 def __loadEditorConfigObject(self, fileName): 8703 def __loadEditorConfigObject(self, fileName):
8677 """ 8704 """
8678 Private method to load the EditorConfig properties for the given 8705 Private method to load the EditorConfig properties for the given
8679 file name. 8706 file name.
8680 8707
8681 @param fileName name of the file 8708 @param fileName name of the file
8682 @type str 8709 @type str
8683 @return EditorConfig dictionary 8710 @return EditorConfig dictionary
8684 @rtype dict 8711 @rtype dict
8685 """ 8712 """
8686 editorConfig = {} 8713 editorConfig = {}
8687 8714
8688 if fileName: 8715 if fileName:
8689 try: 8716 try:
8690 editorConfig = editorconfig.get_properties(fileName) 8717 editorConfig = editorconfig.get_properties(fileName)
8691 except editorconfig.EditorConfigError: 8718 except editorconfig.EditorConfigError:
8692 EricMessageBox.warning( 8719 EricMessageBox.warning(
8693 self, 8720 self,
8694 self.tr("EditorConfig Properties"), 8721 self.tr("EditorConfig Properties"),
8695 self.tr("""<p>The EditorConfig properties for file""" 8722 self.tr(
8696 """ <b>{0}</b> could not be loaded.</p>""") 8723 """<p>The EditorConfig properties for file"""
8697 .format(fileName)) 8724 """ <b>{0}</b> could not be loaded.</p>"""
8698 8725 ).format(fileName),
8726 )
8727
8699 return editorConfig 8728 return editorConfig
8700 8729
8701 def __getEditorConfig(self, option, nodefault=False, config=None): 8730 def __getEditorConfig(self, option, nodefault=False, config=None):
8702 """ 8731 """
8703 Private method to get the requested option via EditorConfig. 8732 Private method to get the requested option via EditorConfig.
8704 8733
8705 If there is no EditorConfig defined, the equivalent built-in option 8734 If there is no EditorConfig defined, the equivalent built-in option
8706 will be used (Preferences.getEditor() ). The option must be given as 8735 will be used (Preferences.getEditor() ). The option must be given as
8707 the Preferences option key. The mapping to the EditorConfig option name 8736 the Preferences option key. The mapping to the EditorConfig option name
8708 will be done within this method. 8737 will be done within this method.
8709 8738
8710 @param option Preferences option key 8739 @param option Preferences option key
8711 @type str 8740 @type str
8712 @param nodefault flag indicating to not get the default value from 8741 @param nodefault flag indicating to not get the default value from
8713 Preferences but return None instead 8742 Preferences but return None instead
8714 @type bool 8743 @type bool
8718 nodefault parameter was True 8747 nodefault parameter was True
8719 @rtype any 8748 @rtype any
8720 """ 8749 """
8721 if config is None: 8750 if config is None:
8722 config = self.__editorConfig 8751 config = self.__editorConfig
8723 8752
8724 if not config: 8753 if not config:
8725 if nodefault: 8754 if nodefault:
8726 return None 8755 return None
8727 else: 8756 else:
8728 value = self.__getOverrideValue(option) 8757 value = self.__getOverrideValue(option)
8729 if value is None: 8758 if value is None:
8730 # no override 8759 # no override
8731 value = Preferences.getEditor(option) 8760 value = Preferences.getEditor(option)
8732 return value 8761 return value
8733 8762
8734 try: 8763 try:
8735 if option == "EOLMode": 8764 if option == "EOLMode":
8736 value = config["end_of_line"] 8765 value = config["end_of_line"]
8737 if value == "lf": 8766 if value == "lf":
8738 value = QsciScintilla.EolMode.EolUnix 8767 value = QsciScintilla.EolMode.EolUnix
8758 value = int(value) 8787 value = int(value)
8759 elif option == "TabForIndentation": 8788 elif option == "TabForIndentation":
8760 value = config["indent_style"] == "tab" 8789 value = config["indent_style"] == "tab"
8761 except KeyError: 8790 except KeyError:
8762 value = None 8791 value = None
8763 8792
8764 if value is None and not nodefault: 8793 if value is None and not nodefault:
8765 # use Preferences in case of error 8794 # use Preferences in case of error
8766 value = self.__getOverrideValue(option) 8795 value = self.__getOverrideValue(option)
8767 if value is None: 8796 if value is None:
8768 # no override 8797 # no override
8769 value = Preferences.getEditor(option) 8798 value = Preferences.getEditor(option)
8770 8799
8771 return value 8800 return value
8772 8801
8773 def getEditorConfig(self, option): 8802 def getEditorConfig(self, option):
8774 """ 8803 """
8775 Public method to get the requested option via EditorConfig. 8804 Public method to get the requested option via EditorConfig.
8776 8805
8777 @param option Preferences option key 8806 @param option Preferences option key
8778 @type str 8807 @type str
8779 @return value of requested setting 8808 @return value of requested setting
8780 @rtype any 8809 @rtype any
8781 """ 8810 """
8782 return self.__getEditorConfig(option) 8811 return self.__getEditorConfig(option)
8783 8812
8784 def __getOverrideValue(self, option): 8813 def __getOverrideValue(self, option):
8785 """ 8814 """
8786 Private method to get an override value for the current file type. 8815 Private method to get an override value for the current file type.
8787 8816
8788 @param option Preferences option key 8817 @param option Preferences option key
8789 @type str 8818 @type str
8790 @return override value; None in case nothing is defined 8819 @return override value; None in case nothing is defined
8791 @rtype any 8820 @rtype any
8792 """ 8821 """
8796 if language in overrides: 8825 if language in overrides:
8797 if option == "TabWidth": 8826 if option == "TabWidth":
8798 return overrides[language][0] 8827 return overrides[language][0]
8799 elif option == "IndentWidth": 8828 elif option == "IndentWidth":
8800 return overrides[language][1] 8829 return overrides[language][1]
8801 8830
8802 return None 8831 return None
8803 8832
8804 ####################################################################### 8833 #######################################################################
8805 ## Methods implementing the docstring generator interface 8834 ## Methods implementing the docstring generator interface
8806 ####################################################################### 8835 #######################################################################
8807 8836
8808 def getDocstringGenerator(self): 8837 def getDocstringGenerator(self):
8809 """ 8838 """
8810 Public method to get a reference to the docstring generator. 8839 Public method to get a reference to the docstring generator.
8811 8840
8812 @return reference to the docstring generator 8841 @return reference to the docstring generator
8813 @rtype BaseDocstringGenerator 8842 @rtype BaseDocstringGenerator
8814 """ 8843 """
8815 if self.__docstringGenerator is None: 8844 if self.__docstringGenerator is None:
8816 from . import DocstringGenerator 8845 from . import DocstringGenerator
8817 self.__docstringGenerator = ( 8846
8818 DocstringGenerator.getDocstringGenerator(self) 8847 self.__docstringGenerator = DocstringGenerator.getDocstringGenerator(self)
8819 ) 8848
8820
8821 return self.__docstringGenerator 8849 return self.__docstringGenerator
8822 8850
8823 def insertDocstring(self): 8851 def insertDocstring(self):
8824 """ 8852 """
8825 Public method to generate and insert a docstring for the function under 8853 Public method to generate and insert a docstring for the function under
8826 the cursor. 8854 the cursor.
8827 8855
8828 Note: This method is called via a keyboard shortcut or through the 8856 Note: This method is called via a keyboard shortcut or through the
8829 global 'Edit' menu. 8857 global 'Edit' menu.
8830 """ 8858 """
8831 generator = self.getDocstringGenerator() 8859 generator = self.getDocstringGenerator()
8832 generator.insertDocstringFromShortcut(self.getCursorPosition()) 8860 generator.insertDocstringFromShortcut(self.getCursorPosition())
8833 8861
8834 @pyqtSlot() 8862 @pyqtSlot()
8835 def __insertDocstring(self): 8863 def __insertDocstring(self):
8836 """ 8864 """
8837 Private slot to generate and insert a docstring for the function under 8865 Private slot to generate and insert a docstring for the function under
8838 the cursor. 8866 the cursor.
8839 """ 8867 """
8840 generator = self.getDocstringGenerator() 8868 generator = self.getDocstringGenerator()
8841 generator.insertDocstring(self.getCursorPosition(), fromStart=True) 8869 generator.insertDocstring(self.getCursorPosition(), fromStart=True)
8842 8870
8843 def __delayedDocstringMenuPopup(self, cursorPosition): 8871 def __delayedDocstringMenuPopup(self, cursorPosition):
8844 """ 8872 """
8845 Private method to test, if the user might want to insert a docstring. 8873 Private method to test, if the user might want to insert a docstring.
8846 8874
8847 @param cursorPosition current cursor position (line and column) 8875 @param cursorPosition current cursor position (line and column)
8848 @type tuple of (int, int) 8876 @type tuple of (int, int)
8849 """ 8877 """
8850 if ( 8878 if Preferences.getEditor(
8851 Preferences.getEditor("DocstringAutoGenerate") and 8879 "DocstringAutoGenerate"
8852 self.getDocstringGenerator().isDocstringIntro(cursorPosition) 8880 ) and self.getDocstringGenerator().isDocstringIntro(cursorPosition):
8853 ): 8881 lineText2Cursor = self.text(cursorPosition[0])[: cursorPosition[1]]
8854 lineText2Cursor = self.text(cursorPosition[0])[:cursorPosition[1]] 8882
8855
8856 QTimer.singleShot( 8883 QTimer.singleShot(
8857 300, 8884 300, lambda: self.__popupDocstringMenu(lineText2Cursor, cursorPosition)
8858 lambda: self.__popupDocstringMenu(lineText2Cursor, 8885 )
8859 cursorPosition) 8886
8860 )
8861
8862 def __popupDocstringMenu(self, lastLineText, lastCursorPosition): 8887 def __popupDocstringMenu(self, lastLineText, lastCursorPosition):
8863 """ 8888 """
8864 Private slot to pop up a menu asking the user, if a docstring should be 8889 Private slot to pop up a menu asking the user, if a docstring should be
8865 inserted. 8890 inserted.
8866 8891
8867 @param lastLineText line contents when the delay timer was started 8892 @param lastLineText line contents when the delay timer was started
8868 @type str 8893 @type str
8869 @param lastCursorPosition position of the cursor when the delay timer 8894 @param lastCursorPosition position of the cursor when the delay timer
8870 was started (line and index) 8895 was started (line and index)
8871 @type tuple of (int, int) 8896 @type tuple of (int, int)
8872 """ 8897 """
8873 cursorPosition = self.getCursorPosition() 8898 cursorPosition = self.getCursorPosition()
8874 if lastCursorPosition != cursorPosition: 8899 if lastCursorPosition != cursorPosition:
8875 return 8900 return
8876 8901
8877 if self.text(cursorPosition[0])[:cursorPosition[1]] != lastLineText: 8902 if self.text(cursorPosition[0])[: cursorPosition[1]] != lastLineText:
8878 return 8903 return
8879 8904
8880 generator = self.getDocstringGenerator() 8905 generator = self.getDocstringGenerator()
8881 if generator.hasFunctionDefinition(cursorPosition): 8906 if generator.hasFunctionDefinition(cursorPosition):
8882 from .DocstringGenerator.BaseDocstringGenerator import ( 8907 from .DocstringGenerator.BaseDocstringGenerator import (
8883 DocstringMenuForEnterOnly 8908 DocstringMenuForEnterOnly,
8884 ) 8909 )
8910
8885 docstringMenu = DocstringMenuForEnterOnly(self) 8911 docstringMenu = DocstringMenuForEnterOnly(self)
8886 act = docstringMenu.addAction( 8912 act = docstringMenu.addAction(
8887 UI.PixmapCache.getIcon("fileText"), 8913 UI.PixmapCache.getIcon("fileText"),
8888 self.tr("Generate Docstring"), 8914 self.tr("Generate Docstring"),
8889 lambda: generator.insertDocstring(cursorPosition, 8915 lambda: generator.insertDocstring(cursorPosition, fromStart=False),
8890 fromStart=False)
8891 ) 8916 )
8892 docstringMenu.setActiveAction(act) 8917 docstringMenu.setActiveAction(act)
8893 docstringMenu.popup( 8918 docstringMenu.popup(self.mapToGlobal(self.getGlobalCursorPosition()))
8894 self.mapToGlobal(self.getGlobalCursorPosition())) 8919
8895
8896 ####################################################################### 8920 #######################################################################
8897 ## Methods implementing the mouse hover help interface 8921 ## Methods implementing the mouse hover help interface
8898 ####################################################################### 8922 #######################################################################
8899 8923
8900 @pyqtSlot(int, int, int) 8924 @pyqtSlot(int, int, int)
8901 def __showMouseHoverHelp(self, pos, x, y): 8925 def __showMouseHoverHelp(self, pos, x, y):
8902 """ 8926 """
8903 Private slot showing code information about the symbol under the 8927 Private slot showing code information about the symbol under the
8904 cursor. 8928 cursor.
8905 8929
8906 @param pos mouse position into the document 8930 @param pos mouse position into the document
8907 @type int 8931 @type int
8908 @param x x-value of mouse screen position 8932 @param x x-value of mouse screen position
8909 @type int 8933 @type int
8910 @param y y-value of mouse screen position 8934 @param y y-value of mouse screen position
8922 self.__mouseHoverHelp(self, line, index) 8946 self.__mouseHoverHelp(self, line, index)
8923 else: 8947 else:
8924 self.__cancelMouseHoverHelp() 8948 self.__cancelMouseHoverHelp()
8925 else: 8949 else:
8926 self.__cancelMouseHoverHelp() 8950 self.__cancelMouseHoverHelp()
8927 8951
8928 def __cancelMouseHoverHelp(self): 8952 def __cancelMouseHoverHelp(self):
8929 """ 8953 """
8930 Private slot cancelling the display of mouse hover help. 8954 Private slot cancelling the display of mouse hover help.
8931 """ 8955 """
8932 if self.__showingMouseHoverHelp: 8956 if self.__showingMouseHoverHelp:
8933 self.cancelCallTips() 8957 self.cancelCallTips()
8934 self.__showingMouseHoverHelp = False 8958 self.__showingMouseHoverHelp = False
8935 8959
8936 def registerMouseHoverHelpFunction(self, func): 8960 def registerMouseHoverHelpFunction(self, func):
8937 """ 8961 """
8938 Public method to register a mouse hover help function. 8962 Public method to register a mouse hover help function.
8939 8963
8940 Note: Only one plugin should provide this function. Otherwise 8964 Note: Only one plugin should provide this function. Otherwise
8941 the last one wins. 8965 the last one wins.
8942 8966
8943 @param func function accepting a reference to the calling editor and 8967 @param func function accepting a reference to the calling editor and
8944 the line and column position (zero based each) 8968 the line and column position (zero based each)
8945 @type func 8969 @type func
8946 """ 8970 """
8947 self.__mouseHoverHelp = func 8971 self.__mouseHoverHelp = func
8948 8972
8949 def unregisterMouseHoverHelpFunction(self, func): 8973 def unregisterMouseHoverHelpFunction(self, func):
8950 """ 8974 """
8951 Public method to unregister a mouse hover help function. 8975 Public method to unregister a mouse hover help function.
8952 8976
8953 @param func function accepting a reference to the calling editor and 8977 @param func function accepting a reference to the calling editor and
8954 the line and column position (zero based each) 8978 the line and column position (zero based each)
8955 @type func 8979 @type func
8956 """ 8980 """
8957 if self.__mouseHoverHelp is func: 8981 if self.__mouseHoverHelp is func:
8958 self.__mouseHoverHelp = None 8982 self.__mouseHoverHelp = None
8959 8983
8960 def showMouseHoverHelpData(self, line, index, data): 8984 def showMouseHoverHelpData(self, line, index, data):
8961 """ 8985 """
8962 Public method to show the mouse hover help data. 8986 Public method to show the mouse hover help data.
8963 8987
8964 @param line line of mouse cursor position 8988 @param line line of mouse cursor position
8965 @type int 8989 @type int
8966 @param index column of mouse cursor position 8990 @param index column of mouse cursor position
8967 @type int 8991 @type int
8968 @param data information text to be shown 8992 @param data information text to be shown
8969 @type str 8993 @type str
8970 """ 8994 """
8971 if data and self.hasFocus() and not self.isListActive(): 8995 if data and self.hasFocus() and not self.isListActive():
8972 pos = self.positionFromLineIndex(line, index) 8996 pos = self.positionFromLineIndex(line, index)
8973 self.SendScintilla(QsciScintilla.SCI_CALLTIPSHOW, 8997 self.SendScintilla(
8974 pos, self._encodeString(data)) 8998 QsciScintilla.SCI_CALLTIPSHOW, pos, self._encodeString(data)
8999 )
8975 self.__showingMouseHoverHelp = True 9000 self.__showingMouseHoverHelp = True
8976 else: 9001 else:
8977 self.__cancelMouseHoverHelp() 9002 self.__cancelMouseHoverHelp()
8978 9003
8979 ####################################################################### 9004 #######################################################################
8980 ## Methods implementing the Black code formatting interface 9005 ## Methods implementing the Black code formatting interface
8981 ####################################################################### 9006 #######################################################################
8982 9007
8983 def __performFormatWithBlack(self, action): 9008 def __performFormatWithBlack(self, action):
8984 """ 9009 """
8985 Private method to format the source code using the 'Black' tool. 9010 Private method to format the source code using the 'Black' tool.
8986 9011
8987 Following actions are supported. 9012 Following actions are supported.
8988 <ul> 9013 <ul>
8989 <li>BlackFormattingAction.Format - the code reformatting is performed</li> 9014 <li>BlackFormattingAction.Format - the code reformatting is performed</li>
8990 <li>BlackFormattingAction.Check - a check is performed, if code formatting 9015 <li>BlackFormattingAction.Check - a check is performed, if code formatting
8991 is necessary</li> 9016 is necessary</li>
8992 <li>BlackFormattingAction.Diff - a unified diff of potential code formatting 9017 <li>BlackFormattingAction.Diff - a unified diff of potential code formatting
8993 changes is generated</li> 9018 changes is generated</li>
8994 </ul> 9019 </ul>
8995 9020
8996 @param action formatting operation to be performed 9021 @param action formatting operation to be performed
8997 @type BlackFormattingAction 9022 @type BlackFormattingAction
8998 """ 9023 """
8999 from CodeFormatting.BlackConfigurationDialog import BlackConfigurationDialog 9024 from CodeFormatting.BlackConfigurationDialog import BlackConfigurationDialog
9000 from CodeFormatting.BlackFormattingDialog import BlackFormattingDialog 9025 from CodeFormatting.BlackFormattingDialog import BlackFormattingDialog
9001 9026
9002 if not self.isModified() or self.saveFile(): 9027 if not self.isModified() or self.saveFile():
9003 withProject = ( 9028 withProject = (
9004 self.fileName and 9029 self.fileName
9005 self.project.isOpen() and 9030 and self.project.isOpen()
9006 self.project.isProjectSource(self.fileName) 9031 and self.project.isProjectSource(self.fileName)
9007 ) 9032 )
9008 dlg = BlackConfigurationDialog(withProject=withProject) 9033 dlg = BlackConfigurationDialog(withProject=withProject)
9009 if dlg.exec() == QDialog.DialogCode.Accepted: 9034 if dlg.exec() == QDialog.DialogCode.Accepted:
9010 config = dlg.getConfiguration() 9035 config = dlg.getConfiguration()
9011 9036
9012 formattingDialog = BlackFormattingDialog( 9037 formattingDialog = BlackFormattingDialog(
9013 config, 9038 config, [self.fileName], project=self.project, action=action
9014 [self.fileName],
9015 project=self.project,
9016 action=action
9017 ) 9039 )
9018 formattingDialog.exec() 9040 formattingDialog.exec()

eric ide

mercurial