# Python imports import os import threading import subprocess import time # Lib imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports from plugins.plugin_base import PluginBase # NOTE: Threads WILL NOT die with parent's destruction. def threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() return wrapper # NOTE: Threads WILL die with parent's destruction. def daemon_threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() return wrapper class Plugin(PluginBase): def __init__(self): super().__init__() self.name = "Autopairs" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus # where self.name should not be needed for message comms self.chars = { "quotedbl": "\"", "apostrophe": "'", "parenleft": "(", "bracketleft": "[", "braceleft": "{", "less": "<", "grave": "`", } self.close = { "\"": "\"", "'": "'", "(": ")", "[": "]", "{": "}", "<": ">", "`": "`", } def generate_reference_ui_element(self): ... def run(self): ... def subscribe_to_events(self): self._event_system.subscribe("set_active_src_view", self._set_active_src_view) self._event_system.subscribe("autopairs", self._autopairs) def _set_active_src_view(self, source_view): self._active_src_view = source_view self._buffer = self._active_src_view.get_buffer() self._tag_table = self._buffer.get_tag_table() def _autopairs(self, keyval_name, ctrl, alt, shift): if keyval_name in self.chars: return self.text_insert(self._buffer, keyval_name) # NOTE: All of below to EOF, lovingly taken from Hamad Al Marri's Gamma # text editor. I did do some cleanup of comments but otherwise pretty # much the same code just fitted to my plugin architecture. # Link: https://gitlab.com/hamadmarri/gamma-text-editor def text_insert(self, buffer, text): selection = buffer.get_selection_bounds() if selection == (): return self.add_close(buffer, text, ) else: return self.add_enclose(buffer, text, selection) def add_close(self, buffer, text): text = self.chars[text] text += self.close[text] position = buffer.get_iter_at_mark( buffer.get_insert() ) c = position.get_char() if not c in (" ", "", ";", ":", "\t", ",", ".", "\n", "\r") \ and not c in list(self.close.values()): return False buffer.insert(position, text) position = buffer.get_iter_at_mark(buffer.get_insert()) position.backward_char() buffer.place_cursor(position) return True def add_enclose(self, buffer, text, selection): (start, end) = selection selected = buffer.get_text(start, end, False) if len(selected) <= 3 and selected in ("<", ">", ">>>" "<<", ">>", "\"", "'", "`", "(", ")", "[", "]", "{", "}", "=", "==", "!=", "==="): return False start_mark = buffer.create_mark("startclose", start, False) end_mark = buffer.create_mark("endclose", end, False) buffer.begin_user_action() t = self.chars[text] buffer.insert(start, t) end = buffer.get_iter_at_mark(end_mark) t = self.close[t] buffer.insert(end, t) start = buffer.get_iter_at_mark(start_mark) end = buffer.get_iter_at_mark(end_mark) end.backward_char() buffer.select_range(start, end) buffer.end_user_action() return True