Implementing own completion UI logic

This commit is contained in:
itdominator 2024-09-25 02:11:39 -05:00
parent dc387d1d4c
commit 3d37a2335a
7 changed files with 181 additions and 16 deletions

View File

@ -11,6 +11,7 @@ from gi.repository import GtkSource
from libs.dto.lsp_message_structs import LSPResponseTypes, LSPResponseRequest, LSPResponseNotification
from .key_input_controller import KeyInputController
from .editor_events import EditorEventsMixin
from ...completion_item import CompletionItem
@ -44,7 +45,7 @@ class EditorControllerMixin(KeyInputController, EditorEventsMixin):
page_num = None
container = None
logger.debug( repr(message) )
logger.debug( f"\n\n{repr(message)}\n\n" )
if isinstance(message, dict):
...
@ -53,14 +54,30 @@ class EditorControllerMixin(KeyInputController, EditorEventsMixin):
if type(message.result) is dict:
keys = message.result.keys()
if "items" in keys: # completion
completion = source_view.get_completion()
providers = completion.get_providers()
if "items" in keys: # completion
if source_view.completion_view.get_parent():
source_view.remove(source_view.completion_view)
source_view.completion_view.clear_items()
x, y = self._get_insert_line_xy(source_view)
source_view.add_child_in_window(source_view.completion_view, Gtk.TextWindowType.WIDGET, x, y)
for item in message.result["items"]:
ci = CompletionItem()
ci.populate_completion_item(item)
source_view.completion_view.add_completion_item(ci)
source_view.completion_view.show_all()
# completion = source_view.get_completion()
# providers = completion.get_providers()
# for provider in providers:
# if provider.__class__.__name__ == 'LSPCompletionProvider':
# source_view.completion_items = message.result["items"]
# source_view.emit("show-completion")
for provider in providers:
if provider.__class__.__name__ == 'LSPCompletionProvider':
source_view.completion_items = message.result["items"]
source_view.emit("show-completion")
if "result" in keys:
...
@ -77,4 +94,23 @@ class EditorControllerMixin(KeyInputController, EditorEventsMixin):
if message.method == "textDocument/publshDiagnostics":
...
source_view = None
source_view = None
# Gotten logic from:
# https://stackoverflow.com/questions/7139645/find-the-cursor-position-on-a-gtksourceview-window
def _get_insert_line_xy(self, source_view):
buffer = source_view.get_buffer()
iter = buffer.get_iter_at_mark( buffer.get_insert() )
iter_loc = source_view.get_iter_location(iter)
win_loc = source_view.buffer_to_window_coords(Gtk.TextWindowType.WIDGET, iter_loc.x, iter_loc.y)
win = source_view.get_window( Gtk.TextWindowType.WIDGET )
view_pos = win.get_position()
xx = win_loc[0] + view_pos[0]
yy = win_loc[1] + view_pos[1] + iter_loc.height
return xx, yy

View File

@ -73,6 +73,9 @@ class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
if "insertText" in keys:
comp_item.set_text(item["insertText"])
if "additionalTextEdits" in keys:
comp_item.additionalTextEdits = item["additionalTextEdits"]
return comp_item

View File

@ -47,6 +47,10 @@ class KeyInputController:
if keyname in [ "Up", "Down", "Left", "Right" ]:
return True
if keyname in [ "Return", "Enter", "Up", "Down" ]:
if self.completion_view.get_parent() and self.completion_view.is_visible():
return True
if len(self._multi_insert_marks) > 0:
if keyname == "BackSpace":
@ -125,6 +129,22 @@ class KeyInputController:
self.keyboard_clear_marks()
if keyname in [ "Return", "Enter", "Up", "Down", "Left", "Right" ]:
if self.completion_view.get_parent() and self.completion_view.is_visible():
if keyname in {"Return", "Enter"}:
self.completion_view.activate_completion()
if keyname == "UP":
self.completion_view.move_selection_up()
if keyname == "Down":
self.completion_view.move_selection_down()
if keyname == "Left":
self.remove( self.completion_view )
if keyname == "Right":
self.remove( self.completion_view )
return True
if keyname in {"Return", "Enter"}:
if len(self._multi_insert_marks) > 0:
self.begin_user_action(buffer)

View File

@ -149,12 +149,12 @@ class FileEventsMixin:
event_system.emit("textDocument/didOpen", (self._current_filetype, uri, self.get_text()))
word_completion = GtkSource.CompletionWords.new("word_completion")
word_completion.register(buffer)
self._completion.add_provider(word_completion)
# word_completion = GtkSource.CompletionWords.new("word_completion")
# 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)
self.got_to_line(buffer, line)
event_system.emit("buffer_changed_first_load", (buffer, ))

View File

@ -17,6 +17,7 @@ from .source_view_controller import SourceViewControllerMixin
# from .custom_completion_providers.example_completion_provider import ExampleCompletionProvider
# from .custom_completion_providers.python_completion_provider import PythonCompletionProvider
from ...completion_view import CompletionView
@ -46,9 +47,11 @@ class SourceView(SourceViewControllerMixin, GtkSource.View):
self._px_value = settings.theming.default_zoom
self._multi_insert_marks = []
self.completion_items = []
self.freeze_multi_line_insert = False
self.completion_view = CompletionView()
# self.completion_items = []
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
@ -117,4 +120,4 @@ class SourceView(SourceViewControllerMixin, GtkSource.View):
self._timer.start()
def _clear_cut_buffer(self):
self._cut_buffer = ""
self._cut_buffer = ""

View File

@ -0,0 +1,44 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
class CompletionItem(Gtk.Button):
def __init__(self):
super(CompletionItem, self).__init__()
self.insertText: str = ""
self.additionalTextEdits: [] = []
self._setup_styling()
self._setup_signals()
self.show()
def _setup_styling(self):
ctx = self.get_style_context()
ctx.add_class("completion-item")
def _setup_signals(self):
self.connect("clicked", self._do_completion)
def populate_completion_item(self, item):
keys = item.keys()
self.set_label(item["label"])
if "insertText" in keys:
self.insertText = item["insertText"]
if "additionalTextEdits" in keys:
self.additionalTextEdits = item["additionalTextEdits"]
def _do_completion(self, button):
...

View File

@ -0,0 +1,59 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .completion_item import CompletionItem
class CompletionView(Gtk.ScrolledWindow):
def __init__(self):
super(CompletionView, self).__init__()
self.button_box = None
self._setup_styling()
self._setup_signals()
self._load_widgets()
self.show_all()
def _setup_styling(self):
ctx = self.get_style_context()
ctx.add_class("completion-view")
self.set_size_request(320, 320)
def _setup_signals(self):
...
def _load_widgets(self):
viewport = Gtk.Viewport()
self.button_box = Gtk.Box()
self.button_box.set_orientation( Gtk.Orientation.VERTICAL )
self.button_box.set_hexpand( True )
viewport.add(self.button_box)
self.add(viewport)
def add_completion_item(self, item: CompletionItem):
self.button_box.add(item)
def clear_items(self):
for child in self.button_box.get_children():
self.button_box.remove(child)
def activate_completion(self):
...
def move_selection_up(self):
...
def move_selection_down(self):
...