Refactoring notebook and sourceview; embedding keybindings for time being

This commit is contained in:
itdominator 2023-11-02 01:29:50 -05:00
parent d09a6e063e
commit 3b2fab0f4c
13 changed files with 412 additions and 394 deletions

View File

@ -3,10 +3,12 @@
# Lib imports # Lib imports
# Application imports # Application imports
from .key_input_controller import KeyInputController
from .editor_events import EditorEventsMixin
class EditorControllerMixin: class EditorControllerMixin(KeyInputController, EditorEventsMixin):
def get_active_view(self): def get_active_view(self):
page_num = self.get_current_page() page_num = self.get_current_page()
container = self.get_nth_page( page_num ) container = self.get_nth_page( page_num )
@ -19,47 +21,13 @@ class EditorControllerMixin:
return return
page_num, container, source_view = self.get_active_view() page_num, container, source_view = self.get_active_view()
if action == "close_tab":
self.close_tab(None, container, source_view)
if action == "keyboard_prev_tab":
self.keyboard_prev_tab(page_num)
if action == "keyboard_next_tab":
self.keyboard_next_tab(page_num)
if action == "keyboard_move_tab_left":
self.keyboard_move_tab_left(page_num)
if action == "keyboard_move_tab_right":
self.keyboard_move_tab_right(page_num)
if action == "keyboard_move_tab_to_1":
self.keyboard_move_tab_to_1(page_num)
if action == "keyboard_move_tab_to_2":
self.keyboard_move_tab_to_2(page_num)
# NOTE: These feel bad being here man... # NOTE: These feel bad being here man...
if action == "scale_up_text": if action == "scale_up_text":
self.scale_up_text(source_view) self.scale_up_text(source_view)
if action == "keyboard_undo":
self.keyboard_undo(source_view)
if action == "keyboard_redo":
self.keyboard_redo(source_view)
if action == "scale_down_text": if action == "scale_down_text":
self.scale_down_text(source_view) self.scale_down_text(source_view)
if action == "toggle_highlight_line":
self.toggle_highlight_line(source_view)
if action == "keyboard_insert_mark":
self.keyboard_insert_mark(source_view)
if action == "keyboard_clear_marks":
self.keyboard_clear_marks(source_view)
if action == "keyboard_move_lines_up":
self.keyboard_move_lines_up(source_view)
if action == "keyboard_move_lines_down":
self.keyboard_move_lines_down(source_view)
if action == "set_buffer_language": if action == "set_buffer_language":
self.set_buffer_language(source_view, query) self.set_buffer_language(source_view, query)
if action == "set_buffer_style": if action == "set_buffer_style":
self.set_buffer_style(source_view, query) self.set_buffer_style(source_view, query)
if action == "save_file":
return source_view.save_file()
if action == "save_file_as":
return source_view.save_file_as()

View File

@ -101,36 +101,17 @@ class EditorEventsMixin:
# NOTE: These feel bad being here man... # NOTE: These feel bad being here man...
def keyboard_undo(self, source_view):
source_view.keyboard_undo()
def keyboard_redo(self, source_view):
source_view.keyboard_redo()
def scale_up_text(self, source_view): def scale_up_text(self, source_view):
source_view.scale_up_text() source_view.scale_up_text()
def scale_down_text(self, source_view): def scale_down_text(self, source_view):
source_view.scale_down_text() source_view.scale_down_text()
def toggle_highlight_line(self, source_view):
source_view.toggle_highlight_line()
def keyboard_insert_mark(self, source_view):
source_view.keyboard_insert_mark()
def keyboard_clear_marks(self, source_view):
source_view.keyboard_clear_marks()
def keyboard_move_lines_up(self, source_view):
source_view.keyboard_move_lines_up()
def keyboard_move_lines_down(self, source_view):
source_view.keyboard_move_lines_down()
def set_buffer_language(self, source_view, language = "python3"): def set_buffer_language(self, source_view, language = "python3"):
source_view.set_buffer_language(language) source_view.set_buffer_language(language)
def set_buffer_style(self, source_view, style = settings.theming.syntax_theme): def set_buffer_style(self, source_view, style = settings.theming.syntax_theme):
buffer = source_view.get_buffer() buffer = source_view.get_buffer()
source_view.set_buffer_style(buffer, style) source_view.set_buffer_style(buffer, style)

View File

@ -10,13 +10,11 @@ from gi.repository import Gio
# Application imports # Application imports
from .editor_controller import EditorControllerMixin from .editor_controller import EditorControllerMixin
from .editor_events import EditorEventsMixin
# NOTE: https://github.com/Axel-Erfurt/TextEdit/tree/b65f09be945196eb05bef83d81a6abcd129b4eb0 # NOTE: https://github.com/Axel-Erfurt/TextEdit/tree/b65f09be945196eb05bef83d81a6abcd129b4eb0
class EditorNotebook(EditorControllerMixin, Gtk.Notebook):
class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
ccount = 0 ccount = 0
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
@ -35,7 +33,6 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
self.set_group_name("editor_widget") self.set_group_name("editor_widget")
self.builder.expose_object(self.NAME, self) self.builder.expose_object(self.NAME, self)
self._add_action_widgets()
self._setup_styling() self._setup_styling()
self._setup_signals() self._setup_signals()
self._subscribe_to_events() self._subscribe_to_events()
@ -57,35 +54,30 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
def _setup_signals(self): def _setup_signals(self):
self.connect("switch-page", self._switch_page_update) self.connect("switch-page", self._switch_page_update)
self.connect("key-press-event", self._key_press_event)
self.connect("key-release-event", self._key_release_event)
def _subscribe_to_events(self): def _subscribe_to_events(self):
event_system.subscribe("create_view", self._create_view) event_system.subscribe("create_view", self._create_view)
event_system.subscribe("set_buffer_style", self.action_controller) event_system.subscribe("set_buffer_style", self.action_controller)
event_system.subscribe("set_buffer_language", self.action_controller) event_system.subscribe("set_buffer_language", self.action_controller)
event_system.subscribe("focused_target_changed", self._focused_target_changed) event_system.subscribe("focused_target_changed", self._focused_target_changed)
event_system.subscribe("keyboard_create_tab", self._keyboard_create_tab)
event_system.subscribe("keyboard_open_file", self._keyboard_open_file)
event_system.subscribe("keyboard_close_tab", self._keyboard_close_tab)
event_system.subscribe("keyboard_prev_tab", self._keyboard_prev_tab)
event_system.subscribe("keyboard_next_tab", self._keyboard_next_tab)
event_system.subscribe("keyboard_move_tab_left", self._keyboard_move_tab_left)
event_system.subscribe("keyboard_move_tab_right", self._keyboard_move_tab_right)
event_system.subscribe("keyboard_move_tab_to_1", self._keyboard_move_tab_to_1)
event_system.subscribe("keyboard_move_tab_to_2", self._keyboard_move_tab_to_2)
event_system.subscribe("toggle_highlight_line", self._toggle_highlight_line) event_system.subscribe("keyboard_open_file", self._keyboard_open_file)
event_system.subscribe("keyboard_move_lines_up", self._keyboard_move_lines_up)
event_system.subscribe("keyboard_move_lines_down", self._keyboard_move_lines_down)
event_system.subscribe("keyboard_undo", self._keyboard_undo)
event_system.subscribe("keyboard_redo", self._keyboard_redo)
event_system.subscribe("keyboard_insert_mark", self._keyboard_insert_mark)
event_system.subscribe("keyboard_clear_marks", self._keyboard_clear_marks)
event_system.subscribe("keyboard_scale_up_text", self._keyboard_scale_up_text) event_system.subscribe("keyboard_scale_up_text", self._keyboard_scale_up_text)
event_system.subscribe("keyboard_scale_down_text", self._keyboard_scale_down_text) event_system.subscribe("keyboard_scale_down_text", self._keyboard_scale_down_text)
event_system.subscribe("keyboard_save_file", self._keyboard_save_file)
event_system.subscribe("keyboard_save_file_as", self._keyboard_save_file_as)
# event_system.subscribe("keyboard_save_file_as", self._keyboard_save_file_as)
def _load_widgets(self):
self._add_action_widgets()
if self.NAME == "notebook_1" and not settings_manager.is_starting_with_file():
self.create_view()
def _dbl_click_create_view(self, notebook, eve):
if eve.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and eve.button == 1: # l-click
...
def _focused_target_changed(self, target): def _focused_target_changed(self, target):
self.is_editor_focused = True if target == self.NAME else False self.is_editor_focused = True if target == self.NAME else False
@ -108,14 +100,6 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
self.set_action_widget(start_box, 0) self.set_action_widget(start_box, 0)
self.set_action_widget(end_box, 1) self.set_action_widget(end_box, 1)
def _load_widgets(self):
if self.NAME == "notebook_1" and not settings_manager.is_starting_with_file():
self.create_view()
def _dbl_click_create_view(self, notebook, eve):
if eve.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and eve.button == 1: # l-click
...
def _switch_page_update(self, notebook, page, page_num): def _switch_page_update(self, notebook, page, page_num):
source_view = page.get_source_view() source_view = page.get_source_view()
gfile = source_view.get_current_file() gfile = source_view.get_current_file()
@ -150,66 +134,8 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
self.open_file(gfile) self.open_file(gfile)
def _keyboard_create_tab(self, _gfile = None):
if not self.is_editor_focused: # TODO: Find way to converge this
return
self.create_view(gfile = _gfile)
def _keyboard_close_tab(self):
self.action_controller("close_tab")
def _keyboard_move_tab_right(self):
self.action_controller("keyboard_move_tab_right")
def _keyboard_move_tab_left(self):
self.action_controller("keyboard_move_tab_left")
def _keyboard_move_tab_to_1(self):
self.action_controller("keyboard_move_tab_to_1")
def _keyboard_move_tab_to_2(self):
self.action_controller("keyboard_move_tab_to_2")
def _keyboard_prev_tab(self):
self.action_controller("keyboard_prev_tab")
def _keyboard_next_tab(self):
self.action_controller("keyboard_next_tab")
# NOTE: These feel bad being here man...
def _keyboard_undo(self):
self.action_controller("keyboard_undo")
def _keyboard_redo(self):
self.action_controller("keyboard_redo")
def _toggle_highlight_line(self):
self.action_controller("toggle_highlight_line")
def _keyboard_insert_mark(self):
self.action_controller("keyboard_insert_mark")
def _keyboard_move_lines_up(self):
self.action_controller("keyboard_move_lines_up")
def _keyboard_move_lines_down(self):
self.action_controller("keyboard_move_lines_down")
def _keyboard_clear_marks(self):
self.action_controller("keyboard_clear_marks")
def _keyboard_scale_up_text(self): def _keyboard_scale_up_text(self):
self.action_controller("scale_up_text") self.action_controller("scale_up_text")
def _keyboard_scale_down_text(self): def _keyboard_scale_down_text(self):
self.action_controller("scale_down_text") self.action_controller("scale_down_text")
def _keyboard_save_file(self):
self.action_controller("save_file")
def _keyboard_save_file_as(self):
self.action_controller("save_file_as")

View File

@ -0,0 +1,68 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
# Application imports
class KeyInputController:
def _key_press_event(self, widget, eve):
keyname = Gdk.keyval_name(eve.keyval)
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
try:
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
except Exception:
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
def _key_release_event(self, widget, eve):
keyname = Gdk.keyval_name(eve.keyval)
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
try:
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
except Exception:
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
page_num, container, source_view = self.get_active_view()
if is_control:
if is_shift:
if keyname in ["Up", "Down"]:
if keyname == "Up":
self.keyboard_move_tab_to_1(page_num)
if keyname == "Down":
self.keyboard_move_tab_to_2(page_num)
return True
if keyname in ["w", "t", "o"]:
if keyname == "w":
self.close_tab(None, container, source_view)
if keyname == "t":
self._create_view()
if keyname == "o":
event_system.emit("open_files")
return True
if is_alt:
if keyname in ["Up", "Down", "Left", "Right"]:
if keyname == "Up":
self.keyboard_prev_tab(page_num)
if keyname == "Down":
self.keyboard_next_tab(page_num)
if keyname == "Left":
self.keyboard_move_tab_left(page_num)
if keyname == "Right":
self.keyboard_move_tab_right(page_num)
return True

View File

@ -1,23 +0,0 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
# NOTE: GtkSource 5 allows for smart indent action by allowing us to override the default auto indent logic...
# In the long run this will be better because we can check not only for :, ;, { or other things but apply per language such as bash where
# there isn't a special char but words...
# class AutoIndenter(GtkSource.Indenter):
# def __init__(self):
# ...
#
# def indent(self, view, iter):
# ...
#
# def is_trigger(self, view, iter, modifier, keyval):
# print(iter.get_char())

View File

@ -27,14 +27,10 @@ class KeyInputController:
if is_control: if is_control:
if is_shift: if is_shift:
if keyname in [ "z", "Up", "Down", "Left", "Right" ]: if keyname in [ "Up", "Down" ]:
# NOTE: For now do like so for completion sake above.
if keyname in ["Left", "Right"]:
return False
return True return True
if keyname in [ "slash", "Up", "Down", "z" ]: if keyname in [ "slash", "Up", "Down", "m", "z", "y" ]:
return True return True
if is_alt: if is_alt:
@ -56,6 +52,8 @@ class KeyInputController:
# NOTE: if a plugin recieves the call and handles, it will be the final decider for propigation # NOTE: if a plugin recieves the call and handles, it will be the final decider for propigation
return event_system.emit_and_await("autopairs", (keyname, is_control, is_alt, is_shift)) return event_system.emit_and_await("autopairs", (keyname, is_control, is_alt, is_shift))
def _key_release_event(self, widget, eve): def _key_release_event(self, widget, eve):
if self.freeze_multi_line_insert: return if self.freeze_multi_line_insert: return
@ -65,6 +63,57 @@ class KeyInputController:
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
buffer = self.get_buffer() buffer = self.get_buffer()
try:
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
except Exception:
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
can_continue = self.can_proceed(keyname, is_control, is_shift, is_alt)
if not can_continue:
return can_continue
if is_control:
if is_shift:
if keyname in ["S"]:
if keyname == "S":
self.save_file_as()
return True
if keyname in ["z", "y", "m", "s", "h", "equal", "minus", "Up", "Down"]:
if keyname == "z":
self.keyboard_undo()
if keyname == "y":
self.keyboard_redo()
if keyname == "m":
self.keyboard_insert_mark()
if keyname == "s":
self.save_file()
if keyname == "h":
self.toggle_highlight_line()
if keyname == "equal":
self.scale_up_text()
if keyname == "minus":
self.scale_down_text()
if keyname == "Up":
self.keyboard_move_lines_up()
if keyname == "Down":
self.keyboard_move_lines_down()
return True
# Note: Sink these requets
if keyname in ["Slash"]:
return True
if is_alt:
if keyname == "m":
self.keyboard_clear_marks()
if keyname in {"Return", "Enter"}: if keyname in {"Return", "Enter"}:
if len(self._multi_insert_marks) > 0: if len(self._multi_insert_marks) > 0:
self.begin_user_action(buffer) self.begin_user_action(buffer)
@ -76,3 +125,19 @@ class KeyInputController:
has_selection = buffer.get_has_selection() has_selection = buffer.get_has_selection()
if not has_selection: if not has_selection:
return self.insert_indent_handler(buffer) return self.insert_indent_handler(buffer)
def can_proceed(self, keyname, is_control, is_shift, is_alt):
if is_control:
if is_shift:
if keyname in ["Up", "Down"]:
return False
if keyname in ["w", "t", "o"]:
return False
if is_alt:
if keyname in ["Up", "Down", "Left", "Right"]:
return False
return True

View File

@ -0,0 +1,3 @@
"""
SourceView Mixins Module
"""

View File

@ -130,3 +130,34 @@ class FileEventsMixin:
buffer.set_modified(False) buffer.set_modified(False)
return gfile return gfile
def _document_loaded(self, line: int = 0):
for provider in self._completion.get_providers():
self._completion.remove_provider(provider)
file = self._current_file.get_path()
buffer = self.get_buffer()
word_completion = GtkSource.CompletionWords.new("word_completion")
word_completion.register(buffer)
self._completion.add_provider(word_completion)
# TODO: actually load a meaningful provider based on file type...
# example_completion_provider = ExampleCompletionProvider()
# self._completion.add_provider(example_completion_provider)
# py_completion_provider = PythonCompletionProvider(file)
# self._completion.add_provider(py_completion_provider)
self.got_to_line(buffer, line)

View File

@ -12,15 +12,14 @@ from gi.repository import Gio
from gi.repository import GtkSource from gi.repository import GtkSource
# Application imports # Application imports
# from .auto_indenter import AutoIndenter from .source_view_controller import SourceViewControllerMixin
from .key_input_controller import KeyInputController
from .source_view_events import SourceViewEventsMixin
from .custom_completion_providers.example_completion_provider import ExampleCompletionProvider from .custom_completion_providers.example_completion_provider import ExampleCompletionProvider
from .custom_completion_providers.python_completion_provider import PythonCompletionProvider from .custom_completion_providers.python_completion_provider import PythonCompletionProvider
class SourceView(KeyInputController, SourceViewEventsMixin, GtkSource.View): class SourceView(SourceViewControllerMixin, GtkSource.View):
def __init__(self): def __init__(self):
super(SourceView, self).__init__() super(SourceView, self).__init__()
@ -46,7 +45,6 @@ class SourceView(KeyInputController, SourceViewEventsMixin, GtkSource.View):
self._setup_styling() self._setup_styling()
self._setup_signals() self._setup_signals()
self._set_up_dnd()
self._subscribe_to_events() self._subscribe_to_events()
self._load_widgets() self._load_widgets()
@ -99,109 +97,4 @@ class SourceView(KeyInputController, SourceViewEventsMixin, GtkSource.View):
... ...
def _load_widgets(self): def _load_widgets(self):
... self._set_up_dnd()
def _document_loaded(self, line: int = 0):
for provider in self._completion.get_providers():
self._completion.remove_provider(provider)
file = self._current_file.get_path()
buffer = self.get_buffer()
word_completion = GtkSource.CompletionWords.new("word_completion")
word_completion.register(buffer)
self._completion.add_provider(word_completion)
# TODO: actually load a meaningful provider based on file type...
# example_completion_provider = ExampleCompletionProvider()
# self._completion.add_provider(example_completion_provider)
# py_completion_provider = PythonCompletionProvider(file)
# self._completion.add_provider(py_completion_provider)
self.got_to_line(buffer, line)
def _create_default_tag(self, buffer):
general_style_tag = buffer.create_tag('general_style')
general_style_tag.set_property('size', 100)
general_style_tag.set_property('scale', 100)
def _is_modified(self, *args):
buffer = self.get_buffer()
if not self._loading_file:
event_system.emit("buffer_changed", (buffer, ))
else:
event_system.emit("buffer_changed_first_load", (buffer, ))
self.update_cursor_position(buffer)
def _insert_text(self, buffer, location_itr, text_str, len_int):
if self.freeze_multi_line_insert: return
self.begin_user_action(buffer)
with buffer.freeze_notify():
GLib.idle_add(self._update_multi_line_markers, *(buffer, text_str,))
def _buffer_modified_changed(self, buffer):
tab_widget = self.get_parent().get_tab_widget()
tab_widget.set_status(changed = True if buffer.get_modified() else False)
def _button_press_event(self, widget = None, eve = None, user_data = None):
if eve.type == Gdk.EventType.BUTTON_PRESS and eve.button == 1 : # l-click
if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.button_press_insert_mark(eve)
return True
else:
self.keyboard_clear_marks()
elif eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3: # r-click
...
def _scroll_event(self, widget, eve):
accel_mask = Gtk.accelerator_get_default_mod_mask()
x, y, z = eve.get_scroll_deltas()
if eve.state & accel_mask == Gdk.ModifierType.CONTROL_MASK:
buffer = self.get_buffer()
if z > 0:
self.scale_down_text(buffer)
else:
self.scale_up_text(buffer)
return True
if eve.state & accel_mask == Gdk.ModifierType.SHIFT_MASK:
adjustment = self.get_hadjustment()
current_val = adjustment.get_value()
step_val = adjustment.get_step_increment()
if z > 0: # NOTE: scroll left
adjustment.set_value(current_val - step_val * 2)
else: # NOTE: scroll right
adjustment.set_value(current_val + step_val * 2)
return True
def _focus_in_event(self, widget, eve = None):
event_system.emit("set_active_src_view", (self,))
self.get_parent().get_parent().is_editor_focused = True
def _on_widget_focus(self, widget, eve = None):
tab_view = self.get_parent().get_parent()
path = self._current_file if self._current_file else ""
event_system.emit('focused_target_changed', (tab_view.NAME,))
event_system.emit("set_path_label", (path,))
event_system.emit("set_encoding_label")
event_system.emit("set_file_type_label", (self._current_filetype,))
return False
def _on_cursor_move(self, buffer, cursor_iter, mark, user_data = None):
if mark != buffer.get_insert(): return
self.update_cursor_position(buffer)
# NOTE: Not sure but this might not be efficient if the map reloads the same view...
event_system.emit(f"set_source_view", (self,))

View File

@ -0,0 +1,129 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .key_input_controller import KeyInputController
from .source_view_events import SourceViewEvents
class SourceViewControllerMixin(KeyInputController, SourceViewEvents):
def get_current_filepath(self):
return self._current_file
def get_filetype(self):
return self._current_filetype
def set_buffer_language(self, buffer, language = "python3"):
buffer.set_language( self._language_manager.get_language(language) )
def set_buffer_style(self, buffer, style = settings.theming.syntax_theme):
buffer.set_style_scheme( self._style_scheme_manager.get_scheme(style) )
def update_cursor_position(self, buffer = None):
buffer = self.get_buffer() if not buffer else buffer
iter = buffer.get_iter_at_mark( buffer.get_insert() )
chars = iter.get_offset()
row = iter.get_line() + 1
col = self.get_visual_column(iter) + 1
event_system.emit("set_line_char_label", (f"{row}:{col}",))
def update_labels(self, gfile = None):
if not gfile: return
tab_widget = self.get_parent().get_tab_widget()
tab_widget.set_tab_label(self._current_filename)
self.set_bottom_labels(gfile)
def set_bottom_labels(self, gfile = None):
if not gfile: return
event_system.emit("set_bottom_labels", (gfile, None, self._current_filetype, None))
self.update_cursor_position()
def got_to_line(self, buffer = None, line: int = 0):
buffer = self.get_buffer() if not buffer else buffer
line_itr = buffer.get_iter_at_line(line)
char_iter = buffer.get_iter_at_line_offset(line, line_itr.get_bytes_in_line())
buffer.place_cursor(char_iter)
if not buffer.get_mark("starting_cursor"):
buffer.create_mark("starting_cursor", char_iter, True)
self.scroll_to_mark( buffer.get_mark("starting_cursor"), 0.0, True, 0.0, 0.0 )
def toggle_highlight_line(self, widget = None, eve = None):
self.set_highlight_current_line( not self.get_highlight_current_line() )
def scale_up_text(self, buffer = None, scale_step = 10):
if not buffer:
buffer = self.get_buffer()
ctx = self.get_style_context()
if self._px_value < 99:
self._px_value += 1
ctx.add_class(f"px{self._px_value}")
# NOTE: Hope to bring this or similar back after we decouple scaling issues coupled with the miniview.
# tag_table = buffer.get_tag_table()
# start_itr = buffer.get_start_iter()
# end_itr = buffer.get_end_iter()
# tag = tag_table.lookup('general_style')
#
# tag.set_property('scale', tag.get_property('scale') + scale_step)
# buffer.apply_tag(tag, start_itr, end_itr)
def scale_down_text(self, buffer = None, scale_step = 10):
if not buffer:
buffer = self.get_buffer()
ctx = self.get_style_context()
if self._px_value > 1:
ctx.remove_class(f"px{self._px_value}")
self._px_value -= 1
ctx.add_class(f"px{self._px_value}")
# NOTE: Hope to bring this or similar back after we decouple scaling issues coupled with the miniview.
# tag_table = buffer.get_tag_table()
# start_itr = buffer.get_start_iter()
# end_itr = buffer.get_end_iter()
# tag = tag_table.lookup('general_style')
#
# tag.set_property('scale', tag.get_property('scale') - scale_step)
# buffer.apply_tag(tag, start_itr, end_itr)
def keyboard_undo(self):
buffer = self.get_buffer()
buffer.undo()
def keyboard_redo(self):
buffer = self.get_buffer()
buffer.redo()
def keyboard_move_lines_up(self):
buffer = self.get_buffer()
self.begin_user_action(buffer)
self.emit("move-lines", *(False,))
# unindent_lines
# self.emit("move-words", *(self, 4,))
self.end_user_action(buffer)
def keyboard_move_lines_down(self):
buffer = self.get_buffer()
self.begin_user_action(buffer)
self.emit("move-lines", *(True,))
# self.emit("move-words", *(self, -4,))
self.end_user_action(buffer)

View File

@ -3,121 +3,98 @@
# Lib imports # Lib imports
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib
# Application imports # Application imports
from .source_view_dnd_mixin import SourceViewDnDMixin from .mixins.source_view_dnd_mixin import SourceViewDnDMixin
from .source_file_events_mixin import FileEventsMixin from .mixins.source_file_events_mixin import FileEventsMixin
from .source_mark_events_mixin import MarkEventsMixin from .mixins.source_mark_events_mixin import MarkEventsMixin
class SourceViewEvents(SourceViewDnDMixin, MarkEventsMixin, FileEventsMixin):
def _create_default_tag(self, buffer):
general_style_tag = buffer.create_tag('general_style')
general_style_tag.set_property('size', 100)
general_style_tag.set_property('scale', 100)
class SourceViewEventsMixin(SourceViewDnDMixin, MarkEventsMixin, FileEventsMixin): def _is_modified(self, *args):
def get_current_filepath(self):
return self._current_file
def get_filetype(self):
return self._current_filetype
def set_buffer_language(self, buffer, language = "python3"):
buffer.set_language( self._language_manager.get_language(language) )
def set_buffer_style(self, buffer, style = settings.theming.syntax_theme):
buffer.set_style_scheme( self._style_scheme_manager.get_scheme(style) )
def toggle_highlight_line(self, widget = None, eve = None):
self.set_highlight_current_line( not self.get_highlight_current_line() )
def scale_up_text(self, buffer, scale_step = 10):
ctx = self.get_style_context()
if self._px_value < 99:
self._px_value += 1
ctx.add_class(f"px{self._px_value}")
# NOTE: Hope to bring this or similar back after we decouple scaling issues coupled with the miniview.
# tag_table = buffer.get_tag_table()
# start_itr = buffer.get_start_iter()
# end_itr = buffer.get_end_iter()
# tag = tag_table.lookup('general_style')
#
# tag.set_property('scale', tag.get_property('scale') + scale_step)
# buffer.apply_tag(tag, start_itr, end_itr)
def scale_down_text(self, buffer, scale_step = 10):
ctx = self.get_style_context()
if self._px_value > 1:
ctx.remove_class(f"px{self._px_value}")
self._px_value -= 1
ctx.add_class(f"px{self._px_value}")
# NOTE: Hope to bring this or similar back after we decouple scaling issues coupled with the miniview.
# tag_table = buffer.get_tag_table()
# start_itr = buffer.get_start_iter()
# end_itr = buffer.get_end_iter()
# tag = tag_table.lookup('general_style')
#
# tag.set_property('scale', tag.get_property('scale') - scale_step)
# buffer.apply_tag(tag, start_itr, end_itr)
def update_cursor_position(self, buffer = None):
buffer = self.get_buffer() if not buffer else buffer
iter = buffer.get_iter_at_mark( buffer.get_insert() )
chars = iter.get_offset()
row = iter.get_line() + 1
col = self.get_visual_column(iter) + 1
event_system.emit("set_line_char_label", (f"{row}:{col}",))
def got_to_line(self, buffer = None, line: int = 0):
buffer = self.get_buffer() if not buffer else buffer
line_itr = buffer.get_iter_at_line(line)
char_iter = buffer.get_iter_at_line_offset(line, line_itr.get_bytes_in_line())
buffer.place_cursor(char_iter)
if not buffer.get_mark("starting_cursor"):
buffer.create_mark("starting_cursor", char_iter, True)
self.scroll_to_mark( buffer.get_mark("starting_cursor"), 0.0, True, 0.0, 0.0 )
def keyboard_undo(self):
buffer = self.get_buffer() buffer = self.get_buffer()
buffer.undo()
def keyboard_redo(self): if not self._loading_file:
buffer = self.get_buffer() event_system.emit("buffer_changed", (buffer, ))
buffer.redo() else:
event_system.emit("buffer_changed_first_load", (buffer, ))
def keyboard_move_lines_up(self): self.update_cursor_position(buffer)
buffer = self.get_buffer()
def _insert_text(self, buffer, location_itr, text_str, len_int):
if self.freeze_multi_line_insert: return
self.begin_user_action(buffer) self.begin_user_action(buffer)
with buffer.freeze_notify():
GLib.idle_add(self._update_multi_line_markers, *(buffer, text_str,))
self.emit("move-lines", *(False,)) def _buffer_modified_changed(self, buffer):
# unindent_lines
# self.emit("move-words", *(self, 4,))
self.end_user_action(buffer)
def keyboard_move_lines_down(self):
buffer = self.get_buffer()
self.begin_user_action(buffer)
self.emit("move-lines", *(True,))
# self.emit("move-words", *(self, -4,))
self.end_user_action(buffer)
def update_labels(self, gfile = None):
if not gfile: return
tab_widget = self.get_parent().get_tab_widget() tab_widget = self.get_parent().get_tab_widget()
tab_widget.set_tab_label(self._current_filename) tab_widget.set_status(changed = True if buffer.get_modified() else False)
self.set_bottom_labels(gfile)
def set_bottom_labels(self, gfile = None):
if not gfile: return
event_system.emit("set_bottom_labels", (gfile, None, self._current_filetype, None)) def _button_press_event(self, widget = None, eve = None, user_data = None):
self.update_cursor_position() if eve.type == Gdk.EventType.BUTTON_PRESS and eve.button == 1 : # l-click
if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.button_press_insert_mark(eve)
return True
else:
self.keyboard_clear_marks()
elif eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3: # r-click
...
def _scroll_event(self, widget, eve):
accel_mask = Gtk.accelerator_get_default_mod_mask()
x, y, z = eve.get_scroll_deltas()
if eve.state & accel_mask == Gdk.ModifierType.CONTROL_MASK:
buffer = self.get_buffer()
if z > 0:
self.scale_down_text(buffer)
else:
self.scale_up_text(buffer)
return True
if eve.state & accel_mask == Gdk.ModifierType.SHIFT_MASK:
adjustment = self.get_hadjustment()
current_val = adjustment.get_value()
step_val = adjustment.get_step_increment()
if z > 0: # NOTE: scroll left
adjustment.set_value(current_val - step_val * 2)
else: # NOTE: scroll right
adjustment.set_value(current_val + step_val * 2)
return True
def _focus_in_event(self, widget, eve = None):
event_system.emit("set_active_src_view", (self,))
self.get_parent().get_parent().is_editor_focused = True
def _on_widget_focus(self, widget, eve = None):
tab_view = self.get_parent().get_parent()
path = self._current_file if self._current_file else ""
event_system.emit('focused_target_changed', (tab_view.NAME,))
event_system.emit("set_path_label", (path,))
event_system.emit("set_encoding_label")
event_system.emit("set_file_type_label", (self._current_filetype,))
return False
def _on_cursor_move(self, buffer, cursor_iter, mark, user_data = None):
if mark != buffer.get_insert(): return
self.update_cursor_position(buffer)
# NOTE: Not sure but this might not be efficient if the map reloads the same view...
event_system.emit(f"set_source_view", (self,))