Completion providfer efforts; Snippits stubbing message

This commit is contained in:
itdominator 2023-11-08 23:52:23 -06:00
parent 5280667789
commit 37bff1eb3d
10 changed files with 185 additions and 66 deletions

View File

@ -48,6 +48,7 @@ class LSPController:
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(server_proc.stdin, server_proc.stdout)
callbacks = {
"window/showMessage": print,
"textDocument/symbolStatus": print,
"textDocument/publishDiagnostics": self._blame,
}
@ -117,6 +118,41 @@ class LSPController:
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(line, offset)
)
return []
def do_change(self, language_id, line, start, end, text):
if language_id in self.lsp_clients.keys():
start_pos = pylspclient.lsp_structs.Position(line, start.get_line_offset())
end_pos = pylspclient.lsp_structs.Position(line, end.get_line_offset())
range_info = pylspclient.lsp_structs.Range(start_pos, end_pos)
text_length = len(text)
change_event = pylspclient.lsp_structs.TextDocumentContentChangeEvent(range_info, text_length, text)
return self.lsp_clients[language_id].didChange( None, change_event )
return []
def do_completion(self, language_id, uri, line, offset, _char, is_invoked = False):
if language_id in self.lsp_clients.keys():
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter
if _char in [".", " "]:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter
elif is_invoked:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.Invoked
else:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerForIncompleteCompletions
return self.lsp_clients[language_id].completion(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(line, offset),
pylspclient.lsp_structs.CompletionContext(trigger, _char)
)
return []
def load_lsp_server(self, language_id):
if not language_id in self.lsp_servers_config.keys():

View File

@ -1,8 +1,10 @@
# Python imports
import os
import json
import threading
# Lib imports
from gi.repository import GLib
# Application imports
@ -12,7 +14,6 @@ from .lsp_controller import LSPController
class LSPPliginException(Exception):
...
@ -27,6 +28,8 @@ class Plugin(PluginBase):
self.lsp_config_path: str = os.path.dirname(os.path.realpath(__file__)) + "/../../lsp_servers_config.json"
self.lsp_servers_config: dict = {}
self.lsp_controller = None
self.timer = None
def generate_reference_ui_element(self):
...
@ -39,63 +42,76 @@ class Plugin(PluginBase):
text = f"LSP NOT Enabled.\nFile:\n\t{self.lsp_config_path}\ndoes no exsist..."
self._event_system.emit("bubble_message", ("warning", self.name, text,))
return
self.lsp_controller = LSPController(self.lsp_servers_config)
self.inner_subscribe_to_events()
if len(self.lsp_servers_config.keys()) > 0:
self.lsp_controller = LSPController(self.lsp_servers_config)
self.inner_subscribe_to_events()
def subscribe_to_events(self):
...
def inner_subscribe_to_events(self):
self._event_system.subscribe("shutting_down", self._shutting_down)
self._event_system.subscribe("buffer_changed", self._buffer_changed)
self._event_system.subscribe("textDocument/didChange", self._buffer_changed)
self._event_system.subscribe("textDocument/didOpen", self.lsp_controller.do_open)
self._event_system.subscribe("textDocument/didSave", self.lsp_controller.do_save)
self._event_system.subscribe("textDocument/didClose", self.lsp_controller.do_close)
self._event_system.subscribe("textDocument/definition", self._do_goto)
self._event_system.subscribe("textDocument/completion", self.completion)
def _shutting_down(self):
if self.lsp_controller:
self.lsp_controller._shutting_down()
self.lsp_controller._shutting_down()
def cancel_timer(self):
if self.timer:
self.timer.cancel()
GLib.idle_remove_by_data(None)
def _buffer_changed(self, buffer):
# self._do_completion()
...
def delay_completion_glib(self, source_view, context, callback):
GLib.idle_add(self._do_completion, source_view, context, callback)
def _do_completion(self, is_invoked = False):
fpath = self._active_src_view.get_current_filepath()
if not fpath: return
uri = fpath.get_uri()
iter = self._buffer.get_iter_at_mark( self._buffer.get_insert() )
line = iter.get_line()
offset = iter.get_line_offset()
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter
_char = iter.get_char()
trigger = None
if _char in [".", " "]:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter
elif is_invoked:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.Invoked
else:
trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerForIncompleteCompletions
result = self.lsp_controller.completion(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(line, offset),
pylspclient.lsp_structs.CompletionContext(trigger, _char)
)
def delay_completion(self, source_view, context, callback):
self.timer = threading.Timer(0.8, self.delay_completion_glib, (source_view, context, callback,))
self.timer.daemon = True
self.timer.start()
if result.items:
for item in result.items:
print(item.label)
else:
print(result.label)
def _buffer_changed(self, language_id, buffer):
iter = buffer.get_iter_at_mark( buffer.get_insert() )
line = iter.get_line()
start = iter.copy()
end = iter.copy()
start.backward_line()
start.forward_line()
end.forward_to_line_end()
text = buffer.get_text(start, end, include_hidden_chars = False)
result = self.lsp_controller.do_change(language_id, line, start, end, text)
# print(result)
def completion(self, source_view, context, callback):
self.cancel_timer()
self.delay_completion(source_view, context, callback)
def _do_completion(self, source_view, context, callback):
filepath = source_view.get_current_filepath()
if not filepath: return
uri = filepath.get_uri()
buffer = source_view.get_buffer()
iter = buffer.get_iter_at_mark( buffer.get_insert() )
line = iter.get_line() + 1
_char = iter.get_char()
if iter.backward_char():
_char = iter.get_char()
offset = iter.get_line_offset()
result = self.lsp_controller.do_completion(source_view.get_filetype(), uri, line, offset, _char)
callback(context, result)
def _do_goto(self, language_id, uri, line, offset):
results = self.lsp_controller.do_goto(language_id, uri, line, offset)
@ -105,5 +121,4 @@ class Plugin(PluginBase):
file = result.uri[7:]
line = result.range.end.line
message = f"FILE|{file}:{line}"
self._event_system.emit("post_file_to_ipc", message)
self._event_system.emit("post_file_to_ipc", message)

View File

@ -41,7 +41,7 @@ class LspEndpoint(threading.Thread):
params = jsonrpc_message.get("params")
if method:
if rpc_id:
if rpc_id is not None:
if method not in self.method_callbacks:
raise lsp_structs.ResponseError(
lsp_structs.ErrorCodes.MethodNotFound,

View File

@ -436,7 +436,7 @@ class CompletionItem(object):
detail = None, \
documentation = None, \
deprecated = None, \
presented = None, \
preselect = None, \
sortText = None, \
filterText = None, \
insertText = None, \
@ -455,7 +455,7 @@ class CompletionItem(object):
:param str detail: A human-readable string with additional information about this item, like type or symbol information.
:param tr ocumentation: A human-readable string that represents a doc-comment.
:param bool deprecated: Indicates if this item is deprecated.
:param bool presented: Select this item when showing. Note: that only one completion item can be selected and that the
:param bool preselect: Select this item when showing. Note: that only one completion item can be selected and that the
tool / client decides which item that is. The rule is that the first item of those that match best is selected.
:param str sortText: A string that should be used when comparing this item with other items. When `falsy` the label is used.
:param str filterText: A string that should be used when filtering a set of completion items. When `falsy` the label is used.
@ -487,7 +487,7 @@ class CompletionItem(object):
self.detail = detail
self.documentation = documentation
self.deprecated = deprecated
self.presented = presented
self.preselect = preselect
self.sortText = sortText
self.filterText = filterText
self.insertText = insertText
@ -530,7 +530,7 @@ class CompletionItemKind(enum.Enum):
class CompletionList(object):
"""
Represents a collection of [completion items](#CompletionItem) to be presented in the editor.
Represents a collection of [completion items](#CompletionItem) to be preselect in the editor.
"""
def __init__(self, isIncomplete, items):
"""

View File

@ -99,4 +99,5 @@ class Plugin(PluginBase):
body = self.snippet_data[self.active_snippit_group][key]["body"]
snippits.append(body)
print(snippits)
# print(snippits)
print("Snippits Plugin: _handle_update > results > stub...")

View File

@ -0,0 +1,73 @@
# 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 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, 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):
event_system.emit("textDocument/completion", (self._source_view, context, self.do_populate))
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):
proposals = []
if result:
if result.items:
for item in result.items:
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label(item.label)
comp_item.set_text(item.textEdit)
comp_item.set_icon( self.get_icon_for_type(item.kind) )
comp_item.set_info(item.documentation)
proposals.append(comp_item)
else:
comp_item = GtkSource.CompletionItem.new()
comp_item.set_label(item.label)
comp_item.set_text(item.textEdit)
comp_item.set_icon( self.get_icon_for_type(item.kind) )
comp_item.set_info(item.documentation)
proposals.append(comp_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

View File

@ -10,6 +10,7 @@ from gi.repository import Gio
from gi.repository import GtkSource
# Application imports
from ..custom_completion_providers.lsp_completion_provider import LSPCompletionProvider
@ -135,8 +136,7 @@ class FileEventsMixin:
def _document_loaded(self, line: int = 0):
for provider in self._completion.get_providers():
self._completion.remove_provider(provider)
file = self._current_file.get_path()
uri = self._current_file.get_uri()
buffer = self.get_buffer()
@ -145,19 +145,11 @@ class FileEventsMixin:
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)
# TODO: actually load a meaningful provider based on file type...
# example_completion_provider = ExampleCompletionProvider()
# self._completion.add_provider(example_completion_provider)
# py_completion_provider = PythonCompletionProvider(file)
# self._completion.add_provider(py_completion_provider)
self.got_to_line(buffer, line)

View File

@ -14,8 +14,8 @@ from gi.repository import GtkSource
# Application imports
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 .custom_completion_providers.example_completion_provider import ExampleCompletionProvider
# from .custom_completion_providers.python_completion_provider import PythonCompletionProvider

View File

@ -21,10 +21,12 @@ class SourceViewEvents(SourceViewDnDMixin, MarkEventsMixin, FileEventsMixin):
general_style_tag.set_property('scale', 100)
def _is_modified(self, *args):
buffer = self.get_buffer()
buffer = self.get_buffer()
file_type = self.get_filetype()
if not self._loading_file:
event_system.emit("buffer_changed", (buffer, ))
event_system.emit("textDocument/didChange", (file_type, buffer, ))
else:
event_system.emit("buffer_changed_first_load", (buffer, ))

View File

@ -123,4 +123,4 @@ class IPCServer:
logger.error("IPC Socket no longer valid.... Removing.")
os.unlink(self._ipc_address)
except Exception as e:
logger.error( repr(e) )
logger.error( repr(e) )