ProjectKivy/CompleterKivy.py

Tue, 10 Dec 2024 15:48:59 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 10 Dec 2024 15:48:59 +0100
branch
eric7
changeset 70
2c0a54bf5b4c
parent 68
20cdd6e03807
permissions
-rw-r--r--

Updated copyright for 2025.

# -*- coding: utf-8 -*-

# Copyright (c) 2023 - 2025 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the Kivy typing completer.
"""

import re

from PyQt6.Qsci import QsciScintilla

from eric7.QScintilla.TypingCompleters.CompleterBase import CompleterBase


class CompleterKivy(CompleterBase):
    """
    Class implementing the Kivy typing completer.
    """

    def __init__(self, plugin, editor, parent=None):
        """
        Constructor

        @param plugin reference to the plugin object
        @type ProjectKivyPlugin
        @param editor reference to the editor object
        @type Editor
        @param parent reference to the parent object
        @type QObject
        """
        super().__init__(editor, parent)

        self.__plugin = plugin

        self.__autoIndentationRe = re.compile(r"(?:\(|\[|{|:)(\s*)\r?\n")
        self.__trailingBlankRe = re.compile(r"(?:,)(\s*)\r?\n")
        # Trailing blank after ':' is already covered by auto indent rule

        self.readSettings()

    def readSettings(self):
        """
        Public slot called to reread the configuration parameters.
        """
        self.setEnabled(self.__plugin.getTypingPreferences("EnabledTypingAids"))
        self.__insertClosingBrace = self.__plugin.getTypingPreferences(
            "InsertClosingBrace"
        )
        self.__skipBrace = self.__plugin.getTypingPreferences("SkipBrace")
        self.__colonDetection = self.__plugin.getTypingPreferences("ColonDetection")
        self.__autoIndentation = self.__plugin.getTypingPreferences("AutoIndentation")
        self.__insertQuote = self.__plugin.getTypingPreferences("InsertQuote")
        self.__insertBlankColon = self.__plugin.getTypingPreferences("InsertBlankColon")
        self.__insertBlankComma = self.__plugin.getTypingPreferences("InsertBlankComma")

    def charAdded(self, charNumber):
        """
        Public slot called to handle the user entering a character.

        @param charNumber value of the character entered
        @type int
        """
        char = chr(charNumber)
        if char not in (
            "{",
            "}",
            "[",
            "]",
            "(",
            ")",
            "<",
            ">",
            "'",
            '"',
            ":",
            ",",
            "\n",
        ):
            return  # take the short route

        line, col = self.editor.getCursorPosition()

        if self.__inComment(line, col):
            return

        # open parenthesis
        # insert closing parenthesis
        if char == "(" and self.__insertClosingBrace:
            self.editor.insert(")")

        # open curly bracket
        # insert closing bracket
        elif char == "{" and self.__insertClosingBrace:
            self.editor.insert("}")

        # open bracket
        # insert closing bracket
        elif char == "[" and self.__insertClosingBrace:
            self.editor.insert("]")

        # open tag bracket
        # insert closing bracket
        elif char == "<" and self.__insertClosingBrace:
            self.editor.insert(">")

        # closing parenthesis
        # skip matching closing parenthesis
        elif char in (")", "}", "]", ">"):
            txt = self.editor.text(line)
            if col < len(txt) and char == txt[col] and self.__skipBrace:
                self.editor.setSelection(line, col, line, col + 1)
                self.editor.removeSelectedText()

        # colon
        # 1. skip colon if not last character
        # 2. insert blank if last character
        elif char == ":":
            text = self.editor.text(line)
            if col < len(text) and char == text[col]:
                if self.__colonDetection:
                    self.editor.setSelection(line, col, line, col + 1)
                    self.editor.removeSelectedText()
            elif self.__insertBlankColon and col == len(text.rstrip()):
                self.editor.insert(" ")
                self.editor.setCursorPosition(line, col + 1)

        # comma
        # insert blank
        elif char == "," and self.__insertBlankComma:
            self.editor.insert(" ")
            self.editor.setCursorPosition(line, col + 1)

        # double quote
        # insert double quote
        elif char == '"' and self.__insertQuote:
            self.editor.insert('"')

        # quote
        # insert quote
        elif char == "'" and self.__insertQuote:
            self.editor.insert("'")

        # new line
        # indent after line ending with auto indentation character
        elif char == "\n":
            txt = self.editor.text(line - 1)
            if self.__autoIndentation and self.__autoIndentationRe.search(txt):
                match = self.__autoIndentationRe.search(txt)
                if match is not None:
                    startBlanks = match.start(1)
                    endBlanks = match.end(1)
                    if startBlanks != -1 and startBlanks != endBlanks:
                        # previous line ends with whitespace, e.g. caused by
                        # blank insertion above
                        self.editor.setSelection(
                            line - 1, startBlanks, line - 1, endBlanks
                        )
                        self.editor.removeSelectedText()

                    self.editor.indent(line)
                    self.editor.setCursorPosition(line, 0)
                    self.editor.editorCommand(QsciScintilla.SCI_VCHOME)

            elif (
                self.__insertBlankColon or self.__insertBlankComma
            ) and self.__trailingBlankRe.search(txt):
                # remove blank at end of line inserted by blank insertion above
                match = self.__trailingBlankRe.search(txt)
                if match is not None:
                    startBlanks = match.start(1)
                    endBlanks = match.end(1)
                    if startBlanks != -1 and startBlanks != endBlanks:
                        self.editor.setSelection(
                            line - 1, startBlanks, line - 1, endBlanks
                        )
                        self.editor.removeSelectedText()

                    self.editor.setCursorPosition(line, 0)
                    self.editor.editorCommand(QsciScintilla.SCI_VCHOME)

    def __inComment(self, line, col):
        """
        Private method to check, if the cursor is inside a comment.

        @param line current line
        @type int
        @param col current position within line
        @type int
        @return flag indicating, if the cursor is inside a comment
        @rtype bool
        """
        txt = self.editor.text(line)
        if col == len(txt):
            col -= 1
        while col >= 0:
            if txt[col] == "#":
                return True
            col -= 1
        return False

eric ide

mercurial