generated from itdominator/Python-With-Gtk-Template
added colorize plugin; added events; added highlight find functionality
This commit is contained in:
parent
6611eaacd2
commit
d6d9ce54bd
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Pligin Module
|
||||
"""
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Pligin Package
|
||||
"""
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"manifest": {
|
||||
"name": "Colorize",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {
|
||||
"pass_events": "true"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
# Python imports
|
||||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
import time
|
||||
import colorsys
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
# 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 = "Colorize" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
|
||||
# where self.name should not be needed for message comms
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
def generate_reference_ui_element(self):
|
||||
...
|
||||
|
||||
def subscribe_to_events(self):
|
||||
self._event_system.subscribe("set_active_src_view", self._set_active_src_view)
|
||||
event_system.subscribe("buffer_changed_first_load", self._buffer_changed_first_load)
|
||||
event_system.subscribe("buffer_changed", self._buffer_changed)
|
||||
|
||||
|
||||
def _set_active_src_view(self, source_view):
|
||||
self._active_src_view = source_view
|
||||
|
||||
def _buffer_changed_first_load(self, buffer):
|
||||
# rgb(a), hsl, hsv
|
||||
results = self.finalize_non_hex_matches( self.collect_preliminary_results(buffer) )
|
||||
self.process_results(buffer, results)
|
||||
|
||||
# hex color search
|
||||
results = self.finalize_hex_matches( self.collect_preliminary_hex_results(buffer) )
|
||||
self.process_results(buffer, results)
|
||||
|
||||
|
||||
def _buffer_changed(self):
|
||||
...
|
||||
|
||||
|
||||
def search(self, start_itr = None, query = None):
|
||||
if not start_itr or not query: return None, None
|
||||
|
||||
results = []
|
||||
_flags = Gtk.TextSearchFlags.VISIBLE_ONLY & Gtk.TextSearchFlags.TEXT_ONLY
|
||||
while True:
|
||||
result = start_itr.forward_search(query, flags = _flags, limit = None)
|
||||
if not result: break
|
||||
|
||||
results.append(result)
|
||||
start_itr = result[1]
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def collect_preliminary_results(self, buffer = None):
|
||||
if not buffer: return []
|
||||
|
||||
start_itr = buffer.get_start_iter()
|
||||
results1 = self.search(start_itr, "rgb")
|
||||
results2 = self.search(start_itr, "hsl")
|
||||
results3 = self.search(start_itr, "hsv")
|
||||
|
||||
return results1 + results2 + results3
|
||||
|
||||
def collect_preliminary_hex_results(self, buffer = None):
|
||||
if not buffer: return []
|
||||
|
||||
start_itr = buffer.get_start_iter()
|
||||
results1 = self.search(start_itr, "#")
|
||||
|
||||
return results1
|
||||
|
||||
def finalize_non_hex_matches(self, result_hits: [] = []):
|
||||
results = []
|
||||
|
||||
for start, end in result_hits:
|
||||
if end.get_char() == "a":
|
||||
end.forward_char()
|
||||
|
||||
if end.get_char() != "(":
|
||||
continue
|
||||
|
||||
end.forward_chars(21)
|
||||
if end.get_char() == ")":
|
||||
end.forward_char()
|
||||
results.append([start, end])
|
||||
continue
|
||||
|
||||
while end.get_char() != "(":
|
||||
if end.get_char() == ")":
|
||||
end.forward_char()
|
||||
results.append([start, end])
|
||||
break
|
||||
|
||||
end.forward_chars(-1)
|
||||
|
||||
return results
|
||||
|
||||
def finalize_hex_matches(self, result_hits: [] = []):
|
||||
results = []
|
||||
|
||||
for start, end in result_hits:
|
||||
while not end.get_char() in [";", " "]:
|
||||
end.forward_char()
|
||||
|
||||
results.append([start, end])
|
||||
|
||||
return results
|
||||
|
||||
def process_results(self, buffer, results):
|
||||
# NOTE: HSV and HSL parsing are available in Gtk 4.0. Not lower...
|
||||
for start, end in results:
|
||||
text = buffer.get_text(start, end, include_hidden_chars = False)
|
||||
color = Gdk.RGBA()
|
||||
|
||||
if "hsl" in text:
|
||||
text = self.hsl_to_rgb(text)
|
||||
|
||||
if "hsv" in text:
|
||||
text = self.hsv_to_rgb(text)
|
||||
|
||||
if color.parse(text):
|
||||
tag = self.get_colorized_tag(buffer, text, color)
|
||||
buffer.apply_tag(tag, start, end)
|
||||
|
||||
def get_colorized_tag(self, buffer, tag, color: Gdk.RGBA):
|
||||
tag_table = buffer.get_tag_table()
|
||||
colorize_tag = f"colorize_tag_{tag}"
|
||||
search_tag = tag_table.lookup(f"colorize_tag_{tag}")
|
||||
if not search_tag:
|
||||
search_tag = buffer.create_tag(colorize_tag, background_rgba = color)
|
||||
|
||||
return search_tag
|
||||
|
||||
def hsl_to_rgb(self, text):
|
||||
_h, _s , _l = text.replace("hsl", "") \
|
||||
.replace("deg", "") \
|
||||
.replace("(", "") \
|
||||
.replace(")", "") \
|
||||
.replace("%", "") \
|
||||
.replace(" ", "") \
|
||||
.split(",")
|
||||
|
||||
h = None
|
||||
s = None
|
||||
l = None
|
||||
|
||||
try:
|
||||
h, s , l = int(_h) / 360, float(_s) / 100, float(_l) / 100
|
||||
except Exception as e:
|
||||
raise
|
||||
|
||||
rgb = tuple(round(i * 255) for i in colorsys.hls_to_rgb(h, l, s))
|
||||
rgb_sub = ','.join(map(str, rgb))
|
||||
|
||||
return f"rgb({rgb_sub})"
|
||||
|
||||
|
||||
def hsv_to_rgb(self, text):
|
||||
_h, _s , _v = text.replace("hsv", "") \
|
||||
.replace("deg", "") \
|
||||
.replace("(", "") \
|
||||
.replace(")", "") \
|
||||
.replace("%", "") \
|
||||
.replace(" ", "") \
|
||||
.split(",")
|
||||
|
||||
h = None
|
||||
s = None
|
||||
v = None
|
||||
|
||||
try:
|
||||
h, s , v = int(_h) / 360, float(_s) / 100, float(_v) / 100
|
||||
except Exception as e:
|
||||
raise
|
||||
|
||||
rgb = tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))
|
||||
rgb_sub = ','.join(map(str, rgb))
|
||||
|
||||
return f"rgb({rgb_sub})"
|
|
@ -66,11 +66,22 @@ class Plugin(PluginBase):
|
|||
|
||||
def _tggl_search_replace(self, widget = None, eve = None):
|
||||
is_visible = self._search_replace_dialog.is_visible()
|
||||
buffer = self._active_src_view.get_buffer()
|
||||
data = None
|
||||
|
||||
if buffer.get_has_selection():
|
||||
start, end = buffer.get_selection_bounds()
|
||||
data = buffer.get_text(start, end, include_hidden_chars = False)
|
||||
|
||||
if data:
|
||||
self._find_entry.set_text(data)
|
||||
|
||||
if not is_visible:
|
||||
self._search_replace_dialog.popup();
|
||||
self._find_entry.grab_focus()
|
||||
else:
|
||||
elif not data and is_visible:
|
||||
self._search_replace_dialog.popdown()
|
||||
self._find_entry.set_text("")
|
||||
|
||||
def tggle_regex(self, widget):
|
||||
self.use_regex = not widget.get_active()
|
||||
|
|
|
@ -59,7 +59,10 @@ class PythonCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
|
|||
return False
|
||||
|
||||
ch = iter.get_char()
|
||||
if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
|
@ -20,6 +20,7 @@ class FileEventsMixin:
|
|||
|
||||
def open_file(self, gfile, line: int = 0, *args):
|
||||
self._current_file = gfile
|
||||
self._loading_file = True
|
||||
|
||||
self.load_file_info(gfile)
|
||||
self.load_file_async(gfile, line)
|
||||
|
@ -72,6 +73,7 @@ class FileEventsMixin:
|
|||
self._document_loaded()
|
||||
self.got_to_line(line)
|
||||
self.update_labels(gfile)
|
||||
self._loading_file = False
|
||||
|
||||
self._file_loader.load_async(io_priority = 70,
|
||||
cancellable = None,
|
||||
|
|
|
@ -35,6 +35,7 @@ class SourceView(SourceViewEventsMixin, GtkSource.View):
|
|||
|
||||
self._skip_file_load = False
|
||||
self._ignore_internal_change = False
|
||||
self._loading_file = False
|
||||
self._buffer = self.get_buffer()
|
||||
self._completion = self.get_completion()
|
||||
self._px_value = settings.theming.default_zoom
|
||||
|
@ -117,6 +118,11 @@ class SourceView(SourceViewEventsMixin, GtkSource.View):
|
|||
general_style_tag.set_property('scale', 100)
|
||||
|
||||
def _is_modified(self, *args):
|
||||
if not self._loading_file:
|
||||
event_system.emit("buffer_changed")
|
||||
else:
|
||||
event_system.emit("buffer_changed_first_load", (self._buffer, ))
|
||||
|
||||
self.update_cursor_position()
|
||||
|
||||
def _insert_text(self, text_buffer, location_itr, text_str, len_int):
|
||||
|
|
Loading…
Reference in New Issue