Compare commits
32 Commits
99dc917de3
...
release/ne
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c3de1334a | |||
| 41f3501e1f | |||
| 12b5fe7304 | |||
| d8e0185d1c | |||
| fd1f5b8d64 | |||
| 69e766dc28 | |||
| 5911f37449 | |||
| 6e46279da4 | |||
| d90415bffc | |||
| 62a866d9bb | |||
| dc2997ec16 | |||
| 70877a7ee1 | |||
| cb73f6b3b0 | |||
| e6eaa1d83c | |||
| 62731ae766 | |||
| b5cec0d049 | |||
| c821f30880 | |||
| 13908d7ba7 | |||
| ec69d4db73 | |||
| 511138316a | |||
| d6e0823e21 | |||
| 54e7b58c24 | |||
| 77a3b71d31 | |||
| 21dd86ad3d | |||
| fea303c898 | |||
| e8653cd116 | |||
| 5e28fb1e5c | |||
| 609eaa8246 | |||
| 71bab687d7 | |||
| 060f68237b | |||
| ee5f66fbbb | |||
| 7ee484f0c0 |
32
README.md
32
README.md
@@ -1,25 +1,13 @@
|
|||||||
# Python-With-Gtk-Template
|
# Newton
|
||||||
A template project for Python with Gtk applications.
|
A Python + Gtk 3 based quasi-IDE.
|
||||||
|
|
||||||
### Requirements
|
|
||||||
* PyGObject (Gtk introspection library)
|
|
||||||
* pygobject-stubs (For actually getting pylsp or python-language-server to auto complete in LSPs. Do if GTK3 --no-cache-dir --config-settings=config=Gtk3,Gdk3,Soup2)
|
|
||||||
* pyxdg (Desktop ".desktop" file parser)
|
|
||||||
* setproctitle (Define process title to search and kill more easily)
|
|
||||||
* sqlmodel (SQL databases and is powered by Pydantic and SQLAlchemy)
|
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
* pyrightconfig.json can prompt IDEs that use pyright lsp on where imports are located- look at venvPath and venv. "venvPath" is parent path of "venv" where "venv" is just the name of the folder under the parent path that is the python created venv.
|
[TODO](TODO.md)
|
||||||
* Move respetive sub folder content under user_config to the same places in Linux. Though, user/share/<app name> can go to ~/.config folder if prefered.
|
|
||||||
* In additiion, place the plugins folder in the same app folder you moved to /usr/share/<app name> or ~/.config/<app name> .
|
|
||||||
There are a "\<change_me\>" strings and files that need to be set according to your app's name located at:
|
|
||||||
* \_\_builtins\_\_.py
|
|
||||||
* user_config/bin/app_name
|
|
||||||
* user_config/usr/share/app_name
|
|
||||||
* user_config/usr/share/app_name/icons/app_name.png
|
|
||||||
* user_config/usr/share/app_name/icons/app_name-64x64.png
|
|
||||||
* user_config/usr/share/applications/app_name.desktop
|
|
||||||
|
|
||||||
|
### Images
|
||||||
For the user_config, after changing names and files, copy all content to their respective destinations.
|

|
||||||
The logic follows Debian Dpkg packaging and its placement logic.
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|||||||
15
TODO.md
Normal file
15
TODO.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
___
|
||||||
|
### Add
|
||||||
|
1. Add <Ctrl\>i to **lsp_manager** to list who implements xyz
|
||||||
|
|
||||||
|
___
|
||||||
|
### Change
|
||||||
|
1. Make **telescope** plugin a generic base to allow query mode additions through plugins
|
||||||
|
|
||||||
|
___
|
||||||
|
### Fix
|
||||||
|
- Fix LSP WS Server to Godot LSP Server communication
|
||||||
|
- Fix <Ctrl\>z in multi-insert mode being funky. Insure updates happen on block level.
|
||||||
|
I.E, maybe push updates to queue to insure block undo/redo?
|
||||||
|
|
||||||
|
___
|
||||||
BIN
images/pic1.png
Normal file
BIN
images/pic1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
images/pic2.png
Normal file
BIN
images/pic2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
images/pic3.png
Normal file
BIN
images/pic3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
images/pic4.png
Normal file
BIN
images/pic4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
images/pic5.png
Normal file
BIN
images/pic5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 951 KiB |
BIN
images/pic6.png
Normal file
BIN
images/pic6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 901 KiB |
@@ -39,6 +39,24 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "autopairs",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "held",
|
||||||
|
binding = [
|
||||||
|
"'", "`", "[", "]",
|
||||||
|
'<Shift>"',
|
||||||
|
'<Shift>(',
|
||||||
|
'<Shift>)',
|
||||||
|
'<Shift>{',
|
||||||
|
'<Shift>}'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
autopairs = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,19 @@ class Plugin(PluginCode):
|
|||||||
colorize.handle_colorize(event.buffer)
|
colorize.handle_colorize(event.buffer)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
event = Event_Factory.create_event("register_command",
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
event = Event_Factory.create_event("get_source_views")
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
for view in event.response:
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
colorize.clear_color_tags(buffer)
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
command_name = "tggle_colorize",
|
command_name = "tggle_colorize",
|
||||||
command = Handler,
|
command = Handler,
|
||||||
binding_mode = "released",
|
binding_mode = "released",
|
||||||
@@ -36,6 +48,7 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -14,53 +14,94 @@ class Commenter(CodeCommentTagsMixin):
|
|||||||
|
|
||||||
def keyboard_tggl_comment(self, buffer):
|
def keyboard_tggl_comment(self, buffer):
|
||||||
language = buffer.get_language()
|
language = buffer.get_language()
|
||||||
if language is None: return
|
if not language: return
|
||||||
|
|
||||||
start_tag, end_tag = self.get_comment_tags(language)
|
start_tag, end_tag = self.get_comment_tags(language)
|
||||||
# Note: Only handling line comment tag- no block comment option
|
if not (start_tag or end_tag): return
|
||||||
if not start_tag and not end_tag: return
|
|
||||||
|
|
||||||
|
start_tag += " "
|
||||||
|
end_tag = end_tag or ""
|
||||||
bounds = buffer.get_selection_bounds()
|
bounds = buffer.get_selection_bounds()
|
||||||
if bounds:
|
|
||||||
self._bounds_comment(
|
(self._bounds_comment if bounds else self._line_comment)(
|
||||||
start_tag, end_tag, bounds, buffer
|
buffer, start_tag, end_tag, bounds
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _line_comment(self, buffer, start_tag: str, end_tag: str, bounds):
|
||||||
|
start = buffer.get_iter_at_mark(buffer.get_insert()).copy()
|
||||||
|
end = start.copy()
|
||||||
|
line, col = start.get_line() + 1, start.get_line_offset()
|
||||||
|
|
||||||
|
if not start.starts_line():
|
||||||
|
start.set_line_offset(0)
|
||||||
|
if not end.ends_line():
|
||||||
|
end.forward_to_line_end()
|
||||||
|
|
||||||
|
text = buffer.get_text(start, end, True)
|
||||||
|
stripped = text.lstrip()
|
||||||
|
indent = text[:-len(stripped)] if stripped else text
|
||||||
|
|
||||||
|
if stripped.startswith(start_tag):
|
||||||
|
stripped = stripped[len(start_tag):].lstrip().replace(end_tag, "", 1)
|
||||||
else:
|
else:
|
||||||
self._line_comment(start_tag, end_tag, buffer)
|
stripped = f"{start_tag}{stripped}{end_tag}"
|
||||||
|
|
||||||
|
|
||||||
def _line_comment(self, start_tag, end_tag, buffer):
|
|
||||||
start_itr = buffer.get_iter_at_mark( buffer.get_insert() ).copy()
|
|
||||||
end_itr = start_itr.copy()
|
|
||||||
if not start_itr.starts_line():
|
|
||||||
start_itr.set_line_offset(0)
|
|
||||||
if not end_itr.ends_line():
|
|
||||||
end_itr.forward_to_line_end()
|
|
||||||
|
|
||||||
text = buffer.get_text(start_itr, end_itr, True)
|
|
||||||
text = text.replace(start_tag, "") if text.startswith(start_tag) else start_tag + text
|
|
||||||
|
|
||||||
buffer.begin_user_action()
|
buffer.begin_user_action()
|
||||||
buffer.delete(start_itr, end_itr)
|
buffer.delete(start, end)
|
||||||
buffer.insert(start_itr, text)
|
buffer.insert(start, indent + stripped)
|
||||||
buffer.end_user_action()
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
buffer.place_cursor(buffer.get_iter_at_line_offset(line, col))
|
||||||
|
|
||||||
def _bounds_comment(self, start_tag, end_tag, bounds, buffer):
|
def _bounds_comment(self, buffer, start_tag: str, end_tag: str, bounds):
|
||||||
start_itr, end_itr = bounds
|
def indent_len(s): return len(s) - len(s.lstrip())
|
||||||
if not start_itr.starts_line():
|
|
||||||
start_itr.set_line_offset(0)
|
|
||||||
if not end_itr.ends_line():
|
|
||||||
end_itr.forward_to_line_end()
|
|
||||||
|
|
||||||
text = buffer.get_text(start_itr, end_itr, True)
|
def insert(line, idx):
|
||||||
text = "\n".join(
|
return f"{line[:idx]}{start_tag}{line[idx:]}{end_tag}"
|
||||||
line.replace(start_tag, "") if line.startswith(start_tag) else start_tag + line
|
|
||||||
for line in text.splitlines()
|
def process(lines):
|
||||||
|
base_indent = min(
|
||||||
|
(indent_len(l) for l in lines if l.strip()),
|
||||||
|
default = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
is_commented = all(
|
||||||
|
l.lstrip().startswith(start_tag)
|
||||||
|
for l in lines if l.strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_commented:
|
||||||
|
return [
|
||||||
|
l.replace(start_tag, "", 1).replace(end_tag, "", 1)
|
||||||
|
if l.lstrip().startswith(start_tag.lstrip())
|
||||||
|
else l
|
||||||
|
for l in lines
|
||||||
|
]
|
||||||
|
|
||||||
|
return [
|
||||||
|
l if not l.strip()
|
||||||
|
else insert(l, base_indent)
|
||||||
|
for l in lines
|
||||||
|
]
|
||||||
|
|
||||||
|
start, end = bounds
|
||||||
|
sline, scol = start.get_line(), start.get_line_offset()
|
||||||
|
eline, ecol = end.get_line(), end.get_line_offset()
|
||||||
|
|
||||||
|
if not start.starts_line():
|
||||||
|
start.set_line_offset(0)
|
||||||
|
if not end.ends_line():
|
||||||
|
end.forward_to_line_end()
|
||||||
|
|
||||||
|
lines = buffer.get_text(start, end, True).splitlines()
|
||||||
|
new_text = "\n".join(process(lines))
|
||||||
|
|
||||||
buffer.begin_user_action()
|
buffer.begin_user_action()
|
||||||
buffer.delete(start_itr, end_itr)
|
buffer.delete(start, end)
|
||||||
buffer.insert(start_itr, text)
|
buffer.insert(start, new_text)
|
||||||
buffer.end_user_action()
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
buffer.select_range(
|
||||||
|
buffer.get_iter_at_line_offset(sline, scol),
|
||||||
|
buffer.get_iter_at_line_offset(eline, ecol),
|
||||||
|
)
|
||||||
|
|||||||
@@ -36,6 +36,16 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "keyboard_tggl_comment",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control>slash"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
97
plugins/code/commands/file_history/autopairs.py
Normal file
97
plugins/code/commands/file_history/autopairs.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Autopairs:
|
||||||
|
def __init__(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def handle_word_wrap(self, buffer, char_str: str):
|
||||||
|
wrap_block = self.get_wrap_block(char_str)
|
||||||
|
if not wrap_block: return
|
||||||
|
|
||||||
|
selection = buffer.get_selection_bounds()
|
||||||
|
if not selection:
|
||||||
|
self.insert_pair(buffer, char_str, wrap_block)
|
||||||
|
return True
|
||||||
|
|
||||||
|
self.wrap_selection(buffer, char_str, wrap_block, selection)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def insert_pair(
|
||||||
|
self, buffer, char_str: str, wrap_block: tuple
|
||||||
|
):
|
||||||
|
buffer.begin_user_action()
|
||||||
|
|
||||||
|
left_block, right_block = wrap_block
|
||||||
|
insert_mark = buffer.get_insert()
|
||||||
|
|
||||||
|
insert_itr = buffer.get_iter_at_mark(insert_mark)
|
||||||
|
buffer.insert(insert_itr, f"{left_block}{right_block}")
|
||||||
|
insert_itr = buffer.get_iter_at_mark( insert_mark )
|
||||||
|
insert_itr.backward_char()
|
||||||
|
|
||||||
|
buffer.place_cursor(insert_itr)
|
||||||
|
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
def wrap_selection(
|
||||||
|
self, buffer, char_str: str, wrap_block: tuple, selection
|
||||||
|
):
|
||||||
|
left_block, \
|
||||||
|
right_block = wrap_block
|
||||||
|
start_itr, \
|
||||||
|
end_itr = selection
|
||||||
|
data = buffer.get_text(
|
||||||
|
start_itr, end_itr, include_hidden_chars = False
|
||||||
|
)
|
||||||
|
start_mark = buffer.create_mark("startclose", start_itr, False)
|
||||||
|
end_mark = buffer.create_mark("endclose", end_itr, True)
|
||||||
|
|
||||||
|
buffer.begin_user_action()
|
||||||
|
|
||||||
|
buffer.insert(start_itr, left_block)
|
||||||
|
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||||
|
buffer.insert(end_itr, right_block)
|
||||||
|
|
||||||
|
start = buffer.get_iter_at_mark(start_mark)
|
||||||
|
end = buffer.get_iter_at_mark(end_mark)
|
||||||
|
|
||||||
|
buffer.select_range(start, end)
|
||||||
|
buffer.delete_mark_by_name("startclose")
|
||||||
|
buffer.delete_mark_by_name("endclose")
|
||||||
|
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
def get_wrap_block(self, char_str) -> tuple:
|
||||||
|
left_block = ""
|
||||||
|
right_block = ""
|
||||||
|
|
||||||
|
match char_str:
|
||||||
|
case "(" | ")":
|
||||||
|
left_block = "("
|
||||||
|
right_block = ")"
|
||||||
|
case "[" | "]":
|
||||||
|
left_block = "["
|
||||||
|
right_block = "]"
|
||||||
|
case "{" | "}":
|
||||||
|
left_block = "{"
|
||||||
|
right_block = "}"
|
||||||
|
case '"':
|
||||||
|
left_block = '"'
|
||||||
|
right_block = '"'
|
||||||
|
case "'":
|
||||||
|
left_block = "'"
|
||||||
|
right_block = "'"
|
||||||
|
case "`":
|
||||||
|
left_block = "`"
|
||||||
|
right_block = "`"
|
||||||
|
case _:
|
||||||
|
return ()
|
||||||
|
|
||||||
|
return left_block, right_block
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Toggle Source View",
|
"name": "File History",
|
||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
65
plugins/code/commands/file_history/plugin.py
Normal file
65
plugins/code/commands/file_history/plugin.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
history: list = []
|
||||||
|
history_size: int = 30
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.RemovedFileEvent):
|
||||||
|
if event.file.ftype == "buffer": return
|
||||||
|
|
||||||
|
if len(history) == history_size:
|
||||||
|
history.pop(0)
|
||||||
|
|
||||||
|
history.append(event.file.fpath)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "file_history_pop",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Shift><Control>t"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Handler:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: any,
|
||||||
|
char_str: str,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: File History")
|
||||||
|
if len(history) == 0: return
|
||||||
|
|
||||||
|
view._on_uri_data_received(
|
||||||
|
[
|
||||||
|
f"file://{history.pop()}"
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .helpers import clear_temp_cut_buffer_delayed, set_temp_cut_buffer_delayed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Handler:
|
||||||
|
@staticmethod
|
||||||
|
def execute(view: GtkSource.View, *args, **kwargs):
|
||||||
|
logger.debug("Command: Cut to Temp Buffer")
|
||||||
|
|
||||||
|
clear_temp_cut_buffer_delayed(view)
|
||||||
|
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
|
||||||
|
if buffer.get_has_selection():
|
||||||
|
start_itr, end_itr = buffer.get_selection_bounds()
|
||||||
|
|
||||||
|
start_itr.set_line_offset(0)
|
||||||
|
|
||||||
|
if not end_itr.ends_line():
|
||||||
|
end_itr.forward_to_line_end()
|
||||||
|
|
||||||
|
if not end_itr.is_end():
|
||||||
|
end_itr.forward_char()
|
||||||
|
else:
|
||||||
|
itr = buffer.get_iter_at_mark(buffer.get_insert())
|
||||||
|
|
||||||
|
start_itr = itr.copy()
|
||||||
|
start_itr.set_line_offset(0)
|
||||||
|
|
||||||
|
end_itr = start_itr.copy()
|
||||||
|
if not end_itr.forward_line():
|
||||||
|
end_itr = buffer.get_end_iter()
|
||||||
|
|
||||||
|
if not hasattr(view, "_cut_buffer"):
|
||||||
|
view._cut_buffer = ""
|
||||||
|
|
||||||
|
text = buffer.get_text(start_itr, end_itr, True)
|
||||||
|
|
||||||
|
if not text.endswith("\n"):
|
||||||
|
text += "\n"
|
||||||
|
|
||||||
|
view._cut_buffer += text
|
||||||
|
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
buffer.place_cursor(start_itr)
|
||||||
|
|
||||||
|
set_temp_cut_buffer_delayed(view)
|
||||||
24
plugins/code/commands/nanoesq_temp_buffer/helpers.py
Normal file
24
plugins/code/commands/nanoesq_temp_buffer/helpers.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def clear_temp_cut_buffer_delayed(view: any):
|
||||||
|
if not hasattr(view, "_cut_temp_timeout_id"): return
|
||||||
|
if not view._cut_temp_timeout_id: return
|
||||||
|
|
||||||
|
GLib.source_remove(view._cut_temp_timeout_id)
|
||||||
|
|
||||||
|
def set_temp_cut_buffer_delayed(view: any):
|
||||||
|
def clear_temp_buffer(view: any):
|
||||||
|
view._cut_buffer = ""
|
||||||
|
view._cut_temp_timeout_id = None
|
||||||
|
return False
|
||||||
|
|
||||||
|
view._cut_temp_timeout_id = GLib.timeout_add(15000, clear_temp_buffer, view)
|
||||||
7
plugins/code/commands/nanoesq_temp_buffer/manifest.json
Normal file
7
plugins/code/commands/nanoesq_temp_buffer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Nanoesq Temp Buffer",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .helpers import clear_temp_cut_buffer_delayed, set_temp_cut_buffer_delayed
|
||||||
|
|
||||||
|
|
||||||
|
class Handler2:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: GtkSource.View,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: Paste Temp Buffer")
|
||||||
|
if not hasattr(view, "_cut_temp_timeout_id"): return
|
||||||
|
if not hasattr(view, "_cut_buffer"): return
|
||||||
|
if not view._cut_buffer: return
|
||||||
|
|
||||||
|
clear_temp_cut_buffer_delayed(view)
|
||||||
|
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
insert_itr = itr.copy()
|
||||||
|
|
||||||
|
buffer.insert(insert_itr, view._cut_buffer, -1)
|
||||||
|
|
||||||
|
set_temp_cut_buffer_delayed(view)
|
||||||
49
plugins/code/commands/nanoesq_temp_buffer/plugin.py
Normal file
49
plugins/code/commands/nanoesq_temp_buffer/plugin.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .cut_to_temp_buffer import Handler
|
||||||
|
from .paste_temp_buffer import Handler2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "cut_to_temp_buffer",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "held",
|
||||||
|
binding = "<Control>k"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "paste_temp_buffer",
|
||||||
|
command = Handler2,
|
||||||
|
binding_mode = "held",
|
||||||
|
binding = "<Control>u"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
3
plugins/code/commands/split_pane/__init__.py
Normal file
3
plugins/code/commands/split_pane/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/code/commands/split_pane/__main__.py
Normal file
3
plugins/code/commands/split_pane/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
77
plugins/code/commands/split_pane/close_split_view.py
Normal file
77
plugins/code/commands/split_pane/close_split_view.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# 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.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
emit_to: callable = None
|
||||||
|
|
||||||
|
def get_source_view(widget):
|
||||||
|
if isinstance(widget, GtkSource.View):
|
||||||
|
return widget
|
||||||
|
|
||||||
|
if isinstance(widget, Gtk.ScrolledWindow):
|
||||||
|
return widget.get_child()
|
||||||
|
|
||||||
|
if isinstance(widget, Gtk.Paned):
|
||||||
|
return get_source_view(widget.get_child1())
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
source_view,
|
||||||
|
char_str,
|
||||||
|
modkeys_states
|
||||||
|
):
|
||||||
|
logger.debug("Command: Close Split Pane")
|
||||||
|
|
||||||
|
scrolled_win = source_view.get_parent()
|
||||||
|
pane = scrolled_win.get_parent()
|
||||||
|
|
||||||
|
if not isinstance(pane, Gtk.Paned): return
|
||||||
|
|
||||||
|
container = pane.get_parent()
|
||||||
|
source_view1 = pane.get_child1()
|
||||||
|
source_view2 = pane.get_child2()
|
||||||
|
|
||||||
|
if scrolled_win == source_view1:
|
||||||
|
remaining = source_view2
|
||||||
|
closing_view = source_view
|
||||||
|
else:
|
||||||
|
remaining = source_view1
|
||||||
|
closing_view = source_view
|
||||||
|
|
||||||
|
remaining_view = get_source_view(remaining)
|
||||||
|
left = closing_view.sibling_left
|
||||||
|
right = closing_view.sibling_right
|
||||||
|
|
||||||
|
if left:
|
||||||
|
left.sibling_right = right
|
||||||
|
|
||||||
|
if right:
|
||||||
|
right.sibling_left = left
|
||||||
|
|
||||||
|
pane.remove(source_view1)
|
||||||
|
pane.remove(source_view2)
|
||||||
|
|
||||||
|
container.remove(pane)
|
||||||
|
container.add(remaining)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"remove_source_view",
|
||||||
|
view = closing_view
|
||||||
|
)
|
||||||
|
emit_to("source_views", event)
|
||||||
|
|
||||||
|
remaining_view.grab_focus()
|
||||||
77
plugins/code/commands/split_pane/create_split_view.py
Normal file
77
plugins/code/commands/split_pane/create_split_view.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
from libs.dto.states import SourceViewStates
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
emit_to: callable = None
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
source_view1,
|
||||||
|
char_str,
|
||||||
|
modkeys_states
|
||||||
|
):
|
||||||
|
logger.debug("Command: Split Pane")
|
||||||
|
|
||||||
|
scrolled_win1 = source_view1.get_parent()
|
||||||
|
container = scrolled_win1.get_parent()
|
||||||
|
pane = Gtk.Paned()
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"create_source_view",
|
||||||
|
state = SourceViewStates.INSERT
|
||||||
|
)
|
||||||
|
emit_to("source_views", event)
|
||||||
|
|
||||||
|
scrolled_win2, \
|
||||||
|
source_view2 = event.response
|
||||||
|
old_sibling_right = None
|
||||||
|
|
||||||
|
if source_view1.sibling_right:
|
||||||
|
old_sibling_right = source_view1.sibling_right
|
||||||
|
|
||||||
|
source_view1.sibling_right = source_view2
|
||||||
|
if old_sibling_right:
|
||||||
|
old_sibling_right.sibling_left = source_view2
|
||||||
|
source_view2.sibling_right = old_sibling_right
|
||||||
|
|
||||||
|
source_view2.sibling_left = source_view1
|
||||||
|
|
||||||
|
pane.set_hexpand(True)
|
||||||
|
pane.set_vexpand(True)
|
||||||
|
pane.set_wide_handle(True)
|
||||||
|
|
||||||
|
container.remove(scrolled_win1)
|
||||||
|
pane.pack1( scrolled_win1, True, True )
|
||||||
|
pane.pack2( scrolled_win2, True, True )
|
||||||
|
container.add(pane)
|
||||||
|
|
||||||
|
def _show(pane, alloc, is_vertical: bool):
|
||||||
|
if is_vertical:
|
||||||
|
pane.set_position(alloc.width / 2)
|
||||||
|
else:
|
||||||
|
pane.set_position(alloc.height / 2)
|
||||||
|
|
||||||
|
pane.disconnect(pane.show_id)
|
||||||
|
|
||||||
|
is_control, is_shift, is_alt = modkeys_states
|
||||||
|
alloc = container.get_allocation()
|
||||||
|
if char_str == "|":
|
||||||
|
pane.show_id = pane.connect("show", _show, alloc, True)
|
||||||
|
pane.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
elif char_str == "\\":
|
||||||
|
pane.show_id = pane.connect("show", _show, alloc, False)
|
||||||
|
pane.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||||
|
|
||||||
|
pane.show_all()
|
||||||
|
|
||||||
|
source_view2.command.exec("new_file")
|
||||||
|
source_view2.grab_focus()
|
||||||
@@ -7,6 +7,7 @@ gi.require_version('GtkSource', '4')
|
|||||||
|
|
||||||
from gi.repository import GtkSource
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
@@ -18,5 +19,4 @@ def execute(
|
|||||||
):
|
):
|
||||||
logger.debug("Command: Focus Left Sibling")
|
logger.debug("Command: Focus Left Sibling")
|
||||||
if not view.sibling_left: return
|
if not view.sibling_left: return
|
||||||
view.sibling_left.get_parent().show()
|
|
||||||
view.sibling_left.grab_focus()
|
view.sibling_left.grab_focus()
|
||||||
@@ -18,5 +18,4 @@ def execute(
|
|||||||
):
|
):
|
||||||
logger.debug("Command: Focus Right Sibling")
|
logger.debug("Command: Focus Right Sibling")
|
||||||
if not view.sibling_right: return
|
if not view.sibling_right: return
|
||||||
view.sibling_right.get_parent().show()
|
|
||||||
view.sibling_right.grab_focus()
|
view.sibling_right.grab_focus()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "LSP Manager",
|
"name": "Split Pane",
|
||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
100
plugins/code/commands/split_pane/plugin.py
Normal file
100
plugins/code/commands/split_pane/plugin.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from . import create_split_view, \
|
||||||
|
close_split_view, \
|
||||||
|
focus_left_sibling, \
|
||||||
|
focus_right_sibling, \
|
||||||
|
move_to_left_sibling, \
|
||||||
|
move_to_right_sibling
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
gemit_to = self.emit_to
|
||||||
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
_create_split_view = create_split_view
|
||||||
|
_close_split_view = close_split_view
|
||||||
|
_create_split_view.emit_to = self.emit_to
|
||||||
|
_close_split_view.emit_to = self.emit_to
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "create_split_view",
|
||||||
|
command = _create_split_view,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = ["<Control>\\", "<Shift><Control>|"]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "close_split_view",
|
||||||
|
command = _close_split_view,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Alt>\\"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "focus_left_sibling",
|
||||||
|
command = focus_left_sibling,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control>Page_Up"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "focus_right_sibling",
|
||||||
|
command = focus_right_sibling,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control>Page_Down"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "move_to_left_sibling",
|
||||||
|
command = move_to_left_sibling,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control><Shift>Up"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "move_to_right_sibling",
|
||||||
|
command = move_to_right_sibling,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control><Shift>Down"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Python imports
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
|
||||||
|
|
||||||
from plugins.plugin_types import PluginCode
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Plugin(PluginCode):
|
|
||||||
def __init__(self):
|
|
||||||
super(Plugin, self).__init__()
|
|
||||||
|
|
||||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
|
||||||
...
|
|
||||||
|
|
||||||
def load(self):
|
|
||||||
event = Event_Factory.create_event("register_command",
|
|
||||||
command_name = "toggle_source_view",
|
|
||||||
command = Handler,
|
|
||||||
binding_mode = "released",
|
|
||||||
binding = "<Shift><Control>h"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.emit_to("source_views", event)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class Handler:
|
|
||||||
@staticmethod
|
|
||||||
def execute(
|
|
||||||
view: any,
|
|
||||||
char_str: str,
|
|
||||||
*args,
|
|
||||||
**kwargs
|
|
||||||
):
|
|
||||||
logger.debug("Command: Toggle Source View")
|
|
||||||
target = view.get_parent()
|
|
||||||
target.hide() if target.is_visible() else target.show()
|
|
||||||
|
|
||||||
if view.sibling_left:
|
|
||||||
target = view.sibling_left.get_parent()
|
|
||||||
target.show()
|
|
||||||
view.sibling_left.grab_focus()
|
|
||||||
|
|
||||||
if view.sibling_right:
|
|
||||||
target = view.sibling_right.get_parent()
|
|
||||||
target.show()
|
|
||||||
view.sibling_right.grab_focus()
|
|
||||||
|
|
||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Example Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_text_inserted(self, event: Code_Event_Types.TextInsertedEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_delete_range(self, event: Code_Event_Types.DeleteRangeEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def filter(self, word: str) -> list[dict]:
|
def filter(self, word: str) -> list[dict]:
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"register_provider",
|
||||||
|
provider_name = "Python Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
|||||||
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 supporting logic to use spaces
|
||||||
# As is it slows down the editor in certain contexts...
|
# As is it slows down the editor in certain contexts...
|
||||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||||
if not (ch in ('_', '.') or ch.isalnum()):
|
if not (ch in ('_', '.') or ch.isalnum()):
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_text_inserted(self, event: Code_Event_Types.TextInsertedEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_delete_range(self, event: Code_Event_Types.DeleteRangeEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def filter(self, word: str) -> list[dict]:
|
def filter(self, word: str) -> list[dict]:
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Snippets Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_text_inserted(self, event: Code_Event_Types.TextInsertedEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def process_file_delete_range(self, event: Code_Event_Types.DeleteRangeEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def filter(self, word: str) -> list[dict]:
|
def filter(self, word: str) -> list[dict]:
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Words Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -35,11 +35,14 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||||
...
|
...
|
||||||
|
|
||||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
def process_file_text_inserted(self, event: Code_Event_Types.TextInsertedEvent):
|
||||||
buffer = event.file.buffer
|
buffer = event.buffer
|
||||||
self._clear_temp_delay()
|
self._clear_temp_delay()
|
||||||
self._set_temp_delay(buffer)
|
self._set_temp_delay(buffer)
|
||||||
|
|
||||||
|
def process_file_delete_range(self, event: Code_Event_Types.DeleteRangeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
def _clear_temp_delay(self):
|
def _clear_temp_delay(self):
|
||||||
if self._temp_timeout_id:
|
if self._temp_timeout_id:
|
||||||
GLib.source_remove(self._temp_timeout_id)
|
GLib.source_remove(self._temp_timeout_id)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Extend Source View Menu",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .source_view_menu import extend_source_view_menu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.PopulateSourceViewPopupEvent):
|
||||||
|
extend_source_view_menu(event.buffer, event.menu)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Python imports
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_case_handle(menuitem, buffer, action):
|
||||||
|
start_itr, \
|
||||||
|
end_itr = buffer.get_selection_bounds()
|
||||||
|
data = buffer.get_text(start_itr, end_itr, False)
|
||||||
|
text = data
|
||||||
|
|
||||||
|
if action == "on_all_upper":
|
||||||
|
text = data.upper()
|
||||||
|
elif action == "on_all_lower":
|
||||||
|
text = data.lower()
|
||||||
|
elif action == "on_invert":
|
||||||
|
text = data.swapcase()
|
||||||
|
elif action == "on_title":
|
||||||
|
text = data.title()
|
||||||
|
elif action == "on_title_strip":
|
||||||
|
text = data.title().replace("-", "").replace("_", "").replace(" ", "")
|
||||||
|
|
||||||
|
buffer.begin_user_action()
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
buffer.insert(start_itr, text)
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def extend_source_view_menu(buffer, menu):
|
||||||
|
if not buffer.get_selection_bounds(): return
|
||||||
|
|
||||||
|
for child in menu.get_children():
|
||||||
|
if not child.get_label() == "C_hange Case": continue
|
||||||
|
menu.remove(child)
|
||||||
|
|
||||||
|
change_case_item = Gtk.MenuItem(label = "Change Case")
|
||||||
|
|
||||||
|
case_menu = Gtk.Menu()
|
||||||
|
au_case_item = Gtk.MenuItem(label = "All Upper Case")
|
||||||
|
al_case_item = Gtk.MenuItem(label = "All Lower Case")
|
||||||
|
inver_case_item = Gtk.MenuItem(label = "Invert Case")
|
||||||
|
title_case_item = Gtk.MenuItem(label = "Title Case")
|
||||||
|
title_strip_case_item = Gtk.MenuItem(label = "Title Strip Case")
|
||||||
|
|
||||||
|
au_case_item.connect("activate", on_case_handle, buffer, "on_all_upper")
|
||||||
|
al_case_item.connect("activate", on_case_handle, buffer, "on_all_lower")
|
||||||
|
inver_case_item.connect("activate", on_case_handle, buffer, "on_invert")
|
||||||
|
title_case_item.connect("activate", on_case_handle, buffer, "on_title")
|
||||||
|
title_strip_case_item.connect("activate", on_case_handle, buffer, "on_title_strip")
|
||||||
|
|
||||||
|
case_menu.append(au_case_item)
|
||||||
|
case_menu.append(al_case_item)
|
||||||
|
case_menu.append(inver_case_item)
|
||||||
|
case_menu.append(title_case_item)
|
||||||
|
case_menu.append(title_strip_case_item)
|
||||||
|
change_case_item.set_submenu(case_menu)
|
||||||
|
|
||||||
|
menu.append(change_case_item)
|
||||||
@@ -17,16 +17,28 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
|
|
||||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
if isinstance(event, Code_Event_Types.TextChangedEvent):
|
if not isinstance(event, Code_Event_Types.FocusedViewEvent): return
|
||||||
event.file.check_file_on_disk()
|
event = Event_Factory.create_event(
|
||||||
|
"get_file", buffer = event.view.get_buffer()
|
||||||
|
)
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
if event.file.is_deleted():
|
file = event.response
|
||||||
file_is_deleted(event)
|
if not file: return
|
||||||
elif event.file.is_externally_modified():
|
if file.ftype == "buffer": return
|
||||||
file_is_externally_modified(event)
|
|
||||||
|
file.check_file_on_disk()
|
||||||
|
|
||||||
|
if file.is_deleted():
|
||||||
|
file_is_deleted(file, self.emit)
|
||||||
|
elif file.is_externally_modified():
|
||||||
|
file_is_externally_modified(file, self.emit)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -10,23 +10,45 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def file_is_deleted(event):
|
def ask_yes_no(message):
|
||||||
event.file.was_deleted = True
|
dialog = Gtk.MessageDialog(
|
||||||
|
parent = None,
|
||||||
|
flags = 0,
|
||||||
|
message_type = Gtk.MessageType.QUESTION,
|
||||||
|
buttons = Gtk.ButtonsType.YES_NO,
|
||||||
|
text = message,
|
||||||
|
)
|
||||||
|
dialog.set_title("Confirm")
|
||||||
|
|
||||||
|
response = dialog.run()
|
||||||
|
dialog.destroy()
|
||||||
|
|
||||||
|
return response == Gtk.ResponseType.YES
|
||||||
|
|
||||||
|
|
||||||
|
def file_is_deleted(file, emit):
|
||||||
|
file.was_deleted = True
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"file_externally_deleted",
|
"file_externally_deleted",
|
||||||
file = event.file,
|
file = file,
|
||||||
buffer = event.buffer
|
buffer = file.buffer
|
||||||
)
|
)
|
||||||
self.emit(event)
|
emit(event)
|
||||||
|
|
||||||
|
|
||||||
def file_is_externally_modified(event):
|
def file_is_externally_modified(file, emit):
|
||||||
# event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
# "file_externally_modified",
|
"file_externally_modified",
|
||||||
# file = event.file,
|
file = file,
|
||||||
# buffer = event.buffer
|
buffer = file.buffer
|
||||||
# )
|
)
|
||||||
# self.emit(event)
|
emit(event)
|
||||||
|
|
||||||
...
|
if not file.buffer.get_modified():
|
||||||
|
file.reload()
|
||||||
|
return
|
||||||
|
|
||||||
|
result = ask_yes_no("File has been externally modified. Reload?")
|
||||||
|
if not result: return
|
||||||
|
|
||||||
|
file.reload()
|
||||||
|
|||||||
@@ -32,5 +32,8 @@ class Plugin(PluginCode):
|
|||||||
def load(self):
|
def load(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ from gi.repository import Gtk
|
|||||||
|
|
||||||
|
|
||||||
def add_prettify_json(buffer, menu):
|
def add_prettify_json(buffer, menu):
|
||||||
menu.append( Gtk.SeparatorMenuItem() )
|
|
||||||
|
|
||||||
def on_prettify_json(menuitem, buffer):
|
def on_prettify_json(menuitem, buffer):
|
||||||
start_itr, \
|
start_itr, \
|
||||||
end_itr = buffer.get_start_iter(), buffer.get_end_iter()
|
end_itr = buffer.get_start_iter(), buffer.get_end_iter()
|
||||||
|
|||||||
3
plugins/code/event-watchers/tree_sitter/__init__.py
Normal file
3
plugins/code/event-watchers/tree_sitter/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/code/event-watchers/tree_sitter/__main__.py
Normal file
3
plugins/code/event-watchers/tree_sitter/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
134
plugins/code/event-watchers/tree_sitter/languages/scripts/build.sh
Executable file
134
plugins/code/event-watchers/tree_sitter/languages/scripts/build.sh
Executable file
@@ -0,0 +1,134 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# . CONFIG.sh
|
||||||
|
|
||||||
|
# set -o xtrace ## To debug scripts
|
||||||
|
# set -o errexit ## To exit on error
|
||||||
|
# set -o errunset ## To exit if a variable is referenced but not set
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
TOOLS="$ROOT/.tools"
|
||||||
|
NODE_DIR="$TOOLS/node"
|
||||||
|
GRAMMARS_DIR="$ROOT/grammars"
|
||||||
|
BUILD_DIR="$ROOT/build"
|
||||||
|
OUTPUT="$ROOT/compiled"
|
||||||
|
NODE_VERSION="v24.14.1"
|
||||||
|
NODE_DIST="node-$NODE_VERSION-linux-x64"
|
||||||
|
NODE_ARCHIVE="$TOOLS/node.tar.xz"
|
||||||
|
NODE_URL="https://nodejs.org/dist/$NODE_VERSION/$NODE_DIST.tar.xz"
|
||||||
|
TS_CLI_VERSION="0.22.6"
|
||||||
|
|
||||||
|
|
||||||
|
LANGS=(
|
||||||
|
tree-sitter-python
|
||||||
|
tree-sitter-javascript
|
||||||
|
tree-sitter-html
|
||||||
|
tree-sitter-css
|
||||||
|
tree-sitter-json
|
||||||
|
tree-sitter-java
|
||||||
|
tree-sitter-c
|
||||||
|
tree-sitter-cpp
|
||||||
|
tree-sitter-go
|
||||||
|
)
|
||||||
|
|
||||||
|
REPOS=(
|
||||||
|
https://github.com/tree-sitter/tree-sitter-python
|
||||||
|
https://github.com/tree-sitter/tree-sitter-javascript
|
||||||
|
https://github.com/tree-sitter/tree-sitter-html
|
||||||
|
https://github.com/tree-sitter/tree-sitter-css
|
||||||
|
https://github.com/tree-sitter/tree-sitter-json
|
||||||
|
https://github.com/tree-sitter/tree-sitter-java
|
||||||
|
https://github.com/tree-sitter/tree-sitter-c
|
||||||
|
https://github.com/tree-sitter/tree-sitter-cpp
|
||||||
|
https://github.com/tree-sitter/tree-sitter-go
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p "$TOOLS" "$GRAMMARS_DIR" "$BUILD_DIR" "$OUTPUT"
|
||||||
|
|
||||||
|
ensure_node() {
|
||||||
|
if [ -x "$NODE_DIR/bin/node" ]; then
|
||||||
|
echo "==> Using cached Node.js"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Downloading Node.js $NODE_VERSION"
|
||||||
|
wget -O "$NODE_ARCHIVE" "$NODE_URL"
|
||||||
|
|
||||||
|
echo "==> Extracting Node.js"
|
||||||
|
mkdir -p "$NODE_DIR"
|
||||||
|
tar -xf "$NODE_ARCHIVE" -C "$NODE_DIR" --strip-components=1
|
||||||
|
rm "$NODE_ARCHIVE"
|
||||||
|
|
||||||
|
echo "==> Node installed at $NODE_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_tree_sitter() {
|
||||||
|
export PATH="$NODE_DIR/bin:$PATH"
|
||||||
|
TS="$TOOLS/node_modules/.bin/tree-sitter"
|
||||||
|
|
||||||
|
if [ -x "$TS" ]; then
|
||||||
|
echo "==> Using cached tree-sitter-cli"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Installing tree-sitter-cli"
|
||||||
|
cd "$TOOLS"
|
||||||
|
npm init -y >/dev/null 2>&1 || true
|
||||||
|
npm install tree-sitter-cli@$TS_CLI_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_grammars() {
|
||||||
|
echo "==> Syncing grammars"
|
||||||
|
|
||||||
|
for i in "${!LANGS[@]}"; do
|
||||||
|
NAME="${LANGS[$i]}"
|
||||||
|
REPO="${REPOS[$i]}"
|
||||||
|
TARGET="$GRAMMARS_DIR/$NAME"
|
||||||
|
|
||||||
|
if [ -d "$TARGET/.git" ]; then
|
||||||
|
echo "Updating $NAME"
|
||||||
|
git -C "$TARGET" pull --depth 1
|
||||||
|
else
|
||||||
|
echo "Cloning $NAME"
|
||||||
|
git clone --depth 1 "$REPO" "$TARGET"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
build_lib() {
|
||||||
|
echo "==> Building Tree-sitter library"
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT"
|
||||||
|
|
||||||
|
PARSER_SRC=()
|
||||||
|
INCLUDE_PATHS=()
|
||||||
|
|
||||||
|
for GRAMMAR in "${LANGS[@]/#/$GRAMMARS_DIR/}"; do
|
||||||
|
echo "==> Processing grammar $GRAMMAR"
|
||||||
|
|
||||||
|
PARSER_SRC+=("$GRAMMAR/src/parser.c")
|
||||||
|
|
||||||
|
if [[ -f "$GRAMMAR/src/scanner.c" ]]; then
|
||||||
|
PARSER_SRC+=("$GRAMMAR/src/scanner.c")
|
||||||
|
fi
|
||||||
|
|
||||||
|
INCLUDE_PATHS+=("-I$GRAMMAR/src")
|
||||||
|
done
|
||||||
|
|
||||||
|
gcc -shared -o "$OUTPUT/languages.so" "${PARSER_SRC[@]}" "${INCLUDE_PATHS[@]}" -fPIC
|
||||||
|
|
||||||
|
echo "==> Output: $OUTPUT/languages.so"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
ensure_node
|
||||||
|
ensure_tree_sitter
|
||||||
|
sync_grammars
|
||||||
|
build_lib
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
3
plugins/code/event-watchers/tree_sitter/libs/__init__.py
Normal file
3
plugins/code/event-watchers/tree_sitter/libs/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Libs Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
"""Python bindings to the Tree-sitter parsing library."""
|
||||||
|
|
||||||
|
from typing import Protocol as _Protocol
|
||||||
|
|
||||||
|
from ._binding import (
|
||||||
|
Language,
|
||||||
|
LogType,
|
||||||
|
LookaheadIterator,
|
||||||
|
Node,
|
||||||
|
Parser,
|
||||||
|
Point,
|
||||||
|
Query,
|
||||||
|
QueryCursor,
|
||||||
|
QueryError,
|
||||||
|
Range,
|
||||||
|
Tree,
|
||||||
|
TreeCursor,
|
||||||
|
LANGUAGE_VERSION,
|
||||||
|
MIN_COMPATIBLE_LANGUAGE_VERSION,
|
||||||
|
)
|
||||||
|
|
||||||
|
LogType.__doc__ = "The type of a log message."
|
||||||
|
|
||||||
|
Point.__doc__ = "A position in a multi-line text document, in terms of rows and columns."
|
||||||
|
Point.row.__doc__ = "The zero-based row of the document."
|
||||||
|
Point.column.__doc__ = "The zero-based column of the document."
|
||||||
|
|
||||||
|
|
||||||
|
class QueryPredicate(_Protocol):
|
||||||
|
"""A custom query predicate that runs on a pattern."""
|
||||||
|
def __call__(self, predicate, args, pattern_index, captures):
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
predicate : str
|
||||||
|
The name of the predicate.
|
||||||
|
args : list[tuple[str, typing.Literal['capture', 'string']]]
|
||||||
|
The arguments to the predicate.
|
||||||
|
pattern_index : int
|
||||||
|
The index of the pattern within the query.
|
||||||
|
captures : dict[str, list[Node]]
|
||||||
|
The captures contained in the pattern.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
``True`` if the predicate matches, ``False`` otherwise.
|
||||||
|
|
||||||
|
Tip
|
||||||
|
---
|
||||||
|
You don't need to create an actual class, just a function with this signature.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Language",
|
||||||
|
"LogType",
|
||||||
|
"LookaheadIterator",
|
||||||
|
"Node",
|
||||||
|
"Parser",
|
||||||
|
"Point",
|
||||||
|
"Query",
|
||||||
|
"QueryCursor",
|
||||||
|
"QueryError",
|
||||||
|
"QueryPredicate",
|
||||||
|
"Range",
|
||||||
|
"Tree",
|
||||||
|
"TreeCursor",
|
||||||
|
"LANGUAGE_VERSION",
|
||||||
|
"MIN_COMPATIBLE_LANGUAGE_VERSION",
|
||||||
|
]
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
from collections.abc import ByteString, Callable, Iterator, Sequence
|
||||||
|
from typing import Annotated, Any, Final, Literal, NamedTuple, Protocol, Self, final, overload
|
||||||
|
from typing_extensions import deprecated
|
||||||
|
|
||||||
|
class _SupportsFileno(Protocol):
|
||||||
|
def fileno(self) -> int: ...
|
||||||
|
|
||||||
|
class Point(NamedTuple):
|
||||||
|
row: int
|
||||||
|
column: int
|
||||||
|
|
||||||
|
class LogType(IntEnum):
|
||||||
|
PARSE: int
|
||||||
|
LEX: int
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Language:
|
||||||
|
@overload
|
||||||
|
@deprecated("int argument support is deprecated")
|
||||||
|
def __init__(self, ptr: Annotated[int, "TSLanguage *"], /) -> None: ...
|
||||||
|
@overload
|
||||||
|
def __init__(self, ptr: Annotated[object, "TSLanguage *"], /) -> None: ...
|
||||||
|
@property
|
||||||
|
def name(self) -> str | None: ...
|
||||||
|
@property
|
||||||
|
def abi_version(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def semantic_version(self) -> tuple[int, int, int] | None: ...
|
||||||
|
@deprecated("Use abi_version instead")
|
||||||
|
@property
|
||||||
|
def version(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def node_kind_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def parse_state_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def field_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def supertypes(self) -> tuple[int, ...]: ...
|
||||||
|
def subtypes(self, supertype: int, /) -> tuple[int, ...]: ...
|
||||||
|
def node_kind_for_id(self, id: int, /) -> str | None: ...
|
||||||
|
def id_for_node_kind(self, kind: str, named: bool, /) -> int | None: ...
|
||||||
|
def node_kind_is_named(self, id: int, /) -> bool: ...
|
||||||
|
def node_kind_is_visible(self, id: int, /) -> bool: ...
|
||||||
|
def node_kind_is_supertype(self, id: int, /) -> bool: ...
|
||||||
|
def field_name_for_id(self, field_id: int, /) -> str | None: ...
|
||||||
|
def field_id_for_name(self, name: str, /) -> int | None: ...
|
||||||
|
def next_state(self, state: int, id: int, /) -> int: ...
|
||||||
|
def lookahead_iterator(self, state: int, /) -> LookaheadIterator | None: ...
|
||||||
|
@deprecated("Use the Query() constructor instead")
|
||||||
|
def query(self, source: str, /) -> Query: ...
|
||||||
|
def copy(self) -> Language: ...
|
||||||
|
def __repr__(self) -> str: ...
|
||||||
|
def __eq__(self, other: Any, /) -> bool: ...
|
||||||
|
def __ne__(self, other: Any, /) -> bool: ...
|
||||||
|
def __hash__(self) -> int: ...
|
||||||
|
def __copy__(self) -> Language: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Node:
|
||||||
|
@property
|
||||||
|
def id(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def kind_id(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def grammar_id(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def grammar_name(self) -> str: ...
|
||||||
|
@property
|
||||||
|
def type(self) -> str: ...
|
||||||
|
@property
|
||||||
|
def is_named(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def is_extra(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def has_changes(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def has_error(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def is_error(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def parse_state(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def next_parse_state(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def is_missing(self) -> bool: ...
|
||||||
|
@property
|
||||||
|
def start_byte(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def end_byte(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def byte_range(self) -> tuple[int, int]: ...
|
||||||
|
@property
|
||||||
|
def range(self) -> Range: ...
|
||||||
|
@property
|
||||||
|
def start_point(self) -> Point: ...
|
||||||
|
@property
|
||||||
|
def end_point(self) -> Point: ...
|
||||||
|
@property
|
||||||
|
def children(self) -> list[Node]: ...
|
||||||
|
@property
|
||||||
|
def child_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def named_children(self) -> list[Node]: ...
|
||||||
|
@property
|
||||||
|
def named_child_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def parent(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def next_sibling(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def prev_sibling(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def next_named_sibling(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def prev_named_sibling(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def descendant_count(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def text(self) -> bytes | None: ...
|
||||||
|
def walk(self) -> TreeCursor: ...
|
||||||
|
def edit(
|
||||||
|
self,
|
||||||
|
start_byte: int,
|
||||||
|
old_end_byte: int,
|
||||||
|
new_end_byte: int,
|
||||||
|
start_point: Point | tuple[int, int],
|
||||||
|
old_end_point: Point | tuple[int, int],
|
||||||
|
new_end_point: Point | tuple[int, int],
|
||||||
|
) -> None: ...
|
||||||
|
def child(self, index: int, /) -> Node | None: ...
|
||||||
|
def named_child(self, index: int, /) -> Node | None: ...
|
||||||
|
def first_child_for_byte(self, byte: int, /) -> Node | None: ...
|
||||||
|
def first_named_child_for_byte(self, byte: int, /) -> Node | None: ...
|
||||||
|
def child_by_field_id(self, id: int, /) -> Node | None: ...
|
||||||
|
def child_by_field_name(self, name: str, /) -> Node | None: ...
|
||||||
|
def child_with_descendant(self, descendant: Node, /) -> Node | None: ...
|
||||||
|
def children_by_field_id(self, id: int, /) -> list[Node]: ...
|
||||||
|
def children_by_field_name(self, name: str, /) -> list[Node]: ...
|
||||||
|
def field_name_for_child(self, child_index: int, /) -> str | None: ...
|
||||||
|
def field_name_for_named_child(self, child_index: int, /) -> str | None: ...
|
||||||
|
def descendant_for_byte_range(
|
||||||
|
self,
|
||||||
|
start_byte: int,
|
||||||
|
end_byte: int,
|
||||||
|
/,
|
||||||
|
) -> Node | None: ...
|
||||||
|
def named_descendant_for_byte_range(
|
||||||
|
self,
|
||||||
|
start_byte: int,
|
||||||
|
end_byte: int,
|
||||||
|
/,
|
||||||
|
) -> Node | None: ...
|
||||||
|
def descendant_for_point_range(
|
||||||
|
self,
|
||||||
|
start_point: Point | tuple[int, int],
|
||||||
|
end_point: Point | tuple[int, int],
|
||||||
|
/,
|
||||||
|
) -> Node | None: ...
|
||||||
|
def named_descendant_for_point_range(
|
||||||
|
self,
|
||||||
|
start_point: Point | tuple[int, int],
|
||||||
|
end_point: Point | tuple[int, int],
|
||||||
|
/,
|
||||||
|
) -> Node | None: ...
|
||||||
|
def __repr__(self) -> str: ...
|
||||||
|
def __str__(self) -> str: ...
|
||||||
|
def __eq__(self, other: Any, /) -> bool: ...
|
||||||
|
def __ne__(self, other: Any, /) -> bool: ...
|
||||||
|
def __hash__(self) -> int: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Tree:
|
||||||
|
@property
|
||||||
|
def root_node(self) -> Node: ...
|
||||||
|
@property
|
||||||
|
def included_ranges(self) -> list[Range]: ...
|
||||||
|
@property
|
||||||
|
def language(self) -> Language: ...
|
||||||
|
def root_node_with_offset(
|
||||||
|
self,
|
||||||
|
offset_bytes: int,
|
||||||
|
offset_extent: Point | tuple[int, int],
|
||||||
|
/,
|
||||||
|
) -> Node | None: ...
|
||||||
|
def copy(self) -> Tree: ...
|
||||||
|
def edit(
|
||||||
|
self,
|
||||||
|
start_byte: int,
|
||||||
|
old_end_byte: int,
|
||||||
|
new_end_byte: int,
|
||||||
|
start_point: Point | tuple[int, int],
|
||||||
|
old_end_point: Point | tuple[int, int],
|
||||||
|
new_end_point: Point | tuple[int, int],
|
||||||
|
) -> None: ...
|
||||||
|
def walk(self) -> TreeCursor: ...
|
||||||
|
def changed_ranges(self, new_tree: Tree, /) -> list[Range]: ...
|
||||||
|
def print_dot_graph(self, file: _SupportsFileno, /) -> None: ...
|
||||||
|
def __copy__(self) -> Tree: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class TreeCursor:
|
||||||
|
@property
|
||||||
|
def node(self) -> Node | None: ...
|
||||||
|
@property
|
||||||
|
def field_id(self) -> int | None: ...
|
||||||
|
@property
|
||||||
|
def field_name(self) -> str | None: ...
|
||||||
|
@property
|
||||||
|
def depth(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def descendant_index(self) -> int: ...
|
||||||
|
def copy(self) -> TreeCursor: ...
|
||||||
|
def reset(self, node: Node, /) -> None: ...
|
||||||
|
def reset_to(self, cursor: TreeCursor, /) -> None: ...
|
||||||
|
def goto_first_child(self) -> bool: ...
|
||||||
|
def goto_last_child(self) -> bool: ...
|
||||||
|
def goto_parent(self) -> bool: ...
|
||||||
|
def goto_next_sibling(self) -> bool: ...
|
||||||
|
def goto_previous_sibling(self) -> bool: ...
|
||||||
|
def goto_descendant(self, index: int, /) -> None: ...
|
||||||
|
def goto_first_child_for_byte(self, byte: int, /) -> int | None: ...
|
||||||
|
def goto_first_child_for_point(self, point: Point | tuple[int, int], /) -> int | None: ...
|
||||||
|
def __copy__(self) -> TreeCursor: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Parser:
|
||||||
|
@overload
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
language: Language | None = None,
|
||||||
|
*,
|
||||||
|
included_ranges: Sequence[Range] | None = None,
|
||||||
|
logger: Callable[[LogType, str], None] | None = None,
|
||||||
|
) -> None: ...
|
||||||
|
@deprecated("timeout_micros is deprecated")
|
||||||
|
@overload
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
language: Language | None = None,
|
||||||
|
*,
|
||||||
|
included_ranges: Sequence[Range] | None = None,
|
||||||
|
timeout_micros: int | None = None,
|
||||||
|
logger: Callable[[LogType, str], None] | None = None,
|
||||||
|
) -> None: ...
|
||||||
|
@property
|
||||||
|
def language(self) -> Language | None: ...
|
||||||
|
@language.setter
|
||||||
|
def language(self, language: Language) -> None: ...
|
||||||
|
@language.deleter
|
||||||
|
def language(self) -> None: ...
|
||||||
|
@property
|
||||||
|
def included_ranges(self) -> list[Range]: ...
|
||||||
|
@included_ranges.setter
|
||||||
|
def included_ranges(self, ranges: Sequence[Range]) -> None: ...
|
||||||
|
@included_ranges.deleter
|
||||||
|
def included_ranges(self) -> None: ...
|
||||||
|
@deprecated("Use the progress_callback in parse()")
|
||||||
|
@property
|
||||||
|
def timeout_micros(self) -> int: ...
|
||||||
|
@deprecated("Use the progress_callback in parse()")
|
||||||
|
@timeout_micros.setter
|
||||||
|
def timeout_micros(self, timeout: int) -> None: ...
|
||||||
|
@deprecated("Use the progress_callback in parse()")
|
||||||
|
@timeout_micros.deleter
|
||||||
|
def timeout_micros(self) -> None: ...
|
||||||
|
@property
|
||||||
|
def logger(self) -> Callable[[LogType, str], None] | None: ...
|
||||||
|
@logger.setter
|
||||||
|
def logger(self, logger: Callable[[LogType, str], None]) -> None: ...
|
||||||
|
@logger.deleter
|
||||||
|
def logger(self) -> None: ...
|
||||||
|
@overload
|
||||||
|
def parse(
|
||||||
|
self,
|
||||||
|
source: ByteString,
|
||||||
|
/,
|
||||||
|
old_tree: Tree | None = None,
|
||||||
|
encoding: Literal["utf8", "utf16", "utf16le", "utf16be"] = "utf8",
|
||||||
|
) -> Tree: ...
|
||||||
|
@overload
|
||||||
|
def parse(
|
||||||
|
self,
|
||||||
|
read_callback: Callable[[int, Point], ByteString | None],
|
||||||
|
/,
|
||||||
|
old_tree: Tree | None = None,
|
||||||
|
encoding: Literal["utf8", "utf16", "utf16le", "utf16be"] = "utf8",
|
||||||
|
progress_callback: Callable[[int, bool], bool] | None = None,
|
||||||
|
) -> Tree: ...
|
||||||
|
def reset(self) -> None: ...
|
||||||
|
def print_dot_graphs(self, file: _SupportsFileno | None, /) -> None: ...
|
||||||
|
|
||||||
|
class QueryError(ValueError): ...
|
||||||
|
|
||||||
|
class QueryPredicate(Protocol):
|
||||||
|
def __call__(
|
||||||
|
self,
|
||||||
|
predicate: str,
|
||||||
|
args: list[tuple[str, Literal["capture", "string"]]],
|
||||||
|
pattern_index: int,
|
||||||
|
captures: dict[str, list[Node]],
|
||||||
|
) -> bool: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Query:
|
||||||
|
def __new__(cls, language: Language, source: str, /) -> Self: ...
|
||||||
|
def pattern_count(self) -> int: ...
|
||||||
|
def capture_count(self) -> int: ...
|
||||||
|
def string_count(self) -> int: ...
|
||||||
|
def start_byte_for_pattern(self, index: int, /) -> int: ...
|
||||||
|
def end_byte_for_pattern(self, index: int, /) -> int: ...
|
||||||
|
def is_pattern_rooted(self, index: int, /) -> bool: ...
|
||||||
|
def is_pattern_non_local(self, index: int, /) -> bool: ...
|
||||||
|
def is_pattern_guaranteed_at_step(self, index: int, /) -> bool: ...
|
||||||
|
def capture_name(self, index: int, /) -> str: ...
|
||||||
|
def capture_quantifier(
|
||||||
|
self,
|
||||||
|
pattern_index: int,
|
||||||
|
capture_index: int,
|
||||||
|
/
|
||||||
|
) -> Literal["", "?", "*", "+"]: ...
|
||||||
|
def string_value(self, index: int, /) -> str: ...
|
||||||
|
def disable_capture(self, name: str, /) -> None: ...
|
||||||
|
def disable_pattern(self, index: int, /) -> None: ...
|
||||||
|
def pattern_settings(self, index: int, /) -> dict[str, str | None]: ...
|
||||||
|
def pattern_assertions(self, index: int, /) -> dict[str, tuple[str | None, bool]]: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class QueryCursor:
|
||||||
|
@overload
|
||||||
|
def __init__(self, query: Query, *, match_limit: int = 0xFFFFFFFF) -> None: ...
|
||||||
|
@deprecated("timeout_micros is deprecated")
|
||||||
|
@overload
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
query: Query,
|
||||||
|
*,
|
||||||
|
match_limit: int = 0xFFFFFFFF,
|
||||||
|
timeout_micros: int = 0
|
||||||
|
) -> None: ...
|
||||||
|
@property
|
||||||
|
def match_limit(self) -> int: ...
|
||||||
|
@match_limit.setter
|
||||||
|
def match_limit(self, limit: int) -> None: ...
|
||||||
|
@match_limit.deleter
|
||||||
|
def match_limit(self) -> None: ...
|
||||||
|
@deprecated("Use the progress_callback in matches() or captures()")
|
||||||
|
@property
|
||||||
|
def timeout_micros(self) -> int: ...
|
||||||
|
@deprecated("Use the progress_callback in matches() or captures()")
|
||||||
|
@timeout_micros.setter
|
||||||
|
def timeout_micros(self, timeout: int) -> None: ...
|
||||||
|
@property
|
||||||
|
def did_exceed_match_limit(self) -> bool: ...
|
||||||
|
def set_max_start_depth(self, depth: int, /) -> None: ...
|
||||||
|
def set_byte_range(self, start: int, end: int, /) -> None: ...
|
||||||
|
def set_point_range(
|
||||||
|
self,
|
||||||
|
start: Point | tuple[int, int],
|
||||||
|
end: Point | tuple[int, int],
|
||||||
|
/,
|
||||||
|
) -> None: ...
|
||||||
|
def captures(
|
||||||
|
self,
|
||||||
|
node: Node,
|
||||||
|
predicate: QueryPredicate | None = None,
|
||||||
|
progress_callback: Callable[[int], bool] | None = None,
|
||||||
|
/,
|
||||||
|
) -> dict[str, list[Node]]: ...
|
||||||
|
def matches(
|
||||||
|
self,
|
||||||
|
node: Node,
|
||||||
|
predicate: QueryPredicate | None = None,
|
||||||
|
progress_callback: Callable[[int], bool] | None = None,
|
||||||
|
/,
|
||||||
|
) -> list[tuple[int, dict[str, list[Node]]]]: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class LookaheadIterator(Iterator[tuple[int, str]]):
|
||||||
|
@property
|
||||||
|
def language(self) -> Language: ...
|
||||||
|
@property
|
||||||
|
def current_symbol(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def current_symbol_name(self) -> str: ...
|
||||||
|
def reset(self, state: int, /, language: Language | None = None) -> bool: ...
|
||||||
|
def names(self) -> list[str]: ...
|
||||||
|
def symbols(self) -> list[int]: ...
|
||||||
|
def __next__(self) -> tuple[int, str]: ...
|
||||||
|
|
||||||
|
@final
|
||||||
|
class Range:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
start_point: Point | tuple[int, int],
|
||||||
|
end_point: Point | tuple[int, int],
|
||||||
|
start_byte: int,
|
||||||
|
end_byte: int,
|
||||||
|
) -> None: ...
|
||||||
|
@property
|
||||||
|
def start_point(self) -> Point: ...
|
||||||
|
@property
|
||||||
|
def end_point(self) -> Point: ...
|
||||||
|
@property
|
||||||
|
def start_byte(self) -> int: ...
|
||||||
|
@property
|
||||||
|
def end_byte(self) -> int: ...
|
||||||
|
def __eq__(self, other: Any, /) -> bool: ...
|
||||||
|
def __ne__(self, other: Any, /) -> bool: ...
|
||||||
|
def __repr__(self) -> str: ...
|
||||||
|
def __hash__(self) -> int: ...
|
||||||
|
|
||||||
|
LANGUAGE_VERSION: Final[int]
|
||||||
|
|
||||||
|
MIN_COMPATIBLE_LANGUAGE_VERSION: Final[int]
|
||||||
8
plugins/code/event-watchers/tree_sitter/manifest.json
Normal file
8
plugins/code/event-watchers/tree_sitter/manifest.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Tree-sitter",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"pre_launch": true,
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
63
plugins/code/event-watchers/tree_sitter/plugin.py
Normal file
63
plugins/code/event-watchers/tree_sitter/plugin.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .tree_sitter import Parser, get_parser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def set_ast(self, file):
|
||||||
|
if not hasattr(file, "tree_sitter"):
|
||||||
|
parser = get_parser( file.ftype )
|
||||||
|
if not parser: return
|
||||||
|
|
||||||
|
file.tree_sitter = parser
|
||||||
|
|
||||||
|
buffer = file.buffer
|
||||||
|
start_itr, \
|
||||||
|
end_itr = buffer.get_bounds()
|
||||||
|
text = buffer.get_text(start_itr, end_itr, True)
|
||||||
|
|
||||||
|
tree = file.tree_sitter.parse( text.encode("UTF-8") )
|
||||||
|
file.ast = tree
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.FocusedViewEvent):
|
||||||
|
self.view = event.view
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"get_file", buffer = self.view.get_buffer()
|
||||||
|
)
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
file = event.response
|
||||||
|
|
||||||
|
if not file: return
|
||||||
|
if file.ftype == "buffer": return
|
||||||
|
|
||||||
|
self.set_ast(file)
|
||||||
|
elif isinstance(event, Code_Event_Types.TextChangedEvent):
|
||||||
|
self.set_ast(event.file)
|
||||||
|
|
||||||
|
# root = tree.root_node
|
||||||
|
# print("Root type:", root.type)
|
||||||
|
# for child in root.children:
|
||||||
|
# print(child.type, child.start_point, child.end_point)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
57
plugins/code/event-watchers/tree_sitter/tree_sitter.py
Normal file
57
plugins/code/event-watchers/tree_sitter/tree_sitter.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .libs.tree_sitter import Language, Parser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_LIB_PATH = os.path.join(
|
||||||
|
os.path.dirname(__file__), "languages", "languages.so"
|
||||||
|
)
|
||||||
|
_LANGUAGE_LIB = ctypes.CDLL(_LIB_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_language(name: str) -> Language | None:
|
||||||
|
symbol = f"tree_sitter_{name}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
func = getattr(_LANGUAGE_LIB, symbol)
|
||||||
|
except AttributeError:
|
||||||
|
logger.warning(f"Tree-sitter: {name} not found in 'languages.so' shared library...")
|
||||||
|
return None
|
||||||
|
|
||||||
|
func.restype = ctypes.c_void_p
|
||||||
|
return Language(func())
|
||||||
|
|
||||||
|
|
||||||
|
LANGUAGES = {
|
||||||
|
"python": load_language("python"),
|
||||||
|
"python3": load_language("python"),
|
||||||
|
"javascript": load_language("javascript"),
|
||||||
|
"html": load_language("html"),
|
||||||
|
"css": load_language("css"),
|
||||||
|
"json": load_language("json"),
|
||||||
|
"java": load_language("java"),
|
||||||
|
"c": load_language("c"),
|
||||||
|
"cpp": load_language("cpp"),
|
||||||
|
"go": load_language("go")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_parser(lang_name: str) -> Parser | None:
|
||||||
|
if not lang_name in LANGUAGES: return
|
||||||
|
|
||||||
|
language = LANGUAGES[lang_name]
|
||||||
|
|
||||||
|
if not language: return
|
||||||
|
|
||||||
|
parser = Parser()
|
||||||
|
parser.language = language
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"info": "https://github.com/godotengine/godot/blob/4a280218fcfdd69408cceb74577c9e69086be23a/editor/settings/editor_settings.cpp#L1132",
|
||||||
|
"command": "lsp-ws-proxy -- godot",
|
||||||
|
"alt-command": "godot",
|
||||||
|
"alt-command2": "lsp-ws-proxy --listen 4114 -- godot --headless",
|
||||||
|
"alt-command3": "godot --headless --lsp-port 7766",
|
||||||
|
"socket": "ws://127.0.0.1:9999/gdscript",
|
||||||
|
"socket-two": "ws://127.0.0.1:9999/?name=gdscript",
|
||||||
|
"initialization-options": {
|
||||||
|
"processId": null,
|
||||||
|
"clientInfo": {
|
||||||
|
"name": "Godot",
|
||||||
|
"version": "4.4"
|
||||||
|
},
|
||||||
|
"rootUri": "file://{workspace.folder}",
|
||||||
|
"capabilities": {
|
||||||
|
"workspace": {
|
||||||
|
"applyEdit": true,
|
||||||
|
"workspaceEdit": {
|
||||||
|
"documentChanges": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textDocument": {
|
||||||
|
"synchronization": {
|
||||||
|
"dynamicRegistration": true,
|
||||||
|
"willSave": false,
|
||||||
|
"didSave": true,
|
||||||
|
"willSaveWaitUntil": false
|
||||||
|
},
|
||||||
|
"completion": {
|
||||||
|
"dynamicRegistration": true,
|
||||||
|
"completionItem": {
|
||||||
|
"snippetSupport": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"definition": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"references": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"documentSymbol": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trace": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Godot LSP Client",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Python imports
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .response_handler import GDScriptHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
dirPth = path.dirname( path.realpath(__file__) )
|
||||||
|
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
|
||||||
|
config = f.read()
|
||||||
|
event = Event_Factory.create_event("register_lsp_client",
|
||||||
|
lang_id = "gdscript",
|
||||||
|
lang_config = config,
|
||||||
|
handler = GDScriptHandler
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_lsp_client",
|
||||||
|
lang_id = "gdscript"
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .gdscript import GDScriptHandler
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from lsp_manager.response_handlers.default import DefaultHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GDScriptHandler(DefaultHandler):
|
||||||
|
"""Uses default handling, can override if Godot needs special logic."""
|
||||||
|
...
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
{
|
||||||
|
"info": "https://download.eclipse.org/jdtls/",
|
||||||
|
"info-init-options": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line",
|
||||||
|
"info-import-build": "https://www.javahotchocolate.com/tutorials/build-path.html",
|
||||||
|
"info-external-class-paths": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/issues/3291",
|
||||||
|
"link": "https://download.eclipse.org/jdtls/milestones/?d",
|
||||||
|
"command": "lsp-ws-proxy --listen 4114 -- jdtls",
|
||||||
|
"alt-command": "lsp-ws-proxy -- jdtls",
|
||||||
|
"alt-command2": "java-language-server",
|
||||||
|
"socket": "ws://127.0.0.1:9999/java",
|
||||||
|
"socket-two": "ws://127.0.0.1:9999/?name=jdtls",
|
||||||
|
"alt-socket": "ws://127.0.0.1:9999/?name=java-language-server",
|
||||||
|
"initialization-options": {
|
||||||
|
"bundles": [
|
||||||
|
"intellicode-core.jar"
|
||||||
|
],
|
||||||
|
"workspaceFolders": [
|
||||||
|
"file://{workspace.folder}"
|
||||||
|
],
|
||||||
|
"extendedClientCapabilities": {
|
||||||
|
"classFileContentsSupport": true,
|
||||||
|
"executeClientCommandSupport": false
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"java": {
|
||||||
|
"autobuild": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"jdt": {
|
||||||
|
"ls": {
|
||||||
|
"javac": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"home": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2"
|
||||||
|
},
|
||||||
|
"lombokSupport": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"protobufSupport":{
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"androidSupport": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"updateBuildConfiguration": "automatic",
|
||||||
|
"maven": {
|
||||||
|
"userSettings": "{user.home}/.config/jdtls/settings.xml",
|
||||||
|
"globalSettings": "{user.home}/.config/jdtls/settings.xml"
|
||||||
|
},
|
||||||
|
"runtimes": [
|
||||||
|
{
|
||||||
|
"name": "JavaSE-17",
|
||||||
|
"path": "/usr/lib/jvm/java-17-openjdk",
|
||||||
|
"javadoc": "https://docs.oracle.com/en/java/javase/17/docs/api/",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "JavaSE-22",
|
||||||
|
"path": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2",
|
||||||
|
"javadoc": "https://docs.oracle.com/en/java/javase/22/docs/api/",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"classPath": [
|
||||||
|
"{user.home}/.config/jdtls/m2/repository/**/*-sources.jar",
|
||||||
|
"lib/**/*-sources.jar"
|
||||||
|
],
|
||||||
|
"docPath": [
|
||||||
|
"{user.home}/.config/jdtls/m2/repository/**/*-javadoc.jar",
|
||||||
|
"lib/**/*-javadoc.jar"
|
||||||
|
],
|
||||||
|
"project": {
|
||||||
|
"encoding": "ignore",
|
||||||
|
"outputPath": "bin",
|
||||||
|
"referencedLibraries": [
|
||||||
|
"{user.home}/.config/jdtls/m2/repository/**/*.jar",
|
||||||
|
"lib/**/*.jar"
|
||||||
|
],
|
||||||
|
"importOnFirstTimeStartup": "automatic",
|
||||||
|
"importHint": true,
|
||||||
|
"resourceFilters": [
|
||||||
|
"node_modules",
|
||||||
|
"\\.git"
|
||||||
|
],
|
||||||
|
"sourcePaths": [
|
||||||
|
"src",
|
||||||
|
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"organizeImports": {
|
||||||
|
"starThreshold": 99,
|
||||||
|
"staticStarThreshold": 99
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": {
|
||||||
|
"gradle": {
|
||||||
|
"wrapper": {
|
||||||
|
"checksums": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"maven": {
|
||||||
|
"enabled": true,
|
||||||
|
"offline": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"disableTestClasspathFlag": false
|
||||||
|
},
|
||||||
|
"gradle": {
|
||||||
|
"enabled": false,
|
||||||
|
"wrapper": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"version": "",
|
||||||
|
"home": "abs(static/gradle-7.3.3)",
|
||||||
|
"java": {
|
||||||
|
"home": "abs(static/launch_jres/17.0.6-linux-x86_64)"
|
||||||
|
},
|
||||||
|
"offline": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"arguments": [],
|
||||||
|
"jvmArguments": [],
|
||||||
|
"user": {
|
||||||
|
"home": ""
|
||||||
|
},
|
||||||
|
"annotationProcessing": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclusions": [
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/.metadata/**",
|
||||||
|
"**/archetype-resources/**",
|
||||||
|
"**/META-INF/maven/**"
|
||||||
|
],
|
||||||
|
"generatesMetadataFilesAtProjectRoot": false
|
||||||
|
},
|
||||||
|
"maven": {
|
||||||
|
"downloadSources": true,
|
||||||
|
"updateSnapshots": true
|
||||||
|
},
|
||||||
|
"silentNotification": true,
|
||||||
|
"contentProvider": {
|
||||||
|
"preferred": "fernflower"
|
||||||
|
},
|
||||||
|
"signatureHelp": {
|
||||||
|
"enabled": true,
|
||||||
|
"description": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"completion": {
|
||||||
|
"enabled": true,
|
||||||
|
"engine": "ecj",
|
||||||
|
"matchCase": "firstletter",
|
||||||
|
"maxResults": 25,
|
||||||
|
"guessMethodArguments": true,
|
||||||
|
"lazyResolveTextEdit": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"postfix": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"favoriteStaticMembers": [
|
||||||
|
"org.junit.Assert.*",
|
||||||
|
"org.junit.Assume.*",
|
||||||
|
"org.junit.jupiter.api.Assertions.*",
|
||||||
|
"org.junit.jupiter.api.Assumptions.*",
|
||||||
|
"org.junit.jupiter.api.DynamicContainer.*",
|
||||||
|
"org.junit.jupiter.api.DynamicTest.*"
|
||||||
|
],
|
||||||
|
"importOrder": [
|
||||||
|
"#",
|
||||||
|
"java",
|
||||||
|
"javax",
|
||||||
|
"org",
|
||||||
|
"com"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"references": {
|
||||||
|
"includeAccessors": true,
|
||||||
|
"includeDecompiledSources": true
|
||||||
|
},
|
||||||
|
"codeGeneration": {
|
||||||
|
"toString": {
|
||||||
|
"template": "${object.className}{${member.name()}=${member.value}, ${otherMembers}}"
|
||||||
|
},
|
||||||
|
"insertionLocation": "afterCursor",
|
||||||
|
"useBlocks": true
|
||||||
|
},
|
||||||
|
"implementationsCodeLens": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"referencesCodeLens": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"progressReports": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"saveActions": {
|
||||||
|
"organizeImports": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Java LSP Client",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Python imports
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .response_handler import JavaHandler
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
dirPth = path.dirname( path.realpath(__file__) )
|
||||||
|
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
|
||||||
|
config = f.read()
|
||||||
|
event = Event_Factory.create_event("register_lsp_client",
|
||||||
|
lang_id = "java",
|
||||||
|
lang_config = config,
|
||||||
|
handler = JavaHandler
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_lsp_client",
|
||||||
|
lang_id = "java"
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .java import JavaHandler
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from lsp_manager.response_handlers.default import DefaultHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class JavaHandler(DefaultHandler):
|
||||||
|
"""Java-specific: overrides definition, handles classFileContents."""
|
||||||
|
|
||||||
|
def handle(self, method: str, response, controller):
|
||||||
|
match method:
|
||||||
|
case "textDocument/definition":
|
||||||
|
self._handle_definition(response, controller)
|
||||||
|
case "java/classFileContents":
|
||||||
|
self._handle_class_file_contents(response)
|
||||||
|
case _:
|
||||||
|
super().handle(method, response, controller)
|
||||||
|
|
||||||
|
def _handle_definition(self, response, controller):
|
||||||
|
if not response: return
|
||||||
|
|
||||||
|
uri = response[0]["uri"]
|
||||||
|
if "jdt://" in uri:
|
||||||
|
controller._lsp_java_class_file_contents(uri)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._prompt_goto_request(uri, response[0]["range"])
|
||||||
|
|
||||||
|
def _handle_class_file_contents(self, text: str):
|
||||||
|
event = Event_Factory.create_event("get_active_view")
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
view = event.response
|
||||||
|
file = view.command.exec("new_file")
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
itr = buffer.get_iter_at_mark(buffer.get_insert())
|
||||||
|
lm = GtkSource.LanguageManager.get_default()
|
||||||
|
language = lm.get_language("java")
|
||||||
|
file.ftype = "java"
|
||||||
|
|
||||||
|
buffer.set_language(language)
|
||||||
|
buffer.insert(itr, text, -1)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
LSP Clients Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from ..config import get_lsp_init_config
|
||||||
|
from ..dto.code.lsp.lsp_messages import get_message_str
|
||||||
|
from ..dto.code.lsp.lsp_message_structs import \
|
||||||
|
LSPResponseTypes, ClientRequest, ClientNotification
|
||||||
|
from .lsp_client_websocket import LSPClientWebsocket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPClient(LSPClientWebsocket):
|
||||||
|
def __init__(self):
|
||||||
|
super(LSPClient, self).__init__()
|
||||||
|
|
||||||
|
self._socket: str = ""
|
||||||
|
self._language: str = ""
|
||||||
|
self._workspace_path: str = ""
|
||||||
|
self._message_id: int = -1
|
||||||
|
self._event_history: dict[int, str] = {}
|
||||||
|
self._init_params: dict = get_lsp_init_config()
|
||||||
|
self._init_opts: dict[str, str] = {}
|
||||||
|
self.doc_vers: dict[str, int] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def set_language(self, language: str):
|
||||||
|
self._language = language
|
||||||
|
|
||||||
|
def set_workspace_path(self, workspace_path: str):
|
||||||
|
self._workspace_path = workspace_path
|
||||||
|
|
||||||
|
def set_init_opts(self, init_opts: dict[str, str]):
|
||||||
|
self._init_opts = init_opts
|
||||||
|
|
||||||
|
def set_socket(self, socket: str):
|
||||||
|
self._socket = socket
|
||||||
|
|
||||||
|
def unset_socket(self):
|
||||||
|
self._socket = ""
|
||||||
|
|
||||||
|
def send_notification(self, method: str, params: dict = {}):
|
||||||
|
self._send_message( ClientNotification(method, params) )
|
||||||
|
|
||||||
|
def send_request(self, method: str, params: dict = {}):
|
||||||
|
self._message_id += 1
|
||||||
|
self._event_history[self._message_id] = method
|
||||||
|
self._send_message( ClientRequest(self._message_id, method, params) )
|
||||||
|
|
||||||
|
def get_event_by_id(self, message_id: int) -> str:
|
||||||
|
if not message_id in self._event_history: return
|
||||||
|
return self._event_history[message_id]
|
||||||
|
|
||||||
|
def handle_lsp_response(self, lsp_response: LSPResponseTypes | dict):
|
||||||
|
raise NotImplementedError
|
||||||
@@ -3,12 +3,13 @@
|
|||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .lsp_controller_events import LSPControllerEvents
|
from ..dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
||||||
from libs.dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
|
||||||
|
from .lsp_client_events import LSPClientEvents
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LSPControllerBase(LSPControllerEvents):
|
class LSPClientBase(LSPClientEvents):
|
||||||
def _send_message(self, data: ClientRequest or ClientNotification):
|
def _send_message(self, data: ClientRequest or ClientNotification):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from ..dto.code.lsp.lsp_messages import get_message_obj
|
||||||
|
from ..dto.code.lsp.lsp_messages import didopen_notification
|
||||||
|
from ..dto.code.lsp.lsp_messages import didsave_notification
|
||||||
|
from ..dto.code.lsp.lsp_messages import didclose_notification
|
||||||
|
from ..dto.code.lsp.lsp_messages import didchange_notification
|
||||||
|
from ..dto.code.lsp.lsp_messages import didchange_notification_range
|
||||||
|
from ..dto.code.lsp.lsp_messages import completion_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import definition_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import implementation_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import references_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import symbols_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import shutdown_request
|
||||||
|
from ..dto.code.lsp.lsp_messages import exit_request
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPClientEvents:
|
||||||
|
def send_initialize_message(self):
|
||||||
|
folder_name = os.path.basename(self._workspace_path)
|
||||||
|
workspace_uri = f"file://{self._workspace_path}"
|
||||||
|
|
||||||
|
self._init_params["processId"] = None
|
||||||
|
self._init_params["rootPath"] = self._workspace_path
|
||||||
|
self._init_params["rootUri"] = workspace_uri
|
||||||
|
self._init_params["workspaceFolders"] = [
|
||||||
|
{
|
||||||
|
"name": folder_name,
|
||||||
|
"uri": workspace_uri
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
self._init_params["initializationOptions"] = self._init_opts
|
||||||
|
self.send_request("initialize", self._init_params)
|
||||||
|
|
||||||
|
def send_initialized_notification(self):
|
||||||
|
self.send_notification("initialized")
|
||||||
|
|
||||||
|
def send_shutdown_request(self):
|
||||||
|
self.send_request("shutdown")
|
||||||
|
|
||||||
|
def send_exit_notification(self):
|
||||||
|
self.send_notification("exit")
|
||||||
|
|
||||||
|
def _lsp_did_open(self, data: dict):
|
||||||
|
method = "textDocument/didOpen"
|
||||||
|
params = didopen_notification["params"]
|
||||||
|
self.doc_vers[ data["uri"] ] = -1
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["textDocument"]["languageId"] = data["language_id"]
|
||||||
|
params["textDocument"]["text"] = data["text"]
|
||||||
|
|
||||||
|
self.send_notification( method, params )
|
||||||
|
|
||||||
|
def _lsp_did_save(self, data: dict):
|
||||||
|
method = "textDocument/didSave"
|
||||||
|
params = didsave_notification["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["text"] = data["text"]
|
||||||
|
|
||||||
|
self.send_notification( method, params )
|
||||||
|
|
||||||
|
def _lsp_did_close(self, data: dict):
|
||||||
|
method = "textDocument/didClose"
|
||||||
|
params = didclose_notification["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
|
||||||
|
self.send_notification( method, params )
|
||||||
|
|
||||||
|
def _lsp_did_change(self, data: dict):
|
||||||
|
method = "textDocument/didChange"
|
||||||
|
params = didchange_notification["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["textDocument"]["languageId"] = data["language_id"]
|
||||||
|
params["textDocument"]["version"] = data["version"]
|
||||||
|
|
||||||
|
contentChanges = params["contentChanges"][0]
|
||||||
|
contentChanges["text"] = data["text"]
|
||||||
|
|
||||||
|
self.send_notification( method, params )
|
||||||
|
|
||||||
|
def _lsp_did_change_range(self, data: dict):
|
||||||
|
method = "textDocument/didChange"
|
||||||
|
params = didchange_notification_range["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["textDocument"]["languageId"] = data["language_id"]
|
||||||
|
params["textDocument"]["version"] = data["version"]
|
||||||
|
|
||||||
|
contentChanges = params["contentChanges"][0]
|
||||||
|
start = contentChanges["range"]["start"]
|
||||||
|
end = contentChanges["range"]["end"]
|
||||||
|
contentChanges["text"] = data["text"]
|
||||||
|
start["line"] = data["line"]
|
||||||
|
start["character"] = data["column"]
|
||||||
|
end["line"] = data["end_line"]
|
||||||
|
end["character"] = data["end_column"]
|
||||||
|
|
||||||
|
self.send_notification( method, params )
|
||||||
|
|
||||||
|
def _lsp_definition(self, data: dict):
|
||||||
|
method = "textDocument/definition"
|
||||||
|
params = definition_request["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["textDocument"]["languageId"] = data["language_id"]
|
||||||
|
params["textDocument"]["version"] = data["version"]
|
||||||
|
params["position"]["line"] = data["line"]
|
||||||
|
params["position"]["character"] = data["column"]
|
||||||
|
|
||||||
|
self.send_request( method, params )
|
||||||
|
|
||||||
|
def _lsp_implementation(self, data: dict):
|
||||||
|
method = "textDocument/implementation"
|
||||||
|
params = implementation_request["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["position"]["line"] = data["line"]
|
||||||
|
params["position"]["character"] = data["column"]
|
||||||
|
|
||||||
|
self.send_request( method, params )
|
||||||
|
|
||||||
|
def _lsp_references(self, data: dict):
|
||||||
|
method = "textDocument/references"
|
||||||
|
params = references_request["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["textDocument"]["languageId"] = data["language_id"]
|
||||||
|
params["textDocument"]["version"] = data["version"]
|
||||||
|
params["position"]["line"] = data["line"]
|
||||||
|
params["position"]["character"] = data["column"]
|
||||||
|
|
||||||
|
self.send_request( method, params )
|
||||||
|
|
||||||
|
def _lsp_completion(self, data: dict):
|
||||||
|
method = "textDocument/completion"
|
||||||
|
params = completion_request["params"]
|
||||||
|
|
||||||
|
params["textDocument"]["uri"] = data["uri"]
|
||||||
|
params["position"]["line"] = data["line"]
|
||||||
|
params["position"]["character"] = data["column"]
|
||||||
|
|
||||||
|
self.send_request( method, params )
|
||||||
|
|
||||||
|
def _lsp_java_class_file_contents(self, uri: str):
|
||||||
|
method = "java/classFileContents"
|
||||||
|
params = {
|
||||||
|
"uri": uri
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send_request( method, params )
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
# from libs import websockets
|
||||||
|
from ..dto.code.lsp.lsp_messages import get_message_str, get_message_obj
|
||||||
|
from ..dto.code.lsp.lsp_message_structs import \
|
||||||
|
LSPResponseTypes, ClientRequest, ClientNotification, \
|
||||||
|
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
|
||||||
|
|
||||||
|
from .lsp_client_base import LSPClientBase
|
||||||
|
from .websocket import Websocket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPClientWebsocket(LSPClientBase):
|
||||||
|
def _send_message(self, data: ClientRequest | ClientNotification):
|
||||||
|
if not data: return
|
||||||
|
|
||||||
|
message_str = get_message_str(data)
|
||||||
|
message_size = len(message_str)
|
||||||
|
message = f"Content-Length: {message_size}\r\n\r\n{message_str}"
|
||||||
|
|
||||||
|
logger.debug(f"Client: {message_str}")
|
||||||
|
self.websocket.send(message_str)
|
||||||
|
|
||||||
|
def start_client(self):
|
||||||
|
self.websocket = Websocket()
|
||||||
|
self.websocket.set_socket(self._socket)
|
||||||
|
self.websocket.set_callback(self._monitor_lsp_response)
|
||||||
|
self.websocket.start_client()
|
||||||
|
|
||||||
|
return self.websocket
|
||||||
|
|
||||||
|
def stop_client(self):
|
||||||
|
if not hasattr(self, "websocket"): return
|
||||||
|
self.websocket.close_client()
|
||||||
|
|
||||||
|
def _monitor_lsp_response(self, data: dict | None):
|
||||||
|
if not data: return {}
|
||||||
|
|
||||||
|
message = get_message_obj(data)
|
||||||
|
keys = message.keys()
|
||||||
|
lsp_response = data
|
||||||
|
|
||||||
|
if "result" in keys:
|
||||||
|
lsp_response = LSPResponseRequest(**get_message_obj(data))
|
||||||
|
|
||||||
|
if "method" in keys:
|
||||||
|
lsp_response = LSPResponseNotification(**get_message_obj(data)) if not "id" in keys else LSPIDResponseNotification( **get_message_obj(data) )
|
||||||
|
|
||||||
|
if isinstance(lsp_response, str):
|
||||||
|
lsp_response = get_message_obj(lsp_response)
|
||||||
|
|
||||||
|
GLib.idle_add(self.handle_lsp_response, lsp_response)
|
||||||
@@ -9,7 +9,7 @@ from ..libs import websocket
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebsocketClient:
|
class Websocket:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ws = None
|
self.ws = None
|
||||||
self._socket = None
|
self._socket = None
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Python imports
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .config import get_lsp_connect_timout
|
||||||
|
from .mixins.client_manager_events_mixin import ClientManagerEventsMixin
|
||||||
|
from .client.lsp_client import LSPClient
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ClientManager(ClientManagerEventsMixin):
|
||||||
|
def __init__(self):
|
||||||
|
super(ClientManager, self).__init__()
|
||||||
|
|
||||||
|
self._cache_refresh_timeout_id: int = None
|
||||||
|
|
||||||
|
self.executor: ThreadPoolExecutor = ThreadPoolExecutor(max_workers = 1)
|
||||||
|
self.active_language_id: str = ""
|
||||||
|
self.clients: dict = {}
|
||||||
|
|
||||||
|
|
||||||
|
def create_client(
|
||||||
|
self,
|
||||||
|
lang_id: str,
|
||||||
|
workspace_path: str,
|
||||||
|
init_opts: dict[str, str],
|
||||||
|
address: str = "127.0.0.1",
|
||||||
|
port: str = "9999"
|
||||||
|
) -> LSPClient:
|
||||||
|
if lang_id in self.clients: return None
|
||||||
|
|
||||||
|
uri = f"ws://{address}:{port}/{lang_id}?workspace={workspace_path}"
|
||||||
|
client = LSPClient()
|
||||||
|
|
||||||
|
client.set_socket(uri)
|
||||||
|
client.set_language(lang_id)
|
||||||
|
client.set_workspace_path(workspace_path)
|
||||||
|
client.set_init_opts(init_opts)
|
||||||
|
client.start_client()
|
||||||
|
|
||||||
|
if not client.websocket.wait_for_connection(timeout = get_lsp_connect_timout()):
|
||||||
|
logger.error(f"Failed to connect to LSP server for {lang_id}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.clients[lang_id] = client
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
def close_client(self, lang_id: str) -> bool:
|
||||||
|
if lang_id not in self.clients: return False
|
||||||
|
|
||||||
|
controller = self.clients.pop(lang_id)
|
||||||
|
controller.stop_client()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_active_client(self) -> LSPClient:
|
||||||
|
return self.clients[self.active_language_id]
|
||||||
87
plugins/code/language_server_clients/lsp_manager/commands.py
Normal file
87
plugins/code/language_server_clients/lsp_manager/commands.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Commands:
|
||||||
|
lsp_manager: callable = None
|
||||||
|
|
||||||
|
class lsp_manager_toggle:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
source_view: GtkSource,
|
||||||
|
char_str: str,
|
||||||
|
modkeys_states: tuple
|
||||||
|
):
|
||||||
|
logger.debug("Command: LSP Manager Toggle")
|
||||||
|
if Commands.lsp_manager.ui_manager.is_visible():
|
||||||
|
Commands.lsp_manager.ui_manager.hide()
|
||||||
|
else:
|
||||||
|
Commands.lsp_manager.ui_manager.show()
|
||||||
|
|
||||||
|
class lsp_references:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: GtkSource,
|
||||||
|
char_str: str,
|
||||||
|
modkeys_states: tuple
|
||||||
|
):
|
||||||
|
logger.debug("Command: LSP References")
|
||||||
|
|
||||||
|
file = view.command.exec("get_current_file")
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
line = iter.get_line()
|
||||||
|
column = iter.get_line_offset()
|
||||||
|
|
||||||
|
Commands.lsp_manager.client_manager.process_references_definition(
|
||||||
|
file.ftype, file.fpath, line, column
|
||||||
|
)
|
||||||
|
|
||||||
|
class lsp_implementation:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: GtkSource,
|
||||||
|
char_str: str,
|
||||||
|
modkeys_states: tuple
|
||||||
|
):
|
||||||
|
logger.debug("Command: LSP Implements")
|
||||||
|
|
||||||
|
file = view.command.exec("get_current_file")
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
line = iter.get_line()
|
||||||
|
column = iter.get_line_offset()
|
||||||
|
|
||||||
|
Commands.lsp_manager.client_manager.process_implementation_definition(
|
||||||
|
file.ftype, file.fpath, line, column
|
||||||
|
)
|
||||||
|
|
||||||
|
class lsp_definition:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: GtkSource,
|
||||||
|
char_str: str,
|
||||||
|
modkeys_states: tuple
|
||||||
|
):
|
||||||
|
logger.debug("Command: LSP Definition (Go-To)")
|
||||||
|
|
||||||
|
file = view.command.exec("get_current_file")
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
line = iter.get_line()
|
||||||
|
column = iter.get_line_offset()
|
||||||
|
|
||||||
|
Commands.lsp_manager.client_manager.process_definition(
|
||||||
|
file.ftype, file.fpath, line, column
|
||||||
|
)
|
||||||
38
plugins/code/language_server_clients/lsp_manager/config.py
Normal file
38
plugins/code/language_server_clients/lsp_manager/config.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Python imports
|
||||||
|
from os import path
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LSP_HOST: str = "127.0.0.1"
|
||||||
|
LSP_PORT: int = 9999
|
||||||
|
LSP_CONNECT_TIMOUT: float = 5.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_lsp_host_addr() -> str:
|
||||||
|
return LSP_HOST
|
||||||
|
|
||||||
|
def get_lsp_host_port() -> int:
|
||||||
|
return LSP_PORT
|
||||||
|
|
||||||
|
def get_lsp_connect_timout() -> float:
|
||||||
|
return LSP_CONNECT_TIMOUT
|
||||||
|
|
||||||
|
def get_lsp_init_config() -> dict:
|
||||||
|
try:
|
||||||
|
_USER_HOME = path.expanduser('~')
|
||||||
|
_SCRIPT_PTH = path.dirname( path.realpath(__file__) )
|
||||||
|
_LSP_INIT_CONFIG = f"{_SCRIPT_PTH}/configs/initialize-params-slim.json"
|
||||||
|
|
||||||
|
with open(_LSP_INIT_CONFIG) as file:
|
||||||
|
data = file.read()
|
||||||
|
return json.loads(data)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error( f"LSP Controller: {_LSP_INIT_CONFIG}\n\t\t{repr(e)}" )
|
||||||
|
|
||||||
|
return {}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Libs Code DTO(s) Events Package
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .lsp_event import LspEvent
|
||||||
|
|
||||||
|
from .register_lsp_client_event import RegisterLspClientEvent
|
||||||
|
from .unregister_lsp_client_event import UnregisterLspClientEvent
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.dto.code.events import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LspEvent(CodeEvent):
|
||||||
|
...
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from ....response_handlers.base_handler import BaseHandler
|
||||||
|
|
||||||
|
from .lsp_event import LspEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RegisterLspClientEvent(LspEvent):
|
||||||
|
lang_id: str = ""
|
||||||
|
lang_config: str = "{}"
|
||||||
|
handler: BaseHandler = None
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .lsp_event import LspEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UnregisterLspClientEvent(LspEvent):
|
||||||
|
lang_id: str = ""
|
||||||
@@ -96,10 +96,10 @@ didchange_notification_range = {
|
|||||||
"uri": "file://",
|
"uri": "file://",
|
||||||
"languageId": "python",
|
"languageId": "python",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": ""
|
|
||||||
},
|
},
|
||||||
"contentChanges": [
|
"contentChanges": [
|
||||||
{
|
{
|
||||||
|
"text": "",
|
||||||
"range": {
|
"range": {
|
||||||
"start": {
|
"start": {
|
||||||
"line": 1,
|
"line": 1,
|
||||||
@@ -108,9 +108,8 @@ didchange_notification_range = {
|
|||||||
"end": {
|
"end": {
|
||||||
"line": 1,
|
"line": 1,
|
||||||
"character": 1,
|
"character": 1,
|
||||||
},
|
|
||||||
"rangeLength": 0
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -125,19 +124,11 @@ completion_request = {
|
|||||||
"method": "textDocument/completion",
|
"method": "textDocument/completion",
|
||||||
"params": {
|
"params": {
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file://",
|
"uri": "file://"
|
||||||
"languageId": "python",
|
|
||||||
"version": 1,
|
|
||||||
"text": ""
|
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"line": 5,
|
"line": 5,
|
||||||
"character": 12,
|
"character": 12
|
||||||
"offset": 0
|
|
||||||
},
|
|
||||||
"contet": {
|
|
||||||
"triggerKind": 3,
|
|
||||||
"triggerCharacter": ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,6 +150,19 @@ definition_request = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implementation_request = {
|
||||||
|
"method": "textDocument/implementation",
|
||||||
|
"params": {
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file://"
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"line": 5,
|
||||||
|
"character": 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
references_request = {
|
references_request = {
|
||||||
"method": "textDocument/references",
|
"method": "textDocument/references",
|
||||||
"params": {
|
"params": {
|
||||||
@@ -179,7 +183,6 @@ references_request = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
symbols_request = {
|
symbols_request = {
|
||||||
"method": "textDocument/documentSymbol",
|
"method": "textDocument/documentSymbol",
|
||||||
"params": {
|
"params": {
|
||||||
@@ -191,3 +194,14 @@ symbols_request = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shutdown_request = {
|
||||||
|
"method": "shutdown",
|
||||||
|
"params": None
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_request = {
|
||||||
|
"method": "exit",
|
||||||
|
"params": None
|
||||||
|
}
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user