From bc47275e5792f12cf865efb035dde49d62d213f7 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 16 Sep 2024 02:03:16 -0500 Subject: [PATCH] Initial display logic of completion request --- .../base/notebook/editor_controller.py | 78 +++++++-------- .../_lsp_completion_provider.py | 98 +++++++++++++++++++ .../lsp_completion_provider.py | 34 +++++-- .../mixins/source_file_events_mixin.py | 10 +- 4 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 src/core/widgets/base/sourceview/custom_completion_providers/_lsp_completion_provider.py diff --git a/src/core/widgets/base/notebook/editor_controller.py b/src/core/widgets/base/notebook/editor_controller.py index 8f6da74..51d0071 100644 --- a/src/core/widgets/base/notebook/editor_controller.py +++ b/src/core/widgets/base/notebook/editor_controller.py @@ -1,6 +1,11 @@ # 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 # Application imports from libs.dto.lsp_message_structs import LSPResponseTypes, LSPResponseRequest, LSPResponseNotification @@ -39,60 +44,43 @@ class EditorControllerMixin(KeyInputController, EditorEventsMixin): page_num = None container = None - # logger.debug( repr(message) ) + logger.debug( repr(message) ) if isinstance(message, dict): ... - if isinstance(message, LSPResponseRequest): + if hasattr(message, "result"): keys = message.result.keys() + if "items" in keys: - self.handle_completion(message.result["items"]) + buffer = source_view.get_buffer() + completion = source_view.get_completion() + providers = completion.get_providers() + + for provider in providers: + if provider.__class__.__name__ == 'LSPCompletionProvider': + # context = completion.create_context( buffer.get_iter_at_mark( buffer.get_insert() ) ) + # context = completion.create_context( None ) + # provider.do_populate(context, message.result["items"]) + + box = Gtk.Box() + box.set_homogeneous(True) + # iter = buffer.get_iter_at_mark( buffer.get_insert() ) + # rects, recte = source_view.get_cursor_locations(iter) + rect = source_view.get_allocation() + + box.set_orientation( Gtk.Orientation.VERTICAL ) + for item in message.result["items"]: + box.add( provider.create_completion_item_button(item) ) + + box.show_all() + source_view.add_child_in_window(box, Gtk.TextWindowType.WIDGET, rect.width - 200, rect.height / 2) + if "result" in keys: ... - if isinstance(message, LSPResponseNotification): + if hasattr(message, "method"): if message.method == "textDocument/publshDiagnostics": ... - source_view = None - - - # export const Text = 1; - # export const Method = 2; - # export const Function = 3; - # export const Constructor = 4; - # export const Field = 5; - # export const Variable = 6; - # export const Class = 7; - # export const Interface = 8; - # export const Module = 9; - # export const Property = 10; - # export const Unit = 11; - # export const Value = 12; - # export const Enum = 13; - # export const Keyword = 14; - # export const Snippet = 15; - # export const Color = 16; - # export const File = 17; - # export const Reference = 18; - # export const Folder = 19; - # export const EnumMember = 20; - # export const Constant = 21; - # export const Struct = 22; - # export const Event = 23; - # export const Operator = 24; - # export const TypeParameter = 25; - - def handle_completion(self, items): - print() - print() - print() - print(len(items)) - print() - print() - print() - for item in items: - if item["kind"] in [2, 3, 4, 5, 6, 7, 8, 10, 15]: - # print(item) - ... \ No newline at end of file + source_view = None \ No newline at end of file diff --git a/src/core/widgets/base/sourceview/custom_completion_providers/_lsp_completion_provider.py b/src/core/widgets/base/sourceview/custom_completion_providers/_lsp_completion_provider.py new file mode 100644 index 0000000..dab2374 --- /dev/null +++ b/src/core/widgets/base/sourceview/custom_completion_providers/_lsp_completion_provider.py @@ -0,0 +1,98 @@ +# 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, source_view): + GObject.Object.__init__(self) + + self._theme = Gtk.IconTheme.get_default() + self._source_view = source_view + + + 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) + 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, result = None): + result = event_system.emit_and_await("textDocument/completion", (self._source_view,)) + proposals = [] + + if result: + if not result.items is None: + for item in result.items: + proposals.append( self.create_completion_item(item) ) + else: + proposals.append( self.create_completion_item(result) ) + + 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() + 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 \ No newline at end of file diff --git a/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py b/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py index dab2374..cd76864 100644 --- a/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py +++ b/src/core/widgets/base/sourceview/custom_completion_providers/lsp_completion_provider.py @@ -25,7 +25,7 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): self._theme = Gtk.IconTheme.get_default() self._source_view = source_view - + def do_get_name(self): return "LSP Code Completion" @@ -54,16 +54,13 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): def do_get_activation(self): return GtkSource.CompletionActivation.INTERACTIVE - def do_populate(self, context, result = None): - result = event_system.emit_and_await("textDocument/completion", (self._source_view,)) + def do_populate(self, context, items = None): + # result = event_system.emit_and_await("textDocument/completion", (self._source_view,)) proposals = [] - if result: - if not result.items is None: - for item in result.items: - proposals.append( self.create_completion_item(item) ) - else: - proposals.append( self.create_completion_item(result) ) + if items: + for item in items: + proposals.append( self.create_completion_item(item) ) context.add_proposals(self, proposals, True) @@ -80,7 +77,24 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider): return None - def create_completion_item(self, item): + + + def create_completion_item_button(self, item): + comp_item = Gtk.Box() + button = Gtk.Button(label = item["label"]) + keys = item.keys() + + if "insertText" in keys: + button.set_tooltip_text( item["insertText"] ) + + button.set_hexpand(True) + comp_item.add(button) + return comp_item + + + + + def _create_completion_item(self, item): comp_item = GtkSource.CompletionItem.new() comp_item.set_label(item.label) diff --git a/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py b/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py index 213f0cb..23c898b 100644 --- a/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py +++ b/src/core/widgets/base/sourceview/mixins/source_file_events_mixin.py @@ -11,8 +11,8 @@ from gi.repository import Gio from gi.repository import GtkSource # Application imports -# from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider -from ..custom_completion_providers.python_completion_provider import PythonCompletionProvider +from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider +# from ..custom_completion_providers.python_completion_provider import PythonCompletionProvider class FileEventsMixin: @@ -153,12 +153,12 @@ class FileEventsMixin: word_completion.register(buffer) self._completion.add_provider(word_completion) - # lsp_completion_provider = LSPCompletionProvider(self) - # self._completion.add_provider(lsp_completion_provider) + lsp_completion_provider = LSPCompletionProvider(self) + self._completion.add_provider(lsp_completion_provider) # if self._current_filetype in ("python", "python3"): # py_lsp_completion_provider = PythonCompletionProvider(uri) # self._completion.add_provider(py_lsp_completion_provider) self.got_to_line(buffer, line) - event_system.emit("buffer_changed_first_load", (buffer, )) \ No newline at end of file + event_system.emit("buffer_changed_first_load", (buffer, ))