Source code for FoxDot.lib.Workspace.BracketHandler

from .tkimport import *

from .Format import *
from .AppFunctions import *

from ..Settings import AUTO_COMPLETE_BRACKETS

whitespace = [" ","\t","\n","\r","\f","\v"]

[docs] class BracketHandler: counter = 0 def __init__(self, master): self.root = master self.text = master.text self.active = AUTO_COMPLETE_BRACKETS self.inbrackets = False self.separators = py_separators self.style = bracket_formatting self.left_brackets = dict(zip(left_b, right_b)) self.right_brackets = dict(zip(right_b, left_b)) self.right_brackets_only = list("]})") self.queue = [] if self.active: for char in list(self.left_brackets.keys()) + list(self.right_brackets.keys()): self.text.bind(char, self.handle) # this binds bracket presses to the handle method self.visible_range = (0,0)
[docs] def handle(self, event=None, insert=INSERT): self.visible_range = self.text.get_visible_range() ret = None line, column = index(self.text.index(insert)) # 1. Type a left bracket next_char = self.text.get(index(line, column)) if event.char in self.left_brackets: # A. Type a left bracket and an area is selected try: a = self.text.index(SEL_FIRST) b = self.text.index(SEL_LAST) self.text.insert(b, self.left_brackets[event.char]) self.text.insert(a, event.char) # unselect self.text.tag_remove(SEL, "1.0", END) ret = "break" except: pass # B. If next character is a whitespace or a right bracket add a closing bracket as well. if next_char in whitespace + self.right_brackets_only: # If the next char is quote mark, just move the cursor if event.char in ("'", '"'): if event.char == next_char: self.text.mark_set(insert, index(line, column + 1)) ret = "break" else: # Only add a closing quote mark if there are already an even no. of quotes in the line text = self.text.get(index(line, 0), index(line, "end")) n = text.count(event.char) if n % 2 == 0: self.text.insert(self.text.index(insert), event.char + self.left_brackets[event.char]) self.text.mark_set(insert, index(line, column + 1)) ret = "break" else: self.text.insert(self.text.index(insert), event.char + self.left_brackets[event.char]) self.text.mark_set(insert, index(line, column + 1)) ret = "break" # Update line colours self.root.colour_line(line) # 2. Type right bracket elif event.char in self.right_brackets: # Go back and find an open bracket -> assume the first open bracket is related to *this* one self.text.insert("{}.{}".format(line,column), event.char) # Add bracket coords = self.find_starting_bracket(line, column, event.char) new_line, new_col = line, column + 1 # Assume we are adding a new bracket adding_bracket = True # Get index of the end of the buffer end_line, end_col = index(self.text.index("{}.end".format(self.visible_range[1]))) while (new_line, new_col) != (end_line, end_col): # If we find a closing bracket, find it's pair next_char = self.text.get(index(new_line, new_col)) if next_char == event.char: coords_ = self.find_starting_bracket(new_line, new_col, event.char, offset=0) # If there is a closing brackets if coords_ is None: adding_bracket = False break else: adding_bracket = True if index(new_line, new_col) == self.text.index(index(new_line, "end")): new_line += 1 new_col = 0 else: new_col += 1 if not adding_bracket: loc = index(line, column+1) if self.text.get(loc) == event.char: self.text.delete(loc) ret = "break" # Update line colours self.root.colour_line(line) # Highlight brackets (remove old highlighting first) self.text.tag_delete("tag_open_brackets") if coords is not None: row, col = coords self.text.tag_config("tag_open_brackets", **self.style) self.text.tag_add("tag_open_brackets", "{}.{}".format(row,col), "{}.{}".format(row,col+1)) self.text.tag_add("tag_open_brackets", "{}.{}".format(line,column), "{}.{}".format(line,column+1)) if ret is None: self.text.insert(INSERT, event.char) self.root.colour_line(line) # Store the text self.root.text_as_string = self.root.get_all() # Add separator to undo stack self.text.edit_separator() return "break"
[docs] def delete(self, insert=INSERT): """ Deletes enclosed set of brackets if no contents and returns True, returns False all other times """ if self.active: line, column = index(self.text.index(insert)) next_char = self.text.get(index(line, column)) prev_char = self.text.get(index(line, column-1)) if prev_char in self.left_brackets: if next_char == self.left_brackets[prev_char] and column > 0: self.text.delete(index(line, column-1), index(line, column+1)) return True return False
[docs] def find_starting_bracket(self, line, column, bracket_style, offset = 0): """ Finds the opening bracket to the closing bracket at line, column co-ords. Returns None if not found. Only goes as far as the first line visible on screen""" line_length = column - 1 used_br = offset start_row, end_row = self.visible_range # returns tuple for row in range(line, start_row - 1, -1): for col in range(line_length, -1, -1): # If the char is a left bracket and not used, break if self.text.get("{}.{}".format(row, col)) == self.right_brackets[bracket_style]: if used_br == 0: return row, col else: used_br -= 1 elif self.text.get("{}.{}".format(row, col)) == bracket_style: used_br += 1 line_length = int(self.text.index("{}.end".format(row-1)).split(".")[1]) else: return None