File: C:/Users/fred/anaconda3/Lib/site-packages/spyder/plugins/editor/extensions/closebrackets.py
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""This module contains the close quotes editor extension."""
from qtpy.QtGui import QTextCursor
from spyder.api.editorextension import EditorExtension
class CloseBracketsExtension(EditorExtension):
"""Editor Extension for insert brackets automatically."""
BRACKETS_CHAR = ["(", ")", "{", "}", "[", "]"]
BRACKETS_LEFT = BRACKETS_CHAR[::2]
BRACKETS_RIGHT = BRACKETS_CHAR[1::2]
BRACKETS_PAIR = {"(": "()", ")": "()",
"{": "{}", "}": "{}",
"[": "[]", "]": "[]"}
def on_state_changed(self, state):
"""Connect/disconnect sig_key_pressed signal."""
if state:
self.editor.sig_key_pressed.connect(self._on_key_pressed)
else:
self.editor.sig_key_pressed.disconnect(self._on_key_pressed)
def _on_key_pressed(self, event):
if event.isAccepted():
return
# It is necessary to use here the text of the event and not the key
# to avoid issues with international keyboards.
# See spyder-ide/spyder#9749
char = event.text()
if char in self.BRACKETS_CHAR and self.enabled:
self.editor.completion_widget.hide()
self._autoinsert_brackets(char)
event.accept()
def unmatched_brackets_in_line(self, text, closing_brackets_type=None,
autoinsert=False):
"""
Checks if there is an unmatched brackets in the 'text'.
The brackets type can be general or specified by closing_brackets_type
(')', ']' or '}')
"""
if closing_brackets_type is None:
opening_brackets = self.BRACKETS_LEFT
closing_brackets = self.BRACKETS_RIGHT
else:
closing_brackets = [closing_brackets_type]
opening_brackets = [{')': '(', '}': '{',
']': '['}[closing_brackets_type]]
block = self.editor.textCursor().block()
line_pos = block.position()
for pos, char in enumerate(text):
if char in opening_brackets:
match = self.editor.find_brace_match(line_pos+pos, char,
forward=True)
if (match is None) or (match > line_pos+len(text)):
return True
if char in closing_brackets:
match = self.editor.find_brace_match(line_pos+pos, char,
forward=False)
# Only validate match existence for autoinsert.
# Having the missing bracket in a previous line is possible.
# See spyder-ide/spyder#11217
if (match is None) or (match < line_pos and not autoinsert):
return True
return False
def _autoinsert_brackets(self, char):
"""Control automatic insertation of brackets in various situations."""
pair = self.BRACKETS_PAIR[char]
cursor = self.editor.textCursor()
trailing_text = self.editor.get_text('cursor', 'eol').strip()
if self.editor.has_selected_text():
text = self.editor.get_selected_text()
self.editor.insert_text("{0}{1}{2}".format(pair[0], text, pair[1]))
# Keep text selected, for inserting multiple brackets
cursor.movePosition(QTextCursor.Left, QTextCursor.MoveAnchor, 1)
cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
len(text))
self.editor.setTextCursor(cursor)
elif char in self.BRACKETS_LEFT:
if (not trailing_text or
trailing_text[0] in self.BRACKETS_RIGHT or
trailing_text[0] in [',', ':', ';']):
# Automatic insertion of brackets
self.editor.insert_text(pair)
cursor.movePosition(QTextCursor.PreviousCharacter)
self.editor.setTextCursor(cursor)
else:
self.editor.insert_text(char)
if char in self.editor.signature_completion_characters:
self.editor.request_signature()
elif char in self.BRACKETS_RIGHT:
if (self.editor.next_char() == char and
not self.editor.textCursor().atBlockEnd() and
not self.unmatched_brackets_in_line(
cursor.block().text(), char, autoinsert=True)):
# Overwrite an existing brackets if all in line are matched
cursor.movePosition(QTextCursor.NextCharacter,
QTextCursor.KeepAnchor, 1)
cursor.clearSelection()
self.editor.setTextCursor(cursor)
else:
self.editor.insert_text(char)