#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
**codeEditor_QPlainTextEdit.py**
**Platform:**
Windows, Linux, Mac Os X.
**Description:**
| This module defines the :class:`LinesNumbers_QWidget` and :class:`CodeEditor_QPlainTextEdit` classes.
| Those objects provides the basics building blocks of a code editor widget.
**Others:**
Portions of the code from codeeditor.py by Roberto Alsina: http://lateral.netmanagers.com.ar/weblog/posts/BB832.html,
KhtEditor.py by Benoit Hervier: http://khertan.net/khteditor, Ninja IDE: http://ninja-ide.org/ and
Prymatex: https://github.com/D3f0/prymatex/
"""
#**********************************************************************************************************************
#*** External imports.
#**********************************************************************************************************************
import re
from PyQt4.QtCore import QSize
from PyQt4.QtCore import pyqtSignal
from PyQt4.QtGui import QBrush
from PyQt4.QtGui import QColor
from PyQt4.QtGui import QCompleter
from PyQt4.QtGui import QFontMetrics
from PyQt4.QtGui import QPainter
from PyQt4.QtGui import QPen
from PyQt4.QtGui import QSyntaxHighlighter
from PyQt4.QtGui import QTextCursor
from PyQt4.QtGui import QTextDocument
from PyQt4.QtGui import QWidget
#**********************************************************************************************************************
#*** Internal imports.
#**********************************************************************************************************************
import foundations.exceptions
import foundations.strings
import foundations.verbose
import umbra.ui.common
import umbra.ui.languages
from umbra.ui.widgets.basic_QPlainTextEdit import Basic_QPlainTextEdit
from umbra.ui.widgets.basic_QPlainTextEdit import editBlock
from umbra.ui.widgets.basic_QPlainTextEdit import anchorTextCursor
#**********************************************************************************************************************
#*** Module attributes.
#**********************************************************************************************************************
__author__ = "Thomas Mansencal"
__copyright__ = "Copyright (C) 2008 - 2012 - Thomas Mansencal"
__license__ = "GPL V3.0 - http://www.gnu.org/licenses/"
__maintainer__ = "Thomas Mansencal"
__email__ = "thomas.mansencal@gmail.com"
__status__ = "Production"
__all__ = ["LOGGER", "LinesNumbers_QWidget",
"CodeEditor_QPlainTextEdit"]
LOGGER = foundations.verbose.installLogger()
#**********************************************************************************************************************
#*** Module classes and definitions.
#**********************************************************************************************************************
[docs]class CodeEditor_QPlainTextEdit(Basic_QPlainTextEdit):
"""
This class provides a code editor base class.
"""
languageChanged = pyqtSignal()
"""
This signal is emited by the :class:`Editor` class when :obj:`ComponentsManagerUi.language` class property language
is changed. ( pyqtSignal )
"""
def __init__(self,
parent=None,
language=umbra.ui.languages.PYTHON_LANGUAGE,
indentMarker="\t",
indentWidth=4,
commentMarker="#",
*args,
**kwargs):
"""
.. Sphinx: Statements updated for auto-documentation purpose.
:param parent: Widget parent. ( QObject )
:param language: Editor language. ( Language )
:param indentMarker: Indentation marker. ( String )
:param indentWidth: Indentation spaces count. ( Integer )
:param commentMarker: Comment marker. ( String )
:param \*args: Arguments. ( \* )
:param \*\*kwargs: Keywords arguments. ( \*\* )
"""
LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))
Basic_QPlainTextEdit.__init__(self, parent, *args, **kwargs)
# --- Setting class attributes. ---
self.__language = language
self.__indentMarker = None
self.indentMarker = indentMarker
self.__indentWidth = None
self.indentWidth = indentWidth
self.__commentMarker = None
self.commentMarker = commentMarker
self.__marginArea_LinesNumbers_widget = None
self.__highlighter = None
self.__completer = None
self.__occurrencesHighlightColor = QColor(80, 80, 80)
self.__preInputAccelerators = []
self.__postInputAccelerators = []
self.__visualAccelerators = []
self.__textCursorAnchor = None
CodeEditor_QPlainTextEdit.__initializeUi(self)
#******************************************************************************************************************
#*** Attributes properties.
#******************************************************************************************************************
@property
def language(self):
"""
This method is the property for **self.__language** attribute.
:return: self.__language. ( Language )
"""
return self.__language
@language.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
def language(self, value):
"""
This method is the setter method for **self.__language** attribute.
:param value: Attribute value. ( Language )
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "language"))
@language.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def language(self):
"""
This method is the deleter method for **self.__language** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "language"))
@property
def indentMarker(self):
"""
This method is the property for **self.__indentMarker** attribute.
:return: self.__indentMarker. ( String )
"""
return self.__indentMarker
@indentMarker.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def indentMarker(self, value):
"""
This method is the setter method for **self.__indentMarker** attribute.
:param value: Attribute value. ( String )
"""
if value is not None:
assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format(
"indentMarker", value)
assert re.search(r"\s", value), "'{0}' attribute: '{1}' is not a whitespace character!".format(
"indentMarker", value)
self.__indentMarker = value
@indentMarker.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def indentMarker(self):
"""
This method is the deleter method for **self.__indentMarker** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "indentMarker"))
@property
def indentWidth(self):
"""
This method is the property for **self.__indentWidth** attribute.
:return: self.__indentWidth. ( Integer )
"""
return self.__indentWidth
@indentWidth.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def indentWidth(self, value):
"""
This method is the setter method for **self.__indentWidth** attribute.
:param value: Attribute value. ( Integer )
"""
if value is not None:
assert type(value) is int, "'{0}' attribute: '{1}' type is not 'int'!".format("indentWidth", value)
self.__indentWidth = value
@indentWidth.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def indentWidth(self):
"""
This method is the deleter method for **self.__indentWidth** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "indentWidth"))
@property
def commentMarker(self):
"""
This method is the property for **self.__commentMarker** attribute.
:return: self.__commentMarker. ( String )
"""
return self.__commentMarker
@commentMarker.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def commentMarker(self, value):
"""
This method is the setter method for **self.__commentMarker** attribute.
:param value: Attribute value. ( String )
"""
if value is not None:
assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format(
"commentMarker", value)
self.__commentMarker = value
@commentMarker.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
@property
def marginArea_LinesNumbers_widget(self):
"""
This method is the property for **self.__marginArea_LinesNumbers_widget** attribute.
:return: self.__marginArea_LinesNumbers_widget. ( LinesNumbers_QWidget )
"""
return self.__marginArea_LinesNumbers_widget
@marginArea_LinesNumbers_widget.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def marginArea_LinesNumbers_widget(self, value):
"""
This method is the setter method for **self.__marginArea_LinesNumbers_widget** attribute.
:param value: Attribute value. ( LinesNumbers_QWidget )
"""
if value is not None:
assert type(value) is LinesNumbers_QWidget, \
"'{0}' attribute: '{1}' type is not 'LinesNumbers_QWidget'!".format("checked", value)
self.__marginArea_LinesNumbers_widget = value
@marginArea_LinesNumbers_widget.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def marginArea_LinesNumbers_widget(self):
"""
This method is the deleter method for **self.__marginArea_LinesNumbers_widget** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "marginArea_LinesNumbers_widget"))
@property
def highlighter(self):
"""
This method is the property for **self.__highlighter** attribute.
:return: self.__highlighter. ( QSyntaxHighlighter )
"""
return self.__highlighter
@highlighter.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
def highlighter(self, value):
"""
This method is the setter method for **self.__highlighter** attribute.
:param value: Attribute value. ( QSyntaxHighlighter )
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "highlighter"))
@highlighter.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def highlighter(self):
"""
This method is the deleter method for **self.__highlighter** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "highlighter"))
@property
def completer(self):
"""
This method is the property for **self.__completer** attribute.
:return: self.__completer. ( QCompleter )
"""
return self.__completer
@completer.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
def completer(self, value):
"""
This method is the setter method for **self.__completer** attribute.
:param value: Attribute value. ( QCompleter )
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completer"))
@completer.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def completer(self):
"""
This method is the deleter method for **self.__completer** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completer"))
@property
def preInputAccelerators(self):
"""
This method is the property for **self.__preInputAccelerators** attribute.
:return: self.__preInputAccelerators. ( Tuple / List )
"""
return self.__preInputAccelerators
@preInputAccelerators.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def preInputAccelerators(self, value):
"""
This method is the setter method for **self.__preInputAccelerators** attribute.
:param value: Attribute value. ( Tuple / List )
"""
if value is not None:
assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
"preInputAccelerators", value)
self.__preInputAccelerators = value
@preInputAccelerators.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def preInputAccelerators(self):
"""
This method is the deleter method for **self.__preInputAccelerators** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "preInputAccelerators"))
@property
def postInputAccelerators(self):
"""
This method is the property for **self.__postInputAccelerators** attribute.
:return: self.__postInputAccelerators. ( Tuple / List )
"""
return self.__postInputAccelerators
@postInputAccelerators.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def postInputAccelerators(self, value):
"""
This method is the setter method for **self.__postInputAccelerators** attribute.
:param value: Attribute value. ( Tuple / List )
"""
if value is not None:
assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
"postInputAccelerators", value)
self.__postInputAccelerators = value
@postInputAccelerators.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def postInputAccelerators(self):
"""
This method is the deleter method for **self.__postInputAccelerators** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "postInputAccelerators"))
@property
def visualAccelerators(self):
"""
This method is the property for **self.__visualAccelerators** attribute.
:return: self.__visualAccelerators. ( Tuple / List )
"""
return self.__visualAccelerators
@visualAccelerators.setter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(AssertionError)
def visualAccelerators(self, value):
"""
This method is the setter method for **self.__visualAccelerators** attribute.
:param value: Attribute value. ( Tuple / List )
"""
if value is not None:
assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
"visualAccelerators", value)
self.__visualAccelerators = value
@visualAccelerators.deleter
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def visualAccelerators(self):
"""
This method is the deleter method for **self.__visualAccelerators** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "visualAccelerators"))
#******************************************************************************************************************
#*** Class methods.
#******************************************************************************************************************
def __initializeUi(self):
"""
This method initializes the Widget ui.
"""
self.__marginArea_LinesNumbers_widget = LinesNumbers_QWidget(self)
self.__setExtraSelections()
self.__setLanguageDescription()
# Signals / Slots.
self.blockCountChanged.connect(self.__marginArea_LinesNumbers_widget.setEditorViewportMargins)
self.updateRequest.connect(self.__marginArea_LinesNumbers_widget.updateRectangle)
self.cursorPositionChanged.connect(self.__setExtraSelections)
[docs] def resizeEvent(self, event):
"""
This method reimplements the :meth:`Basic_QPlainTextEdit.resizeEvent` method.
:param event: Event. ( QEvent )
"""
Basic_QPlainTextEdit.resizeEvent(self, event)
self.__marginArea_LinesNumbers_widget.updateGeometry()
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def keyPressEvent(self, event):
"""
This method reimplements the :meth:`Basic_QPlainTextEdit.keyPressEvent` method.
:param event: Event. ( QEvent )
"""
processEvent = True
for accelerator in self.__preInputAccelerators:
processEvent *= accelerator(self, event)
if not processEvent:
return
Basic_QPlainTextEdit.keyPressEvent(self, event)
for accelerator in self.__postInputAccelerators:
accelerator(self, event)
def __setExtraSelections(self):
"""
This method sets current document extra selections.
"""
self.setExtraSelections(())
for accelerator in self.__visualAccelerators:
accelerator(self)
def __insertCompletion(self, completion):
"""
This method inserts the completion text in the current document.
:param completion: Completion text. ( QString )
"""
LOGGER.debug("> Inserting '{0}' completion.".format(completion))
textCursor = self.textCursor()
extra = (completion.length() - self.__completer.completionPrefix().length())
textCursor.insertText(completion.right(extra))
self.setTextCursor(textCursor)
def __setLanguageDescription(self):
"""
This method sets the language accelerators.
"""
LOGGER.debug("> Setting language description.")
if not self.__language:
return
if self.__language.highlighter:
self.setHighlighter(self.__language.highlighter(self.document(),
self.__language.rules,
self.__language.theme))
self.highlighter.rehighlight()
else:
self.removeHighlighter()
if self.__language.completer:
self.setCompleter(self.__language.completer(self.parent(), self.__language.name, self.__language.tokens))
else:
self.removeCompleter()
self.indentMarker = self.__language.indentMarker
self.commentMarker = self.__language.commentMarker
self.preInputAccelerators = self.__language.preInputAccelerators
self.postInputAccelerators = self.__language.postInputAccelerators
self.visualAccelerators = self.__language.visualAccelerators
color = "rgb({0}, {1}, {2})"
background = self.__language.theme.get("default").background()
foreground = self.__language.theme.get("default").foreground()
self.setStyleSheet(
"QPlainTextEdit{{ background-color: {0}; color: {1}; }}".format(color.format(background.color().red(),
background.color().green(),
background.color().blue()),
color.format(foreground.color().red(),
foreground.color().green(),
foreground.color().blue())))
self.__tabWidth = self.fontMetrics().width(" " * self.indentWidth)
self.setTabStopWidth(self.__tabWidth)
[docs] def setLanguage(self, language):
"""
This method sets the language.
:param language: Language to set. ( Language )
:return: Method success. ( Boolean )
"""
LOGGER.debug("> Setting editor language to '{0}'.".format(language.name))
self.__language = language or umbra.ui.languages.PYTHON_LANGUAGE
self.__setLanguageDescription()
self.languageChanged.emit()
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def setHighlighter(self, highlighter):
"""
This method sets given highlighter as the current document highlighter.
:param highlighter: Highlighter. ( QSyntaxHighlighter )
:return: Method success. ( Boolean )
"""
if not issubclass(highlighter.__class__, QSyntaxHighlighter):
raise foundations.exceptions.ProgrammingError("{0} | '{1}' is not a 'QSyntaxHighlighter' subclass!".format(
self.__class__.__name__, highlighter))
if self.__highlighter:
self.removeHighlighter()
LOGGER.debug("> Setting '{0}' highlighter.".format(highlighter))
self.__highlighter = highlighter
return True
[docs] def removeHighlighter(self):
"""
This method removes current highlighter.
:return: Method success. ( Boolean )
"""
if self.__highlighter:
LOGGER.debug("> Removing '{0}' highlighter.".format(self.__highlighter))
self.__highlighter.deleteLater()
self.__highlighter = None
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def setCompleter(self, completer):
"""
This method sets given completer as the current completer.
:param completer: Completer. ( QCompleter )
:return: Method success. ( Boolean )
"""
if not issubclass(completer.__class__, QCompleter):
raise foundations.exceptions.ProgrammingError("{0} | '{1}' is not a 'QCompleter' subclass!".format(
self.__class__.__name__, completer))
if self.__completer:
self.removeCompleter()
LOGGER.debug("> Setting '{0}' completer.".format(completer))
self.__completer = completer
self.__completer.setWidget(self)
# Signals / Slots.
self.__completer.activated.connect(self.__insertCompletion)
return True
[docs] def removeCompleter(self):
"""
This method removes current completer.
:return: Method success. ( Boolean )
"""
if self.__completer:
LOGGER.debug("> Removing '{0}' completer.".format(self.__completer))
# Signals / Slots.
self.__completer.activated.disconnect(self.__insertCompletion)
self.__completer.deleteLater()
self.__completer = None
return True
[docs] def getMatchingSymbolsPairs(self, cursor, openingSymbol, closingSymbol, backward=False):
"""
This method returns the cursor for matching given symbols pairs.
:param cursor: Cursor to match from. ( QTextCursor )
:param openingSymbol: Opening symbol. ( String )
:param closingSymbol: Closing symbol to match. ( String )
:return: Matching cursor. ( QTextCursor )
"""
if cursor.hasSelection():
startPosition = cursor.selectionEnd() if backward else cursor.selectionStart()
else:
startPosition = cursor.position()
flags = QTextDocument.FindFlags()
if backward:
flags = flags | QTextDocument.FindBackward
startCursor = previousStartCursor = cursor.document().find(openingSymbol, startPosition, flags)
endCursor = previousEndCursor = cursor.document().find(closingSymbol, startPosition, flags)
if backward:
while startCursor > endCursor:
startCursor = cursor.document().find(openingSymbol, startCursor.selectionStart(), flags)
if startCursor > endCursor:
endCursor = cursor.document().find(closingSymbol, endCursor.selectionStart(), flags)
else:
while startCursor < endCursor:
startCursor = cursor.document().find(openingSymbol, startCursor.selectionEnd(), flags)
if startCursor < endCursor:
endCursor = cursor.document().find(closingSymbol, endCursor.selectionEnd(), flags)
return endCursor.position() != -1 and endCursor or previousEndCursor
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def indent(self):
"""
This method indents the document text under cursor.
:return: Method success. ( Boolean )
"""
cursor = self.textCursor()
if not cursor.hasSelection():
cursor.insertText(self.__indentMarker)
else:
block = self.document().findBlock(cursor.selectionStart())
while True:
blockCursor = self.textCursor()
blockCursor.setPosition(block.position())
blockCursor.insertText(self.__indentMarker)
if block.contains(cursor.selectionEnd()):
break
block = block.next()
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def unindent(self):
"""
This method unindents the document text under cursor.
:return: Method success. ( Boolean )
"""
cursor = self.textCursor()
if not cursor.hasSelection():
cursor.movePosition(QTextCursor.StartOfBlock)
line = foundations.strings.encode(self.document().findBlockByNumber(cursor.blockNumber()).text())
indentMarker = re.match(r"({0})".format(self.__indentMarker), line)
if indentMarker:
foundations.common.repeat(cursor.deleteChar, len(indentMarker.group(1)))
else:
block = self.document().findBlock(cursor.selectionStart())
while True:
blockCursor = self.textCursor()
blockCursor.setPosition(block.position())
indentMarker = re.match(r"({0})".format(self.__indentMarker), block.text())
if indentMarker:
foundations.common.repeat(blockCursor.deleteChar, len(indentMarker.group(1)))
if block.contains(cursor.selectionEnd()):
break
block = block.next()
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def removeTrailingWhiteSpaces(self):
"""
This method removes document trailing white spaces.
:return: Method success. ( Boolean )
"""
cursor = self.textCursor()
block = self.document().findBlockByLineNumber(0)
while block.isValid():
cursor.setPosition(block.position())
if re.search(r"\s+$", block.text()):
cursor.movePosition(QTextCursor.EndOfBlock)
cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.KeepAnchor)
cursor.insertText(foundations.strings.encode(block.text()).rstrip())
block = block.next()
cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
if not cursor.block().text().isEmpty():
cursor.insertText("\n")
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @anchorTextCursor
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def convertIndentationToTabs(self):
"""
This method converts document indentation to tabs.
:return: Method success. ( Boolean )
"""
cursor = self.textCursor()
block = self.document().findBlockByLineNumber(0)
while block.isValid():
cursor.setPosition(block.position())
search = re.match(r"^ +", block.text())
if search:
cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.MoveAnchor)
searchLength = len(search.group(0))
foundations.common.repeat(
lambda: cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor), searchLength)
cursor.insertText(self.__indentMarker * (searchLength / self.__indentWidth))
block = block.next()
return True
#*** Sphinx: Decorator commented for auto-documentation purpose. @anchorTextCursor
#*** Sphinx: Decorator commented for auto-documentation purpose. @editBlock
[docs] def convertIndentationToSpaces(self):
"""
This method converts document indentation to spaces.
:return: Method success. ( Boolean )
"""
cursor = self.textCursor()
block = self.document().findBlockByLineNumber(0)
while block.isValid():
cursor.setPosition(block.position())
search = re.match(r"^\t+", block.text())
if search:
cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.MoveAnchor)
searchLength = len(search.group(0))
foundations.common.repeat(
lambda: cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor), searchLength)
cursor.insertText(" " * (searchLength * self.__indentWidth))
block = block.next()
return True
#**********************************************************************************************************************
#*** Sphinx: Statements updated for auto-documentation purpose.
#**********************************************************************************************************************