Major completion provider overhaul; pluigin load and pattern improvements; css overhaul/cleanup; source view state modes added
BIN
notes/dynamic-widget-layout-using-types-in-dict.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
notes/scrshot_2026-01-12 22:42:45.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
notes/scrshot_2026-01-30 13:04:41.png
Normal file
|
After Width: | Height: | Size: 414 KiB |
BIN
notes/scrshot_2026-02-05 01:53:50.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
notes/scrshot_2026-02-05 01:54:06.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
notes/scrshot_2026-02-05 01:58:32.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
notes/scrshot_2026-02-05 02:02:21.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
notes/scrshot_2026-02-05 02:02:57.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
notes/scrshot_2026-02-05 02:05:35.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
notes/scrshot_2026-02-05 02:07:22.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
notes/scrshot_2026-02-05 02:09:23.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
notes/scrshot_2026-02-05 02:09:36.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
notes/scrshot_2026-02-05 02:10:58.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
notes/scrshot_2026-02-05 02:11:39.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
notes/scrshot_2026-02-05 02:11:55.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
3
plugins/example_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/example_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
7
plugins/example_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Example Completer",
|
||||||
|
"author": "John Doe",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
40
plugins/example_completer/plugin.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.dto.base_event import BaseEvent
|
||||||
|
from libs.event_factory import Event_Factory
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .provider import Provider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
self.provider: Provider = None
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: BaseEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.provider = Provider()
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"register_provider",
|
||||||
|
provider_name = "Example Completer",
|
||||||
|
provider = self.provider,
|
||||||
|
language_ids = []
|
||||||
|
)
|
||||||
|
self.message_to("completion", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
57
plugins/example_completer/provider.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
from gi.repository import GObject
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .provider_response_cache import ProviderResponseCache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Provider(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)
|
||||||
|
|
||||||
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
|
|
||||||
|
def do_get_name(self):
|
||||||
|
""" Returns: a new string containing the name of the provider. """
|
||||||
|
return 'Example Completion'
|
||||||
|
|
||||||
|
def do_match(self, context):
|
||||||
|
# word = context.get_word()
|
||||||
|
# if not word or len(word) < 2: return False
|
||||||
|
|
||||||
|
""" Get whether the provider match the context of completion detailed in context. """
|
||||||
|
word = self.response_cache.get_word(context)
|
||||||
|
if not word or len(word) < 2: return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_get_priority(self):
|
||||||
|
""" Determin position in result list along other providor results. """
|
||||||
|
return 5
|
||||||
|
|
||||||
|
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.USER_REQUESTED | GtkSource.CompletionActivation.INTERACTIVE
|
||||||
|
return GtkSource.CompletionActivation.INTERACTIVE
|
||||||
|
|
||||||
|
def do_populate(self, context):
|
||||||
|
proposals = self.response_cache.filter_with_context(context)
|
||||||
|
|
||||||
|
context.add_proposals(self, proposals, True)
|
||||||
|
|
||||||
110
plugins/example_completer/provider_response_cache.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# 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 GLib
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Code_Event_Types
|
||||||
|
|
||||||
|
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(ProviderResponseCache, self).__init__()
|
||||||
|
|
||||||
|
self.matchers: dict = {
|
||||||
|
"hello": {
|
||||||
|
"label": "Hello, World!",
|
||||||
|
"text": "Hello, World!",
|
||||||
|
"info": GLib.markup_escape_text( "<b>Says the first ever program developers write...</b>" )
|
||||||
|
},
|
||||||
|
"foo": {
|
||||||
|
"label": "foo",
|
||||||
|
"text": "foo }}"
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
"label": "bar",
|
||||||
|
"text": "bar }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def filter(self, word: str):
|
||||||
|
...
|
||||||
|
|
||||||
|
def filter_with_context(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 = [
|
||||||
|
self.create_completion_item(
|
||||||
|
self.matchers[ "hello" ]["label"],
|
||||||
|
self.matchers[ "hello" ]["text"],
|
||||||
|
self.matchers[ "hello" ]["info"]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# 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 not end_iter: return
|
||||||
|
|
||||||
|
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):
|
||||||
|
# optionally proposed based on left search via regex
|
||||||
|
proposals.append(
|
||||||
|
self.create_completion_item(
|
||||||
|
self.matchers[ "foo" ]["label"],
|
||||||
|
self.matchers[ "foo" ]["text"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# optionally proposed based on left search via regex
|
||||||
|
proposals.append(
|
||||||
|
self.create_completion_item(
|
||||||
|
self.matchers[ "bar" ]["label"],
|
||||||
|
self.matchers[ "bar" ]["text"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return proposals
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
plugins/lsp_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/lsp_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
7
plugins/lsp_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "LSP Completer",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
43
plugins/lsp_completer/plugin.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.dto.base_event import BaseEvent
|
||||||
|
from libs.event_factory import Event_Factory
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .provider import Provider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
self.provider: Provider = None
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: BaseEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.provider = Provider()
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"register_provider",
|
||||||
|
provider_name = "LSP Completer",
|
||||||
|
provider = self.provider,
|
||||||
|
language_ids = []
|
||||||
|
)
|
||||||
|
self.message_to("completion", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def generate_plugin_element(self):
|
||||||
|
...
|
||||||
79
plugins/lsp_completer/provider.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
from gi.repository import GObject
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .provider_response_cache import ProviderResponseCache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Provider(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.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
word = self.response_cache.get_word(context)
|
||||||
|
if not word or len(word) < 2: return False
|
||||||
|
|
||||||
|
iter = self.get_iter_correctly(context)
|
||||||
|
iter.backward_char()
|
||||||
|
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
|
||||||
|
|
||||||
|
buffer = iter.get_buffer()
|
||||||
|
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_get_priority(self):
|
||||||
|
return 5
|
||||||
|
|
||||||
|
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):
|
||||||
|
proposals = self.get_completion_filter(context)
|
||||||
|
|
||||||
|
context.add_proposals(self, proposals, True)
|
||||||
|
|
||||||
|
def get_completion_filter(self, context):
|
||||||
|
proposals = [
|
||||||
|
self.response_cache.create_completion_item(
|
||||||
|
"LSP Class",
|
||||||
|
"LSP Code",
|
||||||
|
"A test LSP completion item..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
return proposals
|
||||||
45
plugins/lsp_completer/provider_response_cache.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Code_Event_Types
|
||||||
|
|
||||||
|
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(ProviderResponseCache, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def filter(self, word: str):
|
||||||
|
...
|
||||||
|
|
||||||
|
def filter_with_context(self, context: GtkSource.CompletionContext):
|
||||||
|
proposals = [
|
||||||
|
self.create_completion_item(
|
||||||
|
"LSP Class",
|
||||||
|
"LSP Code",
|
||||||
|
"A test LSP completion item..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
return proposals
|
||||||
3
plugins/python_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/python_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
7
plugins/python_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Python Completer",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
40
plugins/python_completer/plugin.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.dto.base_event import BaseEvent
|
||||||
|
from libs.event_factory import Event_Factory
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .provider import Provider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
self.provider: Provider = None
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: BaseEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.provider = Provider()
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"register_provider",
|
||||||
|
provider_name = "Python Completer",
|
||||||
|
provider = self.provider,
|
||||||
|
language_ids = []
|
||||||
|
)
|
||||||
|
self.message_to("completion", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||