Compare commits

...

11 Commits

123 changed files with 1694 additions and 1229 deletions

View File

@@ -1,13 +1,9 @@
{
"manifest": {
"name": "Example Plugin",
"author": "John Doe",
"version": "0.0.1",
"support": "",
"requests": {
"ui_target": "plugin_control_list",
"pass_events": true,
"bind_keys": ["Example Plugin||send_message:<Control>f"]
}
"name": "Example Plugin",
"author": "John Doe",
"version": "0.0.1",
"support": "",
"requests": {
"bind_keys": ["Example Plugin||send_message:<Control>f"]
}
}

View File

@@ -1,8 +1,4 @@
# Python imports
import os
import threading
import subprocess
import time
# Lib imports
import gi
@@ -10,42 +6,36 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from libs.dto.base_event import BaseEvent
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 = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
# where self.name should not be needed for message comms
super(Plugin, self).__init__()
def generate_reference_ui_element(self):
button = Gtk.Button(label=self.name)
button.connect("button-release-event", self.send_message)
return button
def _controller_message(self, event: BaseEvent):
...
def load(self):
ui_element = self.requests_ui_element("plugin_control_list")
ui_element.add( self.generate_plugin_element() )
def run(self):
...
def generate_plugin_element(self):
button = Gtk.Button(label = self.name)
def send_message(self, widget=None, eve=None):
button.connect("button-release-event", self.send_message)
button.show()
return button
def send_message(self, widget = None, eve = None):
message = "Hello, World!"
event_system.emit("display_message", ("warning", message, None))
self.emit("display_message", ("warning", message, None))

View File

@@ -9,10 +9,10 @@ import sys
# Application imports
# from libs.db import DB
from libs.event_system import EventSystem
from libs.endpoint_registry import EndpointRegistry
from libs.keybindings import Keybindings
from libs.logger import Logger
from libs.settings.manager import SettingsManager
from libs.widget_registery import WidgetRegisteryController
@@ -34,12 +34,8 @@ def daemon_threaded_wrapper(fn):
def call_chain_wrapper(fn):
def wrapper(*args, **kwargs):
print()
print()
for line in traceback.format_stack():
print( line.strip() )
print()
print()
return fn(*args, **kwargs)
return wrapper
@@ -51,8 +47,8 @@ builtins.APP_NAME = "<change_me>"
builtins.keybindings = Keybindings()
builtins.event_system = EventSystem()
builtins.endpoint_registry = EndpointRegistry()
builtins.settings_manager = SettingsManager()
builtins.widget_registery = WidgetRegisteryController()
# builtins.db = DB()
settings_manager.load_settings()

View File

@@ -1,33 +0,0 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
class BuilderWrapper(Gtk.Builder):
"""docstring for BuilderWrapper."""
def __init__(self):
super(BuilderWrapper, self).__init__()
self.objects = {}
def get_object(self, id: str, use_gtk: bool = True) -> any:
if not use_gtk:
return self.objects[id]
return super(BuilderWrapper, self).get_object(id)
def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None:
if not use_gtk:
self.objects[id] = object
else:
super(BuilderWrapper, self).expose_object(id, object)
def dereference_object(self, id: str) -> None:
del self.objects[id]

View File

@@ -14,7 +14,6 @@ class CenterContainer(Gtk.Box):
def __init__(self):
super(CenterContainer, self).__init__()
self._builder = settings_manager.get_builder()
self._setup_styling()
self._setup_signals()
@@ -39,7 +38,7 @@ class CenterContainer(Gtk.Box):
...
def _load_widgets(self):
glade_box = self._builder.get_object("glade_box")
glade_box = widget_registery.get_object("glade_box")
button = Gtk.Button(label = "Click Me!")
button.connect("clicked", self._hello_world)

View File

@@ -6,33 +6,48 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from plugins import plugins_controller
from libs.mixins.ipc_signals_mixin import IPCSignalsMixin
from libs.mixins.keyboard_signals_mixin import KeyboardSignalsMixin
from ..containers.base_container import BaseContainer
from .base_controller_data import BaseControllerData
from .base_controller_mixin import BaseControllerMixin
from .bridge_controller import BridgeController
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerMixin):
""" docstring for BaseController. """
def __init__(self):
self._setup_controller_data()
self._load_plugins(is_pre = True)
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_controllers()
self._load_plugins_and_files()
self._load_plugins(is_pre = False)
self._load_files()
logger.info(f"Made it past {self.__class__} loading...")
settings_manager.set_end_load_time()
settings_manager.log_load_time()
def _setup_controller_data(self):
self.window = settings_manager.get_main_window()
self.base_container = BaseContainer()
self.plugins_controller = plugins_controller
widget_registery.expose_object("main_window", self.window)
settings_manager.register_signals_to_builder([self, self.base_container])
self._collect_files_dirs()
def _setup_styling(self):
...
@@ -50,23 +65,22 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
def _load_controllers(self):
BridgeController()
def _load_plugins_and_files(self):
def _load_plugins(self, is_pre: bool):
args, unknownargs = settings_manager.get_starting_args()
if args.no_plugins == "false":
self.plugins_controller.pre_launch_plugins()
self.plugins_controller.post_launch_plugins()
if args.no_plugins == "true": return
if is_pre:
self.plugins_controller.pre_launch_plugins()
return
if not is_pre:
self.plugins_controller.post_launch_plugins()
return
def _load_files(self):
for file in settings_manager.get_starting_files():
event_system.emit("post-file-to-ipc", file)
def _tggl_top_main_menubar(self):
logger.debug("_tggl_top_main_menubar > stub...")
def _load_glade_file(self):
self.builder.add_from_file( settings_manager.path_manager.get_glade_file() )
self.builder.expose_object("main_window", self.window)
settings_manager.set_builder(self.builder)
self.base_container = BaseContainer()
settings_manager.register_signals_to_builder([self, self.base_container])

View File

@@ -6,28 +6,11 @@ from shutil import which
# Lib imports
# Application imports
from plugins.plugins_controller import PluginsController
from ..builder_wrapper import BuilderWrapper
class BaseControllerData:
''' BaseControllerData contains most of the state of the app at ay given time. It also has some support methods. '''
def _setup_controller_data(self) -> None:
self.window = settings_manager.get_main_window()
self.builder = BuilderWrapper()
self.plugins_controller = PluginsController()
self.base_container = None
self.was_midified_key = False
self.ctrl_down = False
self.shift_down = False
self.alt_down = False
self._collect_files_dirs()
self._load_glade_file()
class BaseControllerMixin:
''' BaseControllerMixin contains most of the state of the app at ay given time. It also has some support methods. '''
def _collect_files_dirs(self):
args, \

View File

@@ -3,12 +3,15 @@
# Lib imports
# Application imports
from .controllers.controller_manager import ControllerManager
from plugins import plugins_controller
from libs.controllers.controller_manager import ControllerManager
from .controllers.files_controller import FilesController
from .controllers.tabs_controller import TabsController
from .controllers.commands_controller import CommandsController
from .controllers.completion_controller import CompletionController
from .controllers.source_views_controller import SourceViewsController
from .controllers.views.source_views_controller import SourceViewsController
from .mini_view_widget import MiniViewWidget
@@ -31,11 +34,14 @@ class CodeBase:
completion_controller = CompletionController()
source_views_controller = SourceViewsController()
# self.controller_manager.register_controller("base", self)
self.controller_manager.register_controller("files", files_controller)
self.controller_manager.register_controller("tabs", tabs_controller)
self.controller_manager.register_controller("commands", commands_controller)
self.controller_manager.register_controller("completion", completion_controller)
self.controller_manager.register_controller("source_views", source_views_controller)
self.controller_manager.register_controller("plugins", plugins_controller)
self.controller_manager.register_controller("widgets", widget_registery)
def get_tabs_widget(self):
return self.controller_manager["tabs"].get_tabs_widget()
@@ -44,7 +50,12 @@ class CodeBase:
return self.miniview_widget
def create_source_view(self):
return self.controller_manager["source_views"].create_source_view()
source_view = self.controller_manager["source_views"].create_source_view()
self.controller_manager["completion"].register_completer(
source_view.get_completion()
)
return source_view
def first_map_load(self):
self.controller_manager["source_views"].first_map_load()

View File

@@ -0,0 +1,5 @@
"""
Code Command System Package
"""
from .command_system import CommandSystem

View File

@@ -9,7 +9,7 @@ from gi.repository import GtkSource
def set_language_and_style(view, file):
language = view.language_manager.guess_language(file.fname, None)
file.ftype = language
file.ftype = "buffer" if not language else language
file.buffer.set_language(language)
file.buffer.set_style_scheme(view.syntax_theme)

View File

@@ -3,13 +3,12 @@
# Lib imports
# Application imports
from libs.dto.code import CodeEvent
from .event_factory import Event_Factory, Event_Factory_Types
from libs.event_factory import Event_Factory, Code_Event_Types
from ..source_view import SourceView
from . import commands
from .source_view import SourceView
class CommandSystem:
@@ -39,17 +38,18 @@ class CommandSystem:
return method.execute(*args)
def emit(self, event: CodeEvent):
""" Monky patch 'emit' from command controller... """
def emit(self, event: Code_Event_Types.CodeEvent):
""" Monkey patch 'emit' from command controller... """
...
def emit_to(self, controller: str, event: CodeEvent):
""" Monky patch 'emit' from command controller... """
def emit_to(self, controller: str, event: Code_Event_Types.CodeEvent):
""" Monkey patch 'emit_to' from command controller... """
...
def get_file(self, view: SourceView):
event = Event_Factory.create_get_file(
event = Event_Factory.create_event(
"get_file",
view = view,
buffer = view.get_buffer()
)
@@ -59,7 +59,8 @@ class CommandSystem:
return event.response
def get_swap_file(self, view: SourceView):
event = Event_Factory.create_get_swap_file(
event = Event_Factory.create_event(
"get_swap_file",
view = view,
buffer = view.get_buffer()
)
@@ -76,7 +77,8 @@ class CommandSystem:
return event.response
def remove_file(self, view: SourceView):
event = Event_Factory.create_remove_file(
event = Event_Factory.create_event(
"removed_file",
view = view,
buffer = view.get_buffer()
)

View File

@@ -1,5 +1,5 @@
"""
Commands Package
Code Commands Package
"""
import pkgutil

View File

@@ -9,7 +9,6 @@ from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from ..source_file import SourceFile

View File

@@ -9,7 +9,7 @@ from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from ..source_file import SourceFile
from ...source_file import SourceFile
from ..command_helpers import set_language_and_style

View File

@@ -18,7 +18,7 @@ def execute(
):
logger.debug("Command: New File")
file = view.command.new_file(view)
file = view.command.new_file(view)
set_language_and_style(view, file)
view.set_buffer(file.buffer)

View File

@@ -9,7 +9,7 @@ gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
from ..source_file import SourceFile
from ...source_file import SourceFile
from ..command_helpers import update_info_bar_if_focused

View File

@@ -6,12 +6,8 @@ import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from libs.dto.code import FocusedViewEvent
from ..source_file import SourceFile

View File

@@ -0,0 +1,28 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
view: GtkSource.View = None
):
logger.debug("Command: Show Completion")
completer = view.get_completion()
providers = completer.get_providers()
if not providers:
view.command.request_completion(view)
return
completer.start(
providers,
completer.create_context()
)

View File

@@ -6,10 +6,8 @@ import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from ..source_file import SourceFile

View File

@@ -1,18 +0,0 @@
# Python imports
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
def execute(
view: GtkSource.View = None
):
logger.debug("Command: Show Completion")
view.command.request_completion(view)

View File

@@ -1,3 +1,3 @@
"""
Custom Completion Providers Module
Code Completion Providers Package
"""

View File

@@ -1,84 +0,0 @@
# Python imports
import re
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
# Application imports
class ExampleCompletionProvider(GObject.GObject, GtkSource.CompletionProvider):
"""
This is a custom Completion Example Provider.
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
"""
__gtype_name__ = 'ExampleCompletionProvider'
def __init__(self):
GObject.Object.__init__(self)
def do_get_name(self):
""" Returns: a new string containing the name of the provider. """
return 'Example Completion Provider'
def do_match(self, context):
""" Get whether the provider match the context of completion detailed in context. """
# NOTE: True for debugging but context needs to normally get checked for actual usage needs.
# TODO: Fix me
return True
def do_get_priority(self):
""" Determin position in result list along other providor results. """
return 1
# def do_get_activation(self):
# """ The context for when a provider will show results """
# return GtkSource.CompletionActivation.NONE
# return GtkSource.CompletionActivation.USER_REQUESTED
# return GtkSource.CompletionActivation.INTERACTIVE
def do_populate(self, context):
"""
In this instance, it will do 2 things:
1) always provide Hello World! (Not ideal but an option so its in the example)
2) Utilizes the Gtk.TextIter from the TextBuffer to determine if there is a jinja
example of '{{ custom.' if so it will provide you with the options of foo and bar.
If selected it will insert foo }} or bar }}, completing your syntax...
PLEASE NOTE the GtkTextIter Logic and regex are really rough and should be adjusted and tuned
"""
proposals = [
GtkSource.CompletionItem(label='Hello World!', text = 'Hello World!', icon = None, info = None) # NOTE: Always proposed...
]
# Gtk Versions differ on get_iter responses...
end_iter = context.get_iter()
if not isinstance(end_iter, Gtk.TextIter):
_, end_iter = context.get_iter()
if end_iter:
buf = end_iter.get_buffer()
mov_iter = end_iter.copy()
if mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY):
mov_iter, _ = mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY)
left_text = buf.get_text(mov_iter, end_iter, True)
else:
left_text = ''
if re.match(r'.*\{\{\s*custom\.$', left_text):
proposals.append(
GtkSource.CompletionItem(label='foo', text='foo }}') # optionally proposed based on left search via regex
)
proposals.append(
GtkSource.CompletionItem(label='bar', text='bar }}') # optionally proposed based on left search via regex
)
context.add_proposals(self, proposals, True)

View File

@@ -1,137 +0,0 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
# Application imports
class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
"""
This code is an LSP code completion plugin for Newton.
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
"""
__gtype_name__ = 'LSPProvider'
def __init__(self):
GObject.Object.__init__(self)
self._icon_theme = Gtk.IconTheme.get_default()
self.lsp_data = None
def pre_populate(self, context):
...
def do_get_name(self):
return "LSP Code Completion"
def get_iter_correctly(self, context):
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
def do_match(self, context):
iter = self.get_iter_correctly(context)
iter.backward_char()
buffer = iter.get_buffer()
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
return False
ch = iter.get_char()
# 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
def do_get_priority(self):
return 5
def do_populate(self, context, items = []):
# self.lsp_data
proposals = []
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label("LSP Class")
comp_item.set_text("LSP Code")
# comp_item.set_icon(self.get_icon_for_type(completion.type))
comp_item.set_info("A test LSP completion item...")
context.add_proposals(self, [comp_item], True)
# def do_populate(self, context, items = []):
# if hasattr(self._source_view, "completion_items"):
# items = self._source_view.completion_items
# proposals = []
# for item in items:
# proposals.append( self.create_completion_item(item) )
# context.add_proposals(self, proposals, True)
# def get_icon_for_type(self, _type):
# try:
# return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
# except:
# ...
# try:
# return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
# except:
# ...
# return None
# def create_completion_item(self, item):
# comp_item = GtkSource.CompletionItem.new()
# keys = item.keys()
# comp_item.set_label(item["label"])
# if "insertText" in keys:
# comp_item.set_text(item["insertText"])
# if "additionalTextEdits" in keys:
# comp_item.additionalTextEdits = item["additionalTextEdits"]
# return comp_item
# def create_completion_item(self, item):
# comp_item = GtkSource.CompletionItem.new()
# comp_item.set_label(item.label)
# if item.textEdit:
# if isinstance(item.textEdit, dict):
# comp_item.set_text(item.textEdit["newText"])
# else:
# comp_item.set_text(item.textEdit)
# else:
# comp_item.set_text(item.insertText)
# comp_item.set_icon( self.get_icon_for_type(item.kind) )
# comp_item.set_info(item.documentation)
# return comp_item

View File

@@ -0,0 +1,87 @@
# Python imports
import re
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import GtkSource
# Application imports
class ProviderResponseCacheException(Exception):
...
class ProviderResponseCacheBase:
def __init__(self):
super(ProviderResponseCacheBase, self).__init__()
self._icon_theme = Gtk.IconTheme.get_default()
def process_file_load(self, buffer: GtkSource.Buffer):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'process_file_load' not implemented...")
def process_file_close(self, buffer: GtkSource.Buffer):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'process_file_close' not implemented...")
def process_file_save(self, buffer: GtkSource.Buffer):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'process_file_save' not implemented...")
def process_file_change(self, buffer: GtkSource.Buffer):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'process_change' not implemented...")
def filter(self, word: str):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'filter' not implemented...")
def filter_with_context(self, context: GtkSource.CompletionContext):
raise ProviderResponseCacheException("ProviderResponseCacheBase 'filter_with_context' not implemented...")
def create_completion_item(
self,
label: str = "",
text: str = "",
info: str = "",
completion: any = None
):
if not label or not text: return
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label(label)
comp_item.set_text(text)
if info:
comp_item.set_info(info)
# comp_item.set_markup(f"<h3>{info}</h3>")
if completion:
comp_item.set_icon(
self.get_icon_for_type(completion.type)
)
return comp_item
def get_word(self, context):
start_iter = context.get_iter()
end_iter = None
if not isinstance(start_iter, Gtk.TextIter):
_, start_iter = context.get_iter()
end_iter = start_iter.copy()
if not start_iter.starts_word():
start_iter.backward_word_start()
end_iter.forward_word_end()
buffer = start_iter.get_buffer()
return buffer.get_text(start_iter, end_iter, False)

View File

@@ -1,107 +0,0 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GtkSource
from gi.repository import GObject
import jedi
from jedi.api import Script
# Application imports
# FIXME: Find real icon names...
icon_names = {
'import': '',
'module': '',
'class': '',
'function': '',
'statement': '',
'param': ''
}
class Jedi:
def get_script(file, doc_text):
return Script(code = doc_text, path = file)
class PythonCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
"""
This code is A python code completion plugin for Newton.
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
"""
__gtype_name__ = 'PythonProvider'
def __init__(self, file):
GObject.Object.__init__(self)
self._theme = Gtk.IconTheme.get_default()
self._file = file
def do_get_name(self):
return "Python Code Completion"
def get_iter_correctly(self, context):
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
def do_match(self, context):
iter = self.get_iter_correctly(context)
iter.backward_char()
buffer = iter.get_buffer()
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
return False
ch = iter.get_char()
# 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
def do_get_priority(self):
return 1
def do_get_activation(self):
return GtkSource.CompletionActivation.INTERACTIVE
def do_populate(self, context):
# TODO: Maybe convert async?
it = self.get_iter_correctly(context)
buffer = it.get_buffer()
proposals = []
doc_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
iter_cursor = buffer.get_iter_at_mark(buffer.get_insert())
linenum = iter_cursor.get_line() + 1
charnum = iter_cursor.get_line_index()
def create_generator():
for completion in Jedi.get_script(self._file, doc_text).complete(line = linenum, column = None, fuzzy = False):
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label(completion.name)
comp_item.set_text(completion.name)
comp_item.set_icon(self.get_icon_for_type(completion.type))
comp_item.set_info(completion.docstring())
yield comp_item
for item in create_generator():
proposals.append(item)
context.add_proposals(self, proposals, True)
def get_icon_for_type(self, _type):
try:
return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
except (KeyError, AttributeError, GObject.GError) as e:
return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
except (GObject.GError, AttributeError) as e:
return None

View File

@@ -1,3 +1,3 @@
"""
Controllers Package
"""
Code Controllers Package
"""

View File

@@ -3,16 +3,12 @@
# Lib imports
# Application imports
from libs.dto.code import (
CodeEvent,
GetCommandSystemEvent,
FocusedViewEvent
)
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Code_Event_Types
from ..command_system import CommandSystem
from .controller_base import ControllerBase
class CommandsController(ControllerBase, list):
@@ -20,8 +16,8 @@ class CommandsController(ControllerBase, list):
super(CommandsController, self).__init__()
def _controller_message(self, event: CodeEvent):
if isinstance(event, GetCommandSystemEvent):
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.GetCommandSystemEvent):
event.response = self.get_command_system()
def get_command_system(self):

View File

@@ -8,19 +8,8 @@ from gi.repository import GLib
from gi.repository import GtkSource
# Application imports
from libs.dto.code import (
CodeEvent,
FocusedViewEvent,
RequestCompletionEvent,
CursorMovedEvent,
TextChangedEvent,
TextInsertedEvent
)
from ..completion_providers.example_completion_provider import ExampleCompletionProvider
from ..completion_providers.lsp_completion_provider import LSPCompletionProvider
from .controller_base import ControllerBase
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Event_Factory, Code_Event_Types
@@ -28,84 +17,78 @@ class CompletionController(ControllerBase):
def __init__(self):
super(CompletionController, self).__init__()
self._completor: GtkSource.Completion = None
self._timeout_id: int = None
self._lsp_provider: LSPCompletionProvider = LSPCompletionProvider()
self.words_provider = GtkSource.CompletionWords.new("words", None)
self.words_provider.props.activation = GtkSource.CompletionActivation.INTERACTIVE
self._completers: list[GtkSource.Completion] = []
self._providers: dict[str, GtkSource.CompletionProvider] = {}
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.RegisterProviderEvent):
self.register_provider(
event.provider_name,
event.provider,
event.language_ids
)
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
self.provider_process_file_load(event)
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
self.provider_process_file_close(event)
elif isinstance(event, Code_Event_Types.SavedFileEvent):
self.provider_process_file_save(event)
elif isinstance(event, Code_Event_Types.TextChangedEvent):
self.provider_process_file_change(event)
# elif isinstance(event, Code_Event_Types.RequestCompletionEvent):
# self.request_unbound_completion( event.view.get_completion() )
def _controller_message(self, event: CodeEvent):
if isinstance(event, FocusedViewEvent):
self._completor = event.view.get_completion()
def register_completer(self, completer: GtkSource.Completion):
self._completers.append(completer)
if not self._timeout_id: return
GLib.source_remove(self._timeout_id)
self._timeout_id = None
elif isinstance(event, RequestCompletionEvent):
self.request_completion()
# elif isinstance(event, TextInsertedEvent):
# self.request_completion()
def _process_request_completion(self):
self._start_completion()
self._timeout_id = None
return False
def _do_completion(self):
if self._completor.get_providers():
self._match_completion()
else:
self._start_completion()
def _match_completion(self):
"""
Note: Use IF providers were added to completion...
"""
self._completion.match(
self._completion.create_context()
)
def _start_completion(self):
"""
Note: Use IF NO providers have been added to completion...
"""
self._completor.start(
[
ExampleCompletionProvider(),
self._lsp_provider
],
self._completor.create_context()
)
def set_completer(self, completer):
self._completor = completer
def request_completion(self):
if self._timeout_id:
GLib.source_remove(self._timeout_id)
self._timeout_id = GLib.timeout_add(
800,
self._process_request_completion
)
completer.add_provider(self.words_provider)
for provider in self._providers.values():
completer.add_provider(provider)
def register_provider(
self,
provider_name: str,
provider: GtkSource.CompletionProvider,
priority: int = 0,
language_ids: list = None
provider: GtkSource.CompletionProvider,
language_ids: list = []
):
"""Register completion providers with priority and language filtering"""
...
self._providers[provider_name] = provider
for completer in self._completers:
completer.add_provider(provider)
def unregister_provider(self, provider_name: str):
"""Remove completion providers"""
...
def get_active_providers(self, language_id: str = None) -> list:
"""Get providers filtered by language"""
...
provider = self._providers[provider_name]
del self._providers[provider_name]
for completer in self._completers:
completer.remove_provider(provider)
def provider_process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
self.words_provider.register(event.file.buffer)
for provider in self._providers.values():
provider.response_cache.process_file_load(event)
def provider_process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
self.words_provider.unregister(event.file.buffer)
for provider in self._providers.values():
provider.response_cache.process_file_close(event)
def provider_process_file_save(self, event: Code_Event_Types.SavedFileEvent):
for provider in self._providers.values():
provider.response_cache.process_file_save(event)
def provider_process_file_change(self, event: Code_Event_Types.TextChangedEvent):
for provider in self._providers.values():
provider.response_cache.process_file_change(event)
def request_unbound_completion(self, completer: GtkSource.Completion):
completer.start(
[ *self._providers.values() ],
completer.create_context()
)

View File

@@ -3,13 +3,12 @@
# Lib imports
# Application imports
from libs.dto.code import CodeEvent
from ..event_factory import Event_Factory, Event_Factory_Types
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Event_Factory, Code_Event_Types
from ..source_file import SourceFile
from ..source_buffer import SourceBuffer
from .controller_base import ControllerBase
@@ -18,21 +17,21 @@ class FilesController(ControllerBase, list):
super(FilesController, self).__init__()
def _controller_message(self, event: CodeEvent):
if isinstance(event, Event_Factory_Types.AddNewFileEvent):
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.AddNewFileEvent):
self.new_file(event)
elif isinstance(event, Event_Factory_Types.SwapFileEvent):
elif isinstance(event, Code_Event_Types.SwapFileEvent):
self.swap_file(event)
elif isinstance(event, Event_Factory_Types.PopFileEvent):
elif isinstance(event, Code_Event_Types.PopFileEvent):
self.pop_file(event)
elif isinstance(event, Event_Factory_Types.RemoveFileEvent):
elif isinstance(event, Code_Event_Types.RemoveFileEvent):
self.remove_file(event)
elif isinstance(event, Event_Factory_Types.GetFileEvent):
elif isinstance(event, Code_Event_Types.GetFileEvent):
self.get_file(event)
elif isinstance(event, Event_Factory_Types.GetSwapFileEvent):
elif isinstance(event, Code_Event_Types.GetSwapFileEvent):
self.get_swap_file(event)
def get_file(self, event: Event_Factory_Types.GetFileEvent):
def get_file(self, event: Code_Event_Types.GetFileEvent):
if not event.buffer: return
for file in self:
@@ -42,7 +41,7 @@ class FilesController(ControllerBase, list):
return file
def get_swap_file(self, event: Event_Factory_Types.GetSwapFileEvent):
def get_swap_file(self, event: Code_Event_Types.GetSwapFileEvent):
if not event.buffer: return
for i, file in enumerate(self):
@@ -56,7 +55,7 @@ class FilesController(ControllerBase, list):
return swapped_file, next_file
def new_file(self, event: Event_Factory_Types.AddNewFileEvent):
def new_file(self, event: Code_Event_Types.AddNewFileEvent):
file = SourceFile()
file.emit = self.emit
file.emit_to = self.emit_to
@@ -68,13 +67,13 @@ class FilesController(ControllerBase, list):
view = event.view,
file = file
)
self.message_all(eve)
self.message(eve)
self.append(file)
return file
def swap_file(self, event: Event_Factory_Types.GetSwapFileEvent):
def swap_file(self, event: Code_Event_Types.GetSwapFileEvent):
if not event.buffer: return
for i, file in enumerate(self):
@@ -88,7 +87,7 @@ class FilesController(ControllerBase, list):
return swapped_file, next_file
def pop_file(self, event: Event_Factory_Types.PopFileEvent):
def pop_file(self, event: Code_Event_Types.PopFileEvent):
if not event.buffer: return
for i, file in enumerate(self):
@@ -106,11 +105,11 @@ class FilesController(ControllerBase, list):
file = popped_file,
next_file = next_file
)
self.message_all(eve)
self.message(eve)
return popped_file, next_file
def remove_file(self, event: Event_Factory_Types.RemoveFileEvent):
def remove_file(self, event: Code_Event_Types.RemoveFileEvent):
if not event.buffer: return
for i, file in enumerate(self):
@@ -128,7 +127,7 @@ class FilesController(ControllerBase, list):
file = file,
next_file = next_file
)
self.message_all(eve)
self.message(eve)
self.remove(file)
file.close()

View File

@@ -1,128 +0,0 @@
# Python imports
# Lib imports
# Application imports
from ..event_factory import Event_Factory, Event_Factory_Types
from ..command_system import CommandSystem
from ..key_mapper import KeyMapper
from ..source_view import SourceView
from .controller_base import ControllerBase
class SourceViewsController(ControllerBase, list):
def __init__(self):
super(SourceViewsController, self).__init__()
self.key_mapper: KeyMapper = KeyMapper()
self.active_view: SourceView = None
def get_command_system(self):
event = Event_Factory.create_event("get_command_system")
self.message_to("commands", event)
command = event.response
del event
return command
def create_source_view(self):
source_view: SourceView = SourceView()
source_view.command = self.get_command_system()
source_view.command.set_data(source_view)
self._map_signals(source_view)
self.append(source_view)
return source_view
def _controller_message(self, event: Event_Factory_Types.CodeEvent):
if isinstance(event, Event_Factory_Types.RemovedFileEvent):
self._remove_file(event)
elif isinstance(event, Event_Factory_Types.TextChangedEvent):
self.active_view.command.exec("update_info_bar")
def _map_signals(self, source_view: SourceView):
source_view.connect("focus-in-event", self._focus_in_event)
source_view.connect("move-cursor", self._move_cursor)
source_view.connect("key-press-event", self._key_press_event)
source_view.connect("key-release-event", self._key_release_event)
source_view.connect("button-press-event", self._button_press_event)
source_view.connect("button-release-event", self._button_release_event)
def _focus_in_event(self, view, eve):
self.active_view = view
view.command.exec("set_miniview")
view.command.exec("set_focus_border")
view.command.exec("update_info_bar")
event = Event_Factory.create_focused_view(view = view)
self.emit(event)
def _move_cursor(self, view, step, count, extend_selection):
buffer = view.get_buffer()
iter = buffer.get_iter_at_mark( buffer.get_insert() )
line = iter.get_line()
char = iter.get_line_offset()
event = Event_Factory.create_cursor_moved(
view = view,
buffer = buffer,
line = line,
char = char
)
self.emit(event)
view.command.exec("update_info_bar")
def _button_press_event(self, view, eve):
self.active_view.command.exec("update_info_bar")
def _button_release_event(self, view, eve):
self.active_view.command.exec("update_info_bar")
def _key_press_event(self, view, eve):
command = self.key_mapper._key_press_event(eve)
is_future = self.key_mapper._key_release_event(eve)
if is_future: return True
if not command: return False
view.command.exec(command)
return True
def _key_release_event(self, view, eve):
command = self.key_mapper._key_release_event(eve)
is_past = self.key_mapper._key_press_event(eve)
if is_past: return True
if not command: return False
view.command.exec(command)
return True
def _remove_file(self, event: Event_Factory_Types.RemovedFileEvent):
for view in self:
if not event.file.buffer == view.get_buffer(): continue
if not event.next_file:
view.command.exec("new_file")
continue
view.set_buffer(event.next_file.buffer)
def first_map_load(self):
for view in self:
view.command.exec("new_file")
view = self[0]
view.grab_focus()
view.command.exec("load_start_files")

View File

@@ -3,16 +3,14 @@
# Lib imports
# Application imports
from libs.dto.code import CodeEvent
from ..event_factory import Event_Factory, Event_Factory_Types
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Event_Factory, Code_Event_Types
from ..tabs_widget import TabsWidget
from ..tab_widget import TabWidget
from ..source_view import SourceView
from .controller_base import ControllerBase
class TabsController(ControllerBase):
@@ -23,28 +21,28 @@ class TabsController(ControllerBase):
self.tabs_widget: TabsWidget = TabsWidget()
def _controller_message(self, event: CodeEvent):
if isinstance(event, Event_Factory_Types.FocusedViewEvent):
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.FocusedViewEvent):
self.active_view = event.view
elif isinstance(event, Event_Factory_Types.FilePathSetEvent):
elif isinstance(event, Code_Event_Types.FilePathSetEvent):
self.update_tab_label(event)
elif isinstance(event, Event_Factory_Types.AddedNewFileEvent):
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
self.add_tab(event)
elif isinstance(event, Event_Factory_Types.PoppedFileEvent):
elif isinstance(event, Code_Event_Types.PoppedFileEvent):
...
elif isinstance(event, Event_Factory_Types.RemovedFileEvent):
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
self.remove_tab(event)
def get_tabs_widget(self):
return self.tabs_widget
def update_tab_label(self, event: Event_Factory_Types.FilePathSetEvent):
def update_tab_label(self, event: Code_Event_Types.FilePathSetEvent):
for tab in self.tabs_widget.get_children():
if not event.file == tab.file: continue
tab.label.set_label(event.file.fname)
break
def add_tab(self, event: Event_Factory_Types.AddedNewFileEvent):
def add_tab(self, event: Code_Event_Types.AddedNewFileEvent):
def set_active_tab(tab, eve, file):
event = Event_Factory.create_event(
"set_active_file",
@@ -55,7 +53,7 @@ class TabsController(ControllerBase):
tab.get_parent().file.buffer
)
self.message_all(event)
self.message(event)
def close_tab(tab, eve, file):
event = Event_Factory.create_event(
@@ -63,7 +61,7 @@ class TabsController(ControllerBase):
buffer = tab.get_parent().file.buffer
)
self.message_all(event)
self.message(event)
tab = TabWidget()
tab.file = event.file
@@ -74,7 +72,7 @@ class TabsController(ControllerBase):
self.tabs_widget.add(tab)
tab.show()
def remove_tab(self, event: Event_Factory_Types.RemovedFileEvent):
def remove_tab(self, event: Code_Event_Types.RemovedFileEvent):
for tab in self.tabs_widget.get_children():
if not event.file == tab.file: continue

View File

@@ -0,0 +1,10 @@
"""
Code Controllers Package
"""
from .state_manager import SourceViewStateManager
from .signal_mapper import SourceViewSignalMapper
from .source_views_controller import SourceViewsController
# State imports
from .states import *

View File

@@ -0,0 +1,63 @@
# Python imports
# Lib imports
# Application imports
from ...source_view import SourceView
class SourceViewSignalMapper:
def __init__(self):
self.active_view: SourceView = None
def bind_emit(self, emit: callable):
self.emit = emit
def set_state_manager(self, state_manager):
self.state_manager = state_manager
def connect_signals(self, source_view: SourceView):
signal_mappings = self._get_signal_mappings()
for signal, handler in signal_mappings.items():
source_view.connect(signal, handler)
def disconnect_signals(self, source_view: SourceView):
signal_mappings = self._get_signal_mappings()
for signal, handler in signal_mappings.items():
source_view.disconnect_by_func(handler)
def insert_text(self, file, string: str):
return self.state_manager.handle_insert_text(self.active_view, file, string)
def _get_signal_mappings(self):
return {
"focus-in-event": self._focus_in_event,
"move-cursor": self._move_cursor,
"key-press-event": self._key_press_event,
"key-release-event": self._key_release_event,
"button-press-event": self._button_press_event,
"button-release-event": self._button_release_event
}
def _focus_in_event(self, source_view: SourceView, eve):
self.active_view = source_view
return self.state_manager.handle_focus_in_event(source_view, eve, self.emit)
def _move_cursor(self, source_view: SourceView, step, count, extend_selection):
return self.state_manager.handle_move_cursor(
source_view, step, count, extend_selection, self.emit
)
def _button_press_event(self, source_view: SourceView, eve):
return self.state_manager.handle_button_press_event(source_view, eve)
def _button_release_event(self, source_view: SourceView, eve):
return self.state_manager.handle_button_release_event(source_view, eve)
def _key_press_event(self, source_view: SourceView, eve):
return self.state_manager.handle_key_press_event(source_view, eve)
def _key_release_event(self, source_view: SourceView, eve):
return self.state_manager.handle_key_release_event(source_view, eve)

View File

@@ -0,0 +1,74 @@
# Python imports
# Lib imports
# Application imports
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Event_Factory, Code_Event_Types
from ...source_view import SourceView
from .state_manager import SourceViewStateManager
from .signal_mapper import SourceViewSignalMapper
class SourceViewsController(ControllerBase, list):
def __init__(self):
super(SourceViewsController, self).__init__()
self.state_manager: SourceViewStateManager = SourceViewStateManager()
self.signal_mapper: SourceViewSignalMapper = SourceViewSignalMapper()
self.signal_mapper.bind_emit(self.emit)
self.signal_mapper.set_state_manager(self.state_manager)
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.RemovedFileEvent):
self._remove_file(event)
if not self.signal_mapper.active_view: return
if isinstance(event, Code_Event_Types.TextChangedEvent):
if not self.signal_mapper.active_view: return
self.signal_mapper.active_view.command.exec("update_info_bar")
elif isinstance(event, Code_Event_Types.TextChangedEvent):
self.signal_mapper.active_view.command.exec("update_info_bar")
elif isinstance(event, Code_Event_Types.TextInsertedEvent):
self.signal_mapper.insert_text(event.file, event.text)
def _get_command_system(self):
event = Event_Factory.create_event("get_command_system")
self.message_to("commands", event)
command = event.response
del event
return command
def _remove_file(self, event: Code_Event_Types.RemovedFileEvent):
for source_view in self:
if not event.file.buffer == source_view.get_buffer(): continue
if not event.next_file:
source_view.command.exec("new_file")
continue
source_view.set_buffer(event.next_file.buffer)
def create_source_view(self):
source_view: SourceView = SourceView()
source_view.command = self._get_command_system()
source_view.command.set_data(source_view)
self.signal_mapper.connect_signals(source_view)
self.append(source_view)
return source_view
def first_map_load(self):
for source_view in self:
source_view.command.exec("new_file")
source_view = self[0]
source_view.grab_focus()
source_view.command.exec("load_start_files")

View File

@@ -0,0 +1,65 @@
# Python imports
# Lib imports
# Application imports
from libs.dto.states import SourceViewStates
from ...key_mapper import KeyMapper
from .states import *
class SourceViewStateManager:
def __init__(self):
self.key_mapper: KeyMapper = KeyMapper()
self.states: dict = {
SourceViewStates.INSERT: SourceViewsInsertState(),
SourceViewStates.MULTIINSERT: SourceViewsMultiInsertState(),
SourceViewStates.COMMAND: SourceViewsCommandState(),
SourceViewStates.READONLY: SourceViewsReadOnlyState()
}
def handle_focus_in_event(self, source_view, eve, emit):
return self.states[source_view.state].focus_in_event(source_view, eve, emit)
def handle_insert_text(self, source_view, file, text):
return self.states[source_view.state].insert_text(file, text)
def handle_move_cursor(self, source_view, step, count, extend_selection, emit):
return self.states[source_view.state].move_cursor(
source_view, step, count, extend_selection, emit
)
def handle_button_press_event(self, source_view, eve):
return self.states[source_view.state].button_press_event(source_view, eve)
def handle_button_release_event(self, source_view, eve):
# Handle state transitions (multi-insert toggling)
self._handle_multi_insert_toggle(source_view, eve)
return self.states[source_view.state].button_release_event(source_view, eve)
def handle_key_press_event(self, source_view, eve):
return self.states[source_view.state].key_press_event(
source_view, eve, self.key_mapper
)
def handle_key_release_event(self, source_view, eve):
return self.states[source_view.state].key_release_event(
source_view, eve, self.key_mapper
)
def _handle_multi_insert_toggle(self, source_view, eve):
is_control = self.key_mapper.is_control(eve)
if is_control and not source_view.state == SourceViewStates.MULTIINSERT:
logger.debug("Entered Multi-Insert Mode...")
source_view.state = SourceViewStates.MULTIINSERT
if not is_control and source_view.state == SourceViewStates.MULTIINSERT:
logger.debug("Entered Regular Insert Mode...")
self.states[source_view.state].clear_markers(source_view)
source_view.state = SourceViewStates.INSERT

View File

@@ -0,0 +1,8 @@
"""
Code Controllers Views States Package
"""
from .source_view_insert_state import SourceViewsInsertState
from .source_view_multi_insert_state import SourceViewsMultiInsertState
from .source_view_command_state import SourceViewsCommandState
from .source_view_read_only_state import SourceViewsReadOnlyState

View File

@@ -0,0 +1,36 @@
# Python imports
# Lib imports
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from libs.dto.states import SourceViewStates
class SourceViewsCommandState:
def __init__(self):
super(SourceViewsCommandState, self).__init__()
def focus_in_event(self, source_view, eve, emit):
return True
def move_cursor(self, source_view, step, count, extend_selection, emit):
return True
def insert_text(self, file, text):
return True
def button_press_event(self, source_view, eve):
return True
def button_release_event(self, source_view, eve):
return True
def key_press_event(self, source_view, eve, key_mapper):
return True
def key_release_event(self, source_view, eve, key_mapper):
return True

View File

@@ -0,0 +1,71 @@
# Python imports
# Lib imports
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from libs.dto.states import SourceViewStates
class SourceViewsInsertState:
def __init__(self):
super(SourceViewsInsertState, self).__init__()
def focus_in_event(self, source_view, eve, emit):
source_view.command.exec("set_miniview")
source_view.command.exec("set_focus_border")
source_view.command.exec("update_info_bar")
event = Event_Factory.create_event("focused_view", view = source_view)
emit(event)
def insert_text(self, file, text):
return True
def move_cursor(self, source_view, step, count, extend_selection, emit):
buffer = source_view.get_buffer()
itr = buffer.get_iter_at_mark( buffer.get_insert() )
line = itr.get_line()
char = itr.get_line_offset()
event = Event_Factory.create_event(
"cursor_moved",
view = source_view,
buffer = buffer,
line = line,
char = char
)
emit(event)
source_view.command.exec("update_info_bar")
def button_press_event(self, source_view, eve):
source_view.command.exec("update_info_bar")
def button_release_event(self, source_view, eve):
source_view.command.exec("update_info_bar")
def key_press_event(self, source_view, eve, key_mapper):
command = key_mapper._key_press_event(eve)
is_future = key_mapper._key_release_event(eve)
if is_future: return True
if not command: return False
source_view.command.exec(command)
return True
def key_release_event(self, source_view, eve, key_mapper):
command = key_mapper._key_release_event(eve)
is_past = key_mapper._key_press_event(eve)
if is_past: return True
if not command: return False
source_view.command.exec(command)
return True

View File

@@ -0,0 +1,131 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from libs.dto.states import SourceViewStates, MoveDirection, CursorAction
from ....mixins.source_mark_events_mixin import MarkEventsMixin
class SourceViewsMultiInsertState(MarkEventsMixin):
def __init__(self):
super(SourceViewsMultiInsertState, self).__init__()
self.cursor_action: CursorAction = 0
self.move_direction: MoveDirection = 0
self.insert_markers: list = []
def focus_in_event(self, source_view, eve, emit):
source_view.command.exec("set_miniview")
source_view.command.exec("set_focus_border")
source_view.command.exec("update_info_bar")
event = Event_Factory.create_event("focused_view", view = source_view)
emit(event)
def insert_text(self, file, text):
if not self.insert_markers: return False
buffer = file.buffer
# freeze buffer and insert to each mark (if any)
buffer.block_insert_after_signal()
buffer.begin_user_action()
with buffer.freeze_notify():
for mark in self.insert_markers:
itr = buffer.get_iter_at_mark(mark)
buffer.insert(itr, text, -1)
buffer.end_user_action()
buffer.unblock_insert_after_signal()
return True
def move_cursor(self, source_view, step, count, extend_selection, emit):
buffer = source_view.get_buffer()
self._process_move_direction(buffer)
self._signal_cursor_moved(source_view, emit)
source_view.command.exec("update_info_bar")
def button_press_event(self, source_view, eve):
source_view.command.exec("update_info_bar")
return True
def button_release_event(self, source_view, eve):
buffer = source_view.get_buffer()
insert_iter = buffer.get_iter_at_mark( buffer.get_insert() )
data = source_view.window_to_buffer_coords(
Gtk.TextWindowType.TEXT,
eve.x,
eve.y
)
is_over_text, \
target_iter, \
is_trailing = source_view.get_iter_at_position(data.buffer_x, data.buffer_y)
if not is_over_text:
# NOTE: Trying to put at very end of line if not over text (aka, clicking right of text)
target_iter.forward_visible_line()
target_iter.backward_char()
self._insert_mark(insert_iter, target_iter, buffer)
def key_press_event(self, source_view, eve, key_mapper):
char = key_mapper.get_raw_keyname(eve)
for action in CursorAction:
if not action.name == char.upper(): continue
self.cursor_action = action.value
self._process_cursor_action(source_view.get_buffer())
return False
for direction in MoveDirection:
if not direction.name == char.upper(): continue
self.move_direction = direction.value
return False
is_future = key_mapper._key_release_event(eve)
if is_future: return False
command = key_mapper._key_press_event(eve)
if not command: return False
source_view.command.exec(command)
return True
def key_release_event(self, source_view, eve, key_mapper):
command = key_mapper._key_release_event(eve)
is_past = key_mapper._key_press_event(eve)
if is_past: return False
if not command: return False
source_view.command.exec(command)
return True
def _signal_cursor_moved(self, source_view, emit):
buffer = source_view.get_buffer()
itr = buffer.get_iter_at_mark( buffer.get_insert() )
line = itr.get_line()
char = itr.get_line_offset()
event = Event_Factory.create_event(
"cursor_moved",
view = source_view,
buffer = buffer,
line = line,
char = char
)
emit(event)

View File

@@ -0,0 +1,36 @@
# Python imports
# Lib imports
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from libs.dto.states import SourceViewStates
class SourceViewsReadOnlyState:
def __init__(self):
super(SourceViewsReadOnlyState, self).__init__()
def focus_in_event(self, source_view, eve, emit):
return True
def move_cursor(self, source_view, step, count, extend_selection, emit):
return True
def insert_text(self, file, text):
return True
def button_press_event(self, source_view, eve):
return True
def button_release_event(self, source_view, eve):
return True
def key_press_event(self, source_view, eve, key_mapper):
return True
def key_release_event(self, source_view, eve, key_mapper):
return True

View File

@@ -1,101 +0,0 @@
# Python imports
import inspect
from typing import Dict, Type
import re
# Lib imports
# Application imports
from libs.singleton import Singleton
from libs.dto.code import CodeEvent
from libs.dto import code
class EventFactory(Singleton):
def __init__(self):
self._event_classes: Dict[str, Type[CodeEvent]] = {}
self._auto_register_events()
def register_event(self, event_type: str, event_class: Type[CodeEvent]):
self._event_classes[event_type] = event_class
def create_event(self, event_type: str, **kwargs) -> CodeEvent:
if event_type not in self._event_classes:
raise ValueError(f"Unknown event type: {event_type}")
event_class = self._event_classes[event_type]
event = event_class()
for key, value in kwargs.items():
if hasattr(event, key):
setattr(event, key, value)
else:
raise ValueError(f"Event class {event_class.__name__} has no attribute '{key}'")
return event
def _auto_register_events(self):
for name, obj in code.__dict__.items():
if not self._is_valid_event_class(obj): continue
event_type = self._class_name_to_event_type(name)
self.register_event(event_type, obj)
logger.debug(f"Auto-registered {len(self._event_classes)} event types")
def _is_valid_event_class(self, obj) -> bool:
return (inspect.isclass(obj) and
issubclass(obj, CodeEvent) and
obj != CodeEvent)
def _class_name_to_event_type(self, class_name: str) -> str:
base_name = class_name[:-5] if class_name.endswith('Event') else class_name
return re.sub(r'(?<!^)(?=[A-Z])', '_', base_name).lower()
def create_cursor_moved(self, **kwargs):
return self.create_event("cursor_moved", **kwargs)
def create_text_changed(self, **kwargs):
return self.create_event("text_changed", **kwargs)
def create_focused_view(self, **kwargs):
return self.create_event("focused_view", **kwargs)
def create_modified_changed(self, **kwargs):
return self.create_event("modified_changed", **kwargs)
def create_get_command_system(self, **kwargs):
return self.create_event("get_command_system", **kwargs)
def create_file_path_set(self, **kwargs):
return self.create_event("file_path_set", **kwargs)
def create_text_inserted(self, **kwargs):
return self.create_event("text_inserted", **kwargs)
def create_set_active_file(self, **kwargs):
return self.create_event("set_active_file", **kwargs)
def create_added_new_file(self, **kwargs):
return self.create_event("added_new_file", **kwargs)
def create_popped_file(self, **kwargs):
return self.create_event("popped_file", **kwargs)
def create_get_file(self, **kwargs):
return self.create_event("get_file", **kwargs)
def create_get_swap_file(self, **kwargs):
return self.create_event("get_swap_file", **kwargs)
def create_remove_file(self, **kwargs):
return self.create_event("remove_file", **kwargs)
def create_removed_file(self, **kwargs):
return self.create_event("removed_file", **kwargs)
Event_Factory = EventFactory()
Event_Factory_Types = code

View File

@@ -125,3 +125,13 @@ class KeyMapper:
if is_alt:
self.state = self.state | AltKeyState
def is_control(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
return True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
def is_shift(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
return True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
def get_raw_keyname(self, eve):
return Gdk.keyval_name(eve.keyval)

View File

@@ -0,0 +1,107 @@
# Python imports
import random
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from libs.dto.states import SourceViewStates, MoveDirection, CursorAction
class MarkEventsMixin:
def clear_markers(self, source_view):
buffer = source_view.get_buffer()
for mark in self.insert_markers:
mark.set_visible(False)
buffer.delete_mark(mark)
self.insert_markers.clear()
def _insert_mark(self, insert_iter, target_iter, buffer):
mark_found = self._check_for_insert_marks(target_iter, buffer)
if mark_found: return
random_bits = random.getrandbits(128)
hash = "%032x" % random_bits
mark = Gtk.TextMark.new(
name = f"multi_insert_{hash}",
left_gravity = False
)
buffer.add_mark(mark, target_iter)
mark.set_visible(True)
self.insert_markers.append(mark)
def _check_for_insert_marks(self, target_iter, buffer):
marks = target_iter.get_marks()
for mark in marks:
if mark in self.insert_markers[:]:
mark.set_visible(False)
self.insert_markers.remove(mark)
buffer.delete_mark(mark)
return True
insert_itr = buffer.get_iter_at_mark( buffer.get_insert() )
if target_iter.equal(insert_itr): return True
return False
def _process_cursor_action(self, buffer):
if not self.insert_markers: return
if self.cursor_action == CursorAction.NONE.value: return
action = self.cursor_action
for mark in self.insert_markers:
itr = buffer.get_iter_at_mark(mark)
if action == CursorAction.BACKSPACE.value:
buffer.backspace(itr, interactive = True, default_editable = True)
elif action == CursorAction.DELETE.value:
itr.forward_char()
buffer.backspace(itr, interactive = True, default_editable = True)
elif action == CursorAction.ENTER.value:
...
self.cursor_action = CursorAction.NONE.value
def _process_move_direction(self, buffer):
if not self.insert_markers: return
if self.move_direction == MoveDirection.NONE.value: return
direction = self.move_direction
for mark in self.insert_markers:
itr = buffer.get_iter_at_mark(mark)
if direction == MoveDirection.UP.value:
new_line = itr.get_line() - 1
new_itr = buffer.get_iter_at_line_offset(
new_line,
itr.get_line_index()
)
elif direction == MoveDirection.DOWN.value:
new_line = itr.get_line() + 1
new_itr = buffer.get_iter_at_line_offset(
new_line,
itr.get_line_index()
)
elif direction == MoveDirection.LEFT.value:
if not itr.backward_char(): break
new_itr = itr
elif direction == MoveDirection.RIGHT.value:
if not itr.forward_char(): break
new_itr = itr
else:
continue
buffer.move_mark_by_name(mark.get_name(), new_itr)
self.move_direction = MoveDirection.NONE

View File

@@ -21,20 +21,41 @@ class SourceBuffer(GtkSource.Buffer):
_changed,
_mark_set,
_insert_text,
_after_insert_text,
_modified_changed,
):
self._handler_ids = [
self.connect("changed", _changed),
self.connect("mark-set", _mark_set),
self.connect("insert-text", _insert_text),
self.connect("modified-changed", _modified_changed)
self.connect("changed", _changed),
self.connect("mark-set", _mark_set),
self.connect("insert-text", _insert_text),
self.connect_after("insert-text", _after_insert_text),
self.connect("modified-changed", _modified_changed)
]
def block_changed_signal(self):
self.handler_block(self._handler_ids[0])
def block_insert_after_signal(self):
self.handler_block(self._handler_ids[3])
def block_modified_changed_signal(self):
self.handler_block(self._handler_ids[4])
def unblock_changed_signal(self):
self.handler_unblock(self._handler_ids[0])
def unblock_insert_after_signal(self):
self.handler_unblock(self._handler_ids[3])
def unblock_modified_changed_signal(self):
self.handler_unblock(self._handler_ids[4])
def clear_signals(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)
def __del__(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)
self.disconnect(handle_id)

View File

@@ -8,12 +8,12 @@ gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from libs.dto.code import CodeEvent
from .event_factory import Event_Factory, Event_Factory_Types
from libs.event_factory import Event_Factory, Code_Event_Types
from .source_buffer import SourceBuffer
@@ -38,37 +38,60 @@ class SourceFile(GtkSource.File):
self._changed,
self._mark_set,
self._insert_text,
self._after_insert_text,
self._modified_changed
)
def _changed(self, buffer: SourceBuffer):
event = Event_Factory.create_text_changed(buffer = buffer)
event = Event_Factory.create_event("text_changed", buffer = buffer)
event.file = self
self.emit(event)
def _insert_text(self, buffer: SourceBuffer, location: Gtk.TextIter,
def _insert_text(
self,
buffer: SourceBuffer,
location: Gtk.TextIter,
text: str, length: int
):
...
def _after_insert_text(
self,
buffer: SourceBuffer,
location: Gtk.TextIter,
text: str, length: int
):
event = Event_Factory.create_event(
"text_inserted",
file = self,
buffer = buffer
file = self,
buffer = self.buffer,
location = location,
text = text,
length = length
)
self.emit(event)
def _mark_set(self, buffer: SourceBuffer, location: Gtk.TextIter,
# Note: 'idle_add' needed b/c markers don't get thir positions
# updated relative to the initial insert.
# If not used, seg faults galor during multi insert.
GLib.idle_add(self.emit, event)
def _mark_set(
self,
buffer: SourceBuffer,
location: Gtk.TextIter,
mark: Gtk.TextMark
):
# event = CodeEvent()
# event.etype = "mark_set"
# event.file = self
# event.buffer = buffer
# event = Event_Factory.create_event(
# "mark_set",
# file = self, buffer = buffer
# )
# self.emit(event)
...
def _modified_changed(self, buffer: SourceBuffer):
event = Event_Factory.create_modified_changed(
event = Event_Factory.create_event(
"modified_changed",
file = self, buffer = buffer
)
@@ -108,6 +131,12 @@ class SourceFile(GtkSource.File):
self.emit(event)
def save(self):
event = Event_Factory.create_event(
"saved_file",
file = self, buffer = self.buffer
)
self.emit(event)
self._write_file( self.get_location() )
def save_as(self):
@@ -122,8 +151,8 @@ class SourceFile(GtkSource.File):
def close(self):
del self.buffer
def emit(self, event: CodeEvent):
def emit(self, event: Code_Event_Types.CodeEvent):
...
def emit_to(self, controller: str, event: CodeEvent):
def emit_to(self, controller: str, event: Code_Event_Types.CodeEvent):
...

View File

@@ -9,14 +9,19 @@ from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GtkSource
# Application imports
from libs.dto.states import SourceViewStates
from .mixins.source_view_dnd_mixin import SourceViewDnDMixin
class SourceView(GtkSource.View, SourceViewDnDMixin):
def __init__(self):
def __init__(self, state: SourceViewStates = SourceViewStates.INSERT):
super(SourceView, self).__init__()
self.state = state
self._cut_temp_timeout_id = None
self._cut_buffer = ""

View File

@@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from libs.dto.code.code_event import CodeEvent
from libs.event_factory import Code_Event_Types
from .source_view import SourceView
from .source_file import SourceFile
@@ -37,7 +37,7 @@ class TabsWidget(Gtk.ButtonBox):
def _load_widgets(self):
...
def add_tab(self, event: CodeEvent):
def add_tab(self, event: Code_Event_Types.CodeEvent):
"""Add a tab widget for the given file event."""
if not hasattr(self, 'tabs'):
return
@@ -61,7 +61,7 @@ class TabsWidget(Gtk.ButtonBox):
self.tabs.add(tab)
def remove_tab(self, event: CodeEvent):
def remove_tab(self, event: Code_Event_Types.CodeEvent):
"""Remove a tab widget for the given file event."""
if not hasattr(self, 'tabs'):
return
@@ -75,7 +75,7 @@ class TabsWidget(Gtk.ButtonBox):
return
def update_tab_label(self, event: CodeEvent):
def update_tab_label(self, event: Code_Event_Types.CodeEvent):
"""Update tab label for the given file event."""
if not hasattr(self, 'tabs'):
return

View File

@@ -13,9 +13,8 @@ class Separator(Gtk.Separator):
def __init__(self, id: str = None, ORIENTATION: int = 0):
super(Separator, self).__init__()
builder = settings_manager.get_builder()
if id:
builder.expose_object(id, self)
widget_registery.expose_object(id, self)
self.ORIENTATION = ORIENTATION
self._setup_styling()

View File

@@ -12,7 +12,6 @@ from gi.repository import GLib
from gi.repository import Vte
# Application imports
from libs.dto.event import Event
@@ -59,28 +58,29 @@ class VteWidget(Vte.Terminal):
...
def _do_session_spawn(self):
env = [
"DISPLAY=:0",
"LC_ALL=C",
"TERM='xterm-256color'",
f"HOME='{settings_manager.path_manager.get_home_path()}'",
"XDG_RUNTIME_DIR='/run/user/1000'",
f"XAUTHORITY='{settings_manager.path_manager.get_home_path()}/.Xauthority'",
"HISTFILE=/dev/null",
"HISTSIZE=0",
"HISTFILESIZE=0",
"PS1=\\h@\\u \\W -->: ",
]
self.spawn_sync(
Vte.PtyFlags.DEFAULT,
settings_manager.path_manager.get_home_path(),
["/bin/bash"],
[],
env,
GLib.SpawnFlags.DEFAULT,
None, None,
)
# Note: '-->:' is used as a delimiter to split on to get command actual.
# !!! DO NOT REMOVE UNLESS CODE UPDATED ACCORDINGLY !!!
# Also, KEEP the <space> prefix in commands to keep from inserting to bash history.
startup_cmds = [
" env -i /bin/bash --noprofile --norc\n",
" export TERM='xterm-256color'\n",
" export LC_ALL=C\n",
" export XDG_RUNTIME_DIR='/run/user/1000'\n",
" export DISPLAY=:0\n",
f" export XAUTHORITY='{settings_manager.path_manager.get_home_path()}/.Xauthority'\n",
f" \nexport HOME='{settings_manager.path_manager.get_home_path()}'\n",
" export PS1='\\h@\\u \\W -->: '\n",
" clear\n"
]
for i in startup_cmds:

View File

@@ -10,7 +10,7 @@ from gi.repository import WebKit2
# Application imports
from libs.settings.other.webkit_ui_settings import WebkitUISettings
from libs.dto.event import Event
from libs.dto.base_event import BaseEvent
class WebkitUI(WebKit2.WebView):
@@ -44,6 +44,7 @@ class WebkitUI(WebKit2.WebView):
data = f.read()
self.load_html(content = data, base_uri = f"file://{path}/")
# self.load_uri("https://duckduckgo.com/")
def _setup_content_manager(self):
content_manager = self.get_user_content_manager()
@@ -55,7 +56,7 @@ class WebkitUI(WebKit2.WebView):
message = js_value.to_string()
try:
event = Event( **json.loads(message) )
event = BaseEvent( **json.loads(message) )
event_system.emit("handle-bridge-event", (event,))
except Exception as e:
logger.info(e)

View File

@@ -0,0 +1,3 @@
"""
Libs Controllers Package
"""

View File

@@ -3,9 +3,9 @@
# Lib imports
# Application imports
from libs.singleton import Singleton
from ..singleton import Singleton
from libs.dto.code.code_event import CodeEvent
from ..dto.base_event import BaseEvent
from .emit_dispatcher import EmitDispatcher
from .controller_context import ControllerContext
@@ -24,15 +24,18 @@ class ControllerBase(Singleton, EmitDispatcher):
self.controller_context: ControllerContext = None
def _controller_message(self, event: CodeEvent):
raise ControllerBaseException("Controller Base must override '_controller_message'...")
def _controller_message(self, event: BaseEvent):
raise ControllerBaseException("Controller Base '_controller_message' must be overridden...")
def set_controller_context(self, controller_context: ControllerContext):
self.controller_context = controller_context
def message_to(self, name: str, event: CodeEvent):
def message(self, event: BaseEvent):
return self.controller_context.message(event)
def message_to(self, name: str, event: BaseEvent):
return self.controller_context.message_to(name, event)
def message_all(self, event: CodeEvent):
return self.controller_context.message_all(event)
def message_to_selected(self, names: list[str], event: BaseEvent):
for name in names:
self.controller_context.message_to_selected(name, event)

View File

@@ -3,7 +3,7 @@
# Lib imports
# Application imports
from libs.dto.code.code_event import CodeEvent
from ..dto.base_event import BaseEvent
@@ -17,8 +17,11 @@ class ControllerContext:
super(ControllerContext, self).__init__()
def message_to(self, name: str, event: CodeEvent):
def message(self, event: BaseEvent):
raise ControllerContextException("Controller Context 'message' must be overriden by Controller Manager...")
def message_to(self, name: str, event: BaseEvent):
raise ControllerContextException("Controller Context 'message_to' must be overriden by Controller Manager...")
def message_all(self, event: CodeEvent):
raise ControllerContextException("Controller Context 'message_all' must be overriden by Controller Manager...")
def message_to_selected(self, name: list, event: BaseEvent):
raise ControllerContextException("Controller Context 'message_to_selected' must be overriden by Controller Manager...")

View File

@@ -3,9 +3,8 @@
# Lib imports
# Application imports
from libs.singleton import Singleton
from libs.dto.code.code_event import CodeEvent
from ..singleton import Singleton
from ..event_factory import Code_Event_Types
from .controller_base import ControllerBase
from .controller_context import ControllerContext
@@ -25,7 +24,7 @@ class ControllerManager(Singleton, dict):
def _crete_controller_context(self) -> ControllerContext:
controller_context = ControllerContext()
controller_context.message_to = self.message_to
controller_context.message_all = self.message_all
controller_context.message = self.message
return controller_context
@@ -33,16 +32,19 @@ class ControllerManager(Singleton, dict):
if not name or controller == None:
raise ControllerManagerException("Must pass in a 'name' and 'controller'...")
controller.set_controller_context(
self._crete_controller_context()
)
if name in self.keys():
raise ControllerManagerException(f"Can't bind controller to registered name of '{name}'...")
controller.set_controller_context( self._crete_controller_context() )
self[name] = controller
def get_controllers_key_list(self) -> list[str]:
return self.keys()
def message_to(self, name: str, event: CodeEvent):
def message_to(self, name: str, event: Code_Event_Types.CodeEvent):
self[name]._controller_message(event)
def message_all(self, event: CodeEvent):
def message(self, event: Code_Event_Types.CodeEvent):
for key in self.keys():
self[key]._controller_message(event)

View File

@@ -3,7 +3,7 @@
# Lib imports
# Application imports
from libs.dto.code.code_event import CodeEvent
from ..dto.base_event import BaseEvent
@@ -12,8 +12,8 @@ class EmitDispatcher:
super(EmitDispatcher, self).__init__()
def emit(self, event: CodeEvent):
self.message_all(event)
def emit(self, event: BaseEvent):
self.message(event)
def emit_to(self, controller: str, event: CodeEvent):
def emit_to(self, controller: str, event: BaseEvent):
self.message_to(controller, event)

View File

@@ -1,5 +1,5 @@
"""
DB Package
Libs DB Package
"""
from .models import User

View File

@@ -1,5 +1,5 @@
"""
DTO Class Package
Libs DTO(s) Package
"""
from .event import Event
from .base_event import BaseEvent

View File

@@ -0,0 +1,14 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
@dataclass(slots = True)
class BaseEvent:
topic: str = None
content: any = None
raw_content: any = None

View File

@@ -1,9 +1,11 @@
"""
Code DTO Class Package
Libs Code DTO(s) Code Package
"""
from .code_event import CodeEvent
from .register_provider_event import RegisterProviderEvent
from .get_command_system_event import GetCommandSystemEvent
from .request_completion_event import RequestCompletionEvent
from .cursor_moved_event import CursorMovedEvent
@@ -18,6 +20,7 @@ from .added_new_file_event import AddedNewFileEvent
from .swapped_file_event import SwappedFileEvent
from .popped_file_event import PoppedFileEvent
from .removed_file_event import RemovedFileEvent
from .saved_file_event import SavedFileEvent
from .get_file_event import GetFileEvent
from .get_swap_file_event import GetSwapFileEvent

View File

@@ -4,11 +4,12 @@ from dataclasses import dataclass, field
# Lib imports
# Application imports
from ..base_event import BaseEvent
@dataclass
class CodeEvent:
class CodeEvent(BaseEvent):
ignore_focus: bool = False
view: any = None
file: any = None

View File

@@ -0,0 +1,19 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
import gi
gi.require_version('GtkSource', '4')
from gi.repository import GtkSource
# Application imports
from ..base_event import BaseEvent
@dataclass
class RegisterProviderEvent(BaseEvent):
provider_name: str = ""
provider: GtkSource.CompletionProvider = None
language_ids: list = field(default_factory=lambda: [])

View File

@@ -0,0 +1,13 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
from .code_event import CodeEvent
@dataclass
class SavedFileEvent(CodeEvent):
...

View File

@@ -2,6 +2,11 @@
from dataclasses import dataclass, field
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .code_event import CodeEvent
@@ -10,6 +15,6 @@ from .code_event import CodeEvent
@dataclass
class TextInsertedEvent(CodeEvent):
line: int = 0
char: int = 0
value: str = ""
location: Gtk.TextIter = None
text: str = ""
length: int = 0

View File

@@ -1,10 +0,0 @@
# Python imports
# Lib imports
# Application imports
class ObservableEvent:
...

View File

@@ -0,0 +1,3 @@
"""
Libs Plugin DTO(s) Package
"""

View File

@@ -6,9 +6,6 @@ from dataclasses import dataclass, field
# Application imports
@dataclass
class Event:
topic: str
content: str
raw_content: str
class Requests:
bind_keys: list = field(default_factory = lambda: [])

View File

@@ -0,0 +1,7 @@
"""
Code DTO States Package
"""
from .source_view_states import SourceViewStates
from .cursor_action import CursorAction
from .move_direction import MoveDirection

View File

@@ -0,0 +1,14 @@
# Python imports
from enum import Enum
# Lib imports
# Application imports
class CursorAction(Enum):
NONE = 0
DELETE = 1
BACKSPACE = 2
ENTER = 3

View File

@@ -0,0 +1,15 @@
# Python imports
from enum import Enum
# Lib imports
# Application imports
class MoveDirection(Enum):
NONE = 0
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4

View File

@@ -0,0 +1,14 @@
# Python imports
from enum import Enum
# Lib imports
# Application imports
class SourceViewStates(Enum):
INSERT = 0
MULTIINSERT = 1
COMMAND = 2
READONLY = 3

View File

@@ -1,22 +0,0 @@
# Python imports
# Lib imports
# Application imports
from .singleton import Singleton
class EndpointRegistry(Singleton):
def __init__(self):
self._endpoints = {}
def register(self, rule, **options):
def decorator(f):
self._endpoints[rule] = f
return f
return decorator
def get_endpoints(self):
return self._endpoints

Some files were not shown because too many files have changed in this diff Show More