Moved completers to new dir; improved completers and added word completion
This commit is contained in:
7
plugins/completers/example_completer/manifest.json
Normal file
7
plugins/completers/example_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Example Completer",
|
||||||
|
"author": "John Doe",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
40
plugins/completers/example_completer/plugin.py
Normal file
40
plugins/completers/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):
|
||||||
|
...
|
||||||
76
plugins/completers/example_completer/provider.py
Normal file
76
plugins/completers/example_completer/provider.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GObject
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
super(Provider, self).__init__()
|
||||||
|
|
||||||
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
|
|
||||||
|
def do_get_name(self):
|
||||||
|
""" Returns: a new string containing the name of the provider. """
|
||||||
|
return 'Example Code 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_activate_proposal(self, proposal, iter_):
|
||||||
|
""" Manually handle actual completion insert or set flags and handle normally. """
|
||||||
|
|
||||||
|
buffer = iter_.get_buffer()
|
||||||
|
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||||
|
# to insure marker processes inserted text correctly.
|
||||||
|
buffer.is_processing_completion = True
|
||||||
|
return False
|
||||||
|
|
||||||
|
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):
|
||||||
|
results = self.response_cache.filter_with_context(context)
|
||||||
|
proposals = []
|
||||||
|
|
||||||
|
for entry in results:
|
||||||
|
proposals.append(
|
||||||
|
self.response_cache.create_completion_item(
|
||||||
|
entry["label"],
|
||||||
|
entry["text"],
|
||||||
|
entry["info"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
context.add_proposals(self, proposals, True)
|
||||||
|
|
||||||
109
plugins/completers/example_completer/provider_response_cache.py
Normal file
109
plugins/completers/example_completer/provider_response_cache.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# 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) -> list[dict]:
|
||||||
|
...
|
||||||
|
|
||||||
|
def filter_with_context(self, context) -> list[dict]:
|
||||||
|
"""
|
||||||
|
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: list[dict] = [
|
||||||
|
{
|
||||||
|
"label": self.matchers[ "hello" ]["label"],
|
||||||
|
"text": self.matchers[ "hello" ]["text"],
|
||||||
|
"info": 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(
|
||||||
|
{
|
||||||
|
"label": self.matchers[ "foo" ]["label"],
|
||||||
|
"text": self.matchers[ "foo" ]["text"],
|
||||||
|
"info": ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# optionally proposed based on left search via regex
|
||||||
|
proposals.append(
|
||||||
|
{
|
||||||
|
"label": self.matchers[ "bar" ]["label"],
|
||||||
|
"text": self.matchers[ "bar" ]["text"],
|
||||||
|
"info": ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return proposals
|
||||||
@@ -4,15 +4,15 @@
|
|||||||
import gi
|
import gi
|
||||||
gi.require_version('GtkSource', '4')
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
from gi.repository import GtkSource
|
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .provider_response_cache import ProviderResponseCache
|
from .provider_response_cache import ProviderResponseCache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Provider(GObject.Object, GtkSource.CompletionProvider):
|
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||||
"""
|
"""
|
||||||
This code is an LSP code completion plugin for Newton.
|
This code is an LSP code completion plugin for Newton.
|
||||||
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
|
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
|
||||||
@@ -20,7 +20,7 @@ class Provider(GObject.Object, GtkSource.CompletionProvider):
|
|||||||
__gtype_name__ = 'LSPProvider'
|
__gtype_name__ = 'LSPProvider'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GObject.Object.__init__(self)
|
super(Provider, self).__init__()
|
||||||
|
|
||||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
@@ -31,14 +31,11 @@ class Provider(GObject.Object, GtkSource.CompletionProvider):
|
|||||||
def do_get_name(self):
|
def do_get_name(self):
|
||||||
return "LSP Code Completion"
|
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):
|
def do_match(self, context):
|
||||||
word = self.response_cache.get_word(context)
|
word = self.response_cache.get_word(context)
|
||||||
if not word or len(word) < 2: return False
|
if not word or len(word) < 2: return False
|
||||||
|
|
||||||
iter = self.get_iter_correctly(context)
|
iter = self.response_cache.get_iter_correctly(context)
|
||||||
iter.backward_char()
|
iter.backward_char()
|
||||||
ch = iter.get_char()
|
ch = iter.get_char()
|
||||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||||
@@ -56,6 +53,13 @@ class Provider(GObject.Object, GtkSource.CompletionProvider):
|
|||||||
def do_get_priority(self):
|
def do_get_priority(self):
|
||||||
return 5
|
return 5
|
||||||
|
|
||||||
|
def do_activate_proposal(self, proposal, iter_):
|
||||||
|
buffer = iter_.get_buffer()
|
||||||
|
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||||
|
# to insure marker processes inserted text correctly.
|
||||||
|
buffer.is_processing_completion = True
|
||||||
|
return False
|
||||||
|
|
||||||
def do_get_activation(self):
|
def do_get_activation(self):
|
||||||
""" The context for when a provider will show results """
|
""" The context for when a provider will show results """
|
||||||
# return GtkSource.CompletionActivation.NONE
|
# return GtkSource.CompletionActivation.NONE
|
||||||
@@ -63,17 +67,16 @@ class Provider(GObject.Object, GtkSource.CompletionProvider):
|
|||||||
# return GtkSource.CompletionActivation.INTERACTIVE
|
# return GtkSource.CompletionActivation.INTERACTIVE
|
||||||
|
|
||||||
def do_populate(self, context):
|
def do_populate(self, context):
|
||||||
proposals = self.get_completion_filter(context)
|
results = self.response_cache.filter_with_context(context)
|
||||||
|
proposals = []
|
||||||
|
|
||||||
|
for entry in results:
|
||||||
|
proposals.append(
|
||||||
|
self.response_cache.create_completion_item(
|
||||||
|
entry["label"],
|
||||||
|
entry["text"],
|
||||||
|
entry["info"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
context.add_proposals(self, proposals, True)
|
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
|
|
||||||
@@ -30,16 +30,16 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def filter(self, word: str):
|
def filter(self, word: str) -> list[dict]:
|
||||||
...
|
return []
|
||||||
|
|
||||||
def filter_with_context(self, context: GtkSource.CompletionContext):
|
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||||
proposals = [
|
proposals = [
|
||||||
self.create_completion_item(
|
{
|
||||||
"LSP Class",
|
"label": "LSP Class",
|
||||||
"LSP Code",
|
"text": "LSP Code",
|
||||||
"A test LSP completion item..."
|
"info": "A test LSP completion item..."
|
||||||
)
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
return proposals
|
return proposals
|
||||||
3
plugins/completers/snippets_completer/__init__.py
Normal file
3
plugins/completers/snippets_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/completers/snippets_completer/__main__.py
Normal file
3
plugins/completers/snippets_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -3,11 +3,9 @@ import re
|
|||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
|
||||||
gi.require_version('GtkSource', '4')
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
from gi.repository import Gtk
|
|
||||||
from gi.repository import GtkSource
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
@@ -23,7 +21,7 @@ class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
|||||||
__gtype_name__ = 'SnippetsCompletionProvider'
|
__gtype_name__ = 'SnippetsCompletionProvider'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GObject.Object.__init__(self)
|
super(Provider, self).__init__()
|
||||||
|
|
||||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
@@ -40,6 +38,13 @@ class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
|||||||
def do_get_priority(self):
|
def do_get_priority(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
def do_activate_proposal(self, proposal, iter_):
|
||||||
|
buffer = iter_.get_buffer()
|
||||||
|
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||||
|
# to insure marker processes inserted text correctly.
|
||||||
|
buffer.is_processing_completion = True
|
||||||
|
return False
|
||||||
|
|
||||||
def do_get_activation(self):
|
def do_get_activation(self):
|
||||||
""" The context for when a provider will show results """
|
""" The context for when a provider will show results """
|
||||||
# return GtkSource.CompletionActivation.NONE
|
# return GtkSource.CompletionActivation.NONE
|
||||||
@@ -52,8 +52,8 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def filter(self, word: str):
|
def filter(self, word: str) -> list[dict]:
|
||||||
response: list = []
|
response: list[dict] = []
|
||||||
|
|
||||||
for entry in self.matchers:
|
for entry in self.matchers:
|
||||||
if not word in entry: continue
|
if not word in entry: continue
|
||||||
@@ -61,3 +61,8 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
response.append(data)
|
response.append(data)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||||
|
response: list[dict] = []
|
||||||
|
|
||||||
|
return response
|
||||||
3
plugins/completers/words_completer/__init__.py
Normal file
3
plugins/completers/words_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/completers/words_completer/__main__.py
Normal file
3
plugins/completers/words_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
53
plugins/completers/words_completer/alt_provider.py
Normal file
53
plugins/completers/words_completer/alt_provider.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# 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
|
||||||
|
from .provider_response_cache import ProviderResponseCache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Provider(GtkSource.CompletionWords):
|
||||||
|
"""
|
||||||
|
This is a Words Completion Provider.
|
||||||
|
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||||
|
"""
|
||||||
|
__gtype_name__ = 'WordsCompletionProvider'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Provider, self).__init__()
|
||||||
|
|
||||||
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
|
|
||||||
|
def do_get_name(self):
|
||||||
|
return 'Words Completion'
|
||||||
|
|
||||||
|
def do_match(self, context):
|
||||||
|
word = self.response_cache.get_word(context)
|
||||||
|
if not word or len(word) < 2: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_get_priority(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def do_activate_proposal(self, proposal, iter_):
|
||||||
|
buffer = iter_.get_buffer()
|
||||||
|
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||||
|
# to insure marker processes inserted text correctly.
|
||||||
|
buffer.is_processing_completion = True
|
||||||
|
return False
|
||||||
|
|
||||||
|
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
|
||||||
7
plugins/completers/words_completer/manifest.json
Normal file
7
plugins/completers/words_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Words Completer",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
40
plugins/completers/words_completer/plugin.py
Normal file
40
plugins/completers/words_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 = "Words Completer",
|
||||||
|
provider = self.provider,
|
||||||
|
language_ids = []
|
||||||
|
)
|
||||||
|
self.message_to("completion", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
71
plugins/completers/words_completer/provider.py
Normal file
71
plugins/completers/words_completer/provider.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Python imports
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GObject
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .provider_response_cache import ProviderResponseCache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||||
|
"""
|
||||||
|
This is a Words Completion Provider.
|
||||||
|
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||||
|
"""
|
||||||
|
# __gtype_name__ = 'WordsCompletionProvider'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Provider, self).__init__()
|
||||||
|
|
||||||
|
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||||
|
|
||||||
|
|
||||||
|
def do_get_name(self):
|
||||||
|
return 'Words Completion'
|
||||||
|
|
||||||
|
def do_match(self, context):
|
||||||
|
word = self.response_cache.get_word(context)
|
||||||
|
if not word or len(word) < 2: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_get_priority(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def do_activate_proposal(self, proposal, iter_):
|
||||||
|
buffer = iter_.get_buffer()
|
||||||
|
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||||
|
# to insure marker processes inserted text correctly.
|
||||||
|
buffer.is_processing_completion = True
|
||||||
|
return False
|
||||||
|
|
||||||
|
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):
|
||||||
|
word = self.response_cache.get_word(context)
|
||||||
|
results = self.response_cache.filter_with_context(context)
|
||||||
|
# results = self.response_cache.filter(word)
|
||||||
|
|
||||||
|
# if not results:
|
||||||
|
# results = self.response_cache.filter_with_context(context)
|
||||||
|
|
||||||
|
proposals = []
|
||||||
|
for entry in results:
|
||||||
|
proposals.append(
|
||||||
|
self.response_cache.create_completion_item(
|
||||||
|
entry["label"],
|
||||||
|
entry["text"],
|
||||||
|
entry["info"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
context.add_proposals(self, proposals, True)
|
||||||
131
plugins/completers/words_completer/provider_response_cache.py
Normal file
131
plugins/completers/words_completer/provider_response_cache.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# Python imports
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
|
||||||
|
|
||||||
|
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||||
|
self.load_as_new_set(event.file.buffer)
|
||||||
|
|
||||||
|
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||||
|
self.matchers[event.file.buffer] = []
|
||||||
|
del self.matchers[event.file.buffer]
|
||||||
|
|
||||||
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||||
|
buffer = event.file.buffer
|
||||||
|
# if self.get_if_in_matched_word_set(buffer): return
|
||||||
|
self.load_as_new_set(buffer)
|
||||||
|
|
||||||
|
|
||||||
|
def filter(self, word: str) -> list[dict]:
|
||||||
|
response: list[dict] = []
|
||||||
|
|
||||||
|
for entry in self.matchers:
|
||||||
|
if not word in entry: continue
|
||||||
|
data = self.matchers[entry]
|
||||||
|
response.append(data)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||||
|
buffer = self.get_iter_correctly(context).get_buffer()
|
||||||
|
word = self.get_word(context).rstrip()
|
||||||
|
|
||||||
|
response: list[dict] = []
|
||||||
|
for entry in self.matchers[buffer]:
|
||||||
|
if not entry.rstrip().startswith(word): continue
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"label": entry,
|
||||||
|
"text": entry,
|
||||||
|
"info": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
response.append(data)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def load_as_new_set(self, buffer):
|
||||||
|
start_itr = buffer.get_start_iter()
|
||||||
|
end_itr = buffer.get_end_iter()
|
||||||
|
data = buffer.get_text(start_itr, end_itr, False)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
self.matchers[buffer] = set()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.matchers[buffer] = self.get_all_words(data)
|
||||||
|
|
||||||
|
def get_if_in_matched_word_set(self, buffer):
|
||||||
|
was_found = False
|
||||||
|
|
||||||
|
if not buffer in self.matchers: return was_found
|
||||||
|
|
||||||
|
insert_itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
end_itr = insert_itr.copy()
|
||||||
|
start_itr = end_itr.copy()
|
||||||
|
|
||||||
|
if not start_itr.starts_word():
|
||||||
|
start_itr.backward_word_start()
|
||||||
|
|
||||||
|
if not end_itr.ends_word():
|
||||||
|
end_itr.forward_word_end()
|
||||||
|
|
||||||
|
word = buffer.get_text(start_itr, end_itr, False)
|
||||||
|
for _word in self.matchers[buffer]:
|
||||||
|
if not _word.startswith(word): continue
|
||||||
|
was_found = True
|
||||||
|
|
||||||
|
if was_found: return was_found
|
||||||
|
|
||||||
|
self.matchers[buffer].add(word)
|
||||||
|
|
||||||
|
return was_found
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_words(self, data: str):
|
||||||
|
words = set()
|
||||||
|
|
||||||
|
def is_word_char(c):
|
||||||
|
return c.isalnum() or c == '_'
|
||||||
|
|
||||||
|
size = len(data)
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while i < size:
|
||||||
|
# Skip non-word characters
|
||||||
|
while i < size and not is_word_char(data[i]):
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
start = i
|
||||||
|
# Consume word characters
|
||||||
|
while i < size and is_word_char(data[i]):
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
word = data[start:i]
|
||||||
|
if not word: continue
|
||||||
|
words.add(word)
|
||||||
|
|
||||||
|
return words
|
||||||
@@ -51,7 +51,7 @@ class ProviderResponseCacheBase:
|
|||||||
text: str = "",
|
text: str = "",
|
||||||
info: str = "",
|
info: str = "",
|
||||||
completion: any = None
|
completion: any = None
|
||||||
):
|
) -> dict:
|
||||||
if not label or not text: return
|
if not label or not text: return
|
||||||
|
|
||||||
comp_item = GtkSource.CompletionItem.new()
|
comp_item = GtkSource.CompletionItem.new()
|
||||||
@@ -69,19 +69,51 @@ class ProviderResponseCacheBase:
|
|||||||
|
|
||||||
return comp_item
|
return comp_item
|
||||||
|
|
||||||
def get_word(self, context):
|
def get_all_marks(self, buffer):
|
||||||
start_iter = context.get_iter()
|
marks = []
|
||||||
end_iter = None
|
iter_ = buffer.get_start_iter()
|
||||||
|
|
||||||
if not isinstance(start_iter, Gtk.TextIter):
|
while iter_:
|
||||||
_, start_iter = context.get_iter()
|
marks = iter_.get_marks()
|
||||||
|
|
||||||
|
for mark in marks:
|
||||||
|
if mark and mark not in marks:
|
||||||
|
marks.append(mark)
|
||||||
|
|
||||||
|
if not iter_.forward_char():
|
||||||
|
break
|
||||||
|
|
||||||
|
return marks
|
||||||
|
|
||||||
|
def get_all_insert_marks(self, buffer):
|
||||||
|
marks = []
|
||||||
|
iter_ = buffer.get_start_iter()
|
||||||
|
|
||||||
|
while iter_:
|
||||||
|
marks = iter_.get_marks()
|
||||||
|
|
||||||
|
for mark in marks:
|
||||||
|
if mark.get_name() and "multi_insert_" in mark.get_name():
|
||||||
|
marks.append(mark)
|
||||||
|
|
||||||
|
if not iter_.forward_char():
|
||||||
|
break
|
||||||
|
|
||||||
|
return marks
|
||||||
|
|
||||||
|
def get_word(self, context) -> str:
|
||||||
|
start_iter = self.get_iter_correctly(context)
|
||||||
end_iter = start_iter.copy()
|
end_iter = start_iter.copy()
|
||||||
|
|
||||||
if not start_iter.starts_word():
|
if not start_iter.starts_word():
|
||||||
start_iter.backward_word_start()
|
start_iter.backward_word_start()
|
||||||
|
|
||||||
|
if not end_iter.ends_word():
|
||||||
end_iter.forward_word_end()
|
end_iter.forward_word_end()
|
||||||
|
|
||||||
buffer = start_iter.get_buffer()
|
buffer = start_iter.get_buffer()
|
||||||
|
|
||||||
return buffer.get_text(start_iter, end_iter, False)
|
return buffer.get_text(start_iter, end_iter, False)
|
||||||
|
|
||||||
|
def get_iter_correctly(self, context):
|
||||||
|
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
|
||||||
|
|||||||
@@ -45,10 +45,13 @@ class CompletionController(ControllerBase):
|
|||||||
def register_completer(self, completer: GtkSource.Completion):
|
def register_completer(self, completer: GtkSource.Completion):
|
||||||
self._completers.append(completer)
|
self._completers.append(completer)
|
||||||
|
|
||||||
completer.add_provider(self.words_provider)
|
# completer.add_provider(self.words_provider)
|
||||||
for provider in self._providers.values():
|
for provider in self._providers.values():
|
||||||
completer.add_provider(provider)
|
completer.add_provider(provider)
|
||||||
|
|
||||||
|
def unregister_completer(self, completer: GtkSource.Completion):
|
||||||
|
self._completers.remove(completer)
|
||||||
|
|
||||||
def register_provider(
|
def register_provider(
|
||||||
self,
|
self,
|
||||||
provider_name: str,
|
provider_name: str,
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class SourceViewsMultiInsertState(MarkEventsMixin):
|
|||||||
if not self.insert_markers: return False
|
if not self.insert_markers: return False
|
||||||
|
|
||||||
buffer = file.buffer
|
buffer = file.buffer
|
||||||
|
if buffer.is_processing_completion:
|
||||||
|
self.insert_completion_text(buffer, text)
|
||||||
|
return True
|
||||||
|
|
||||||
# freeze buffer and insert to each mark (if any)
|
# freeze buffer and insert to each mark (if any)
|
||||||
buffer.block_insert_after_signal()
|
buffer.block_insert_after_signal()
|
||||||
@@ -49,6 +52,32 @@ class SourceViewsMultiInsertState(MarkEventsMixin):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def insert_completion_text(self, buffer, text):
|
||||||
|
buffer.is_processing_completion = False
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
end_itr = buffer.get_iter_at_mark(mark)
|
||||||
|
start_itr = end_itr.copy()
|
||||||
|
|
||||||
|
if not start_itr.starts_word():
|
||||||
|
start_itr.backward_word_start()
|
||||||
|
|
||||||
|
if not end_itr.ends_word():
|
||||||
|
end_itr.forward_word_end()
|
||||||
|
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
buffer.insert(end_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):
|
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
||||||
buffer = source_view.get_buffer()
|
buffer = source_view.get_buffer()
|
||||||
|
|
||||||
@@ -95,7 +124,7 @@ class SourceViewsMultiInsertState(MarkEventsMixin):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
is_future = key_mapper._key_release_event(eve)
|
is_future = key_mapper._key_release_event(eve)
|
||||||
if is_future: return False
|
if is_future: return True
|
||||||
|
|
||||||
command = key_mapper._key_press_event(eve)
|
command = key_mapper._key_press_event(eve)
|
||||||
if not command: return False
|
if not command: return False
|
||||||
@@ -108,7 +137,7 @@ class SourceViewsMultiInsertState(MarkEventsMixin):
|
|||||||
command = key_mapper._key_release_event(eve)
|
command = key_mapper._key_release_event(eve)
|
||||||
is_past = key_mapper._key_press_event(eve)
|
is_past = key_mapper._key_press_event(eve)
|
||||||
|
|
||||||
if is_past: return False
|
if is_past: return True
|
||||||
if not command: return False
|
if not command: return False
|
||||||
|
|
||||||
source_view.command.exec(command)
|
source_view.command.exec(command)
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ class SourceBuffer(GtkSource.Buffer):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SourceBuffer, self).__init__()
|
super(SourceBuffer, self).__init__()
|
||||||
|
|
||||||
|
self.is_processing_completion: bool = False
|
||||||
|
|
||||||
self._handler_ids = []
|
self._handler_ids = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user