Compare commits
7 Commits
cb73f6b3b0
...
release/ne
| Author | SHA1 | Date | |
|---|---|---|---|
| 69e766dc28 | |||
| 5911f37449 | |||
| 6e46279da4 | |||
| d90415bffc | |||
| 62a866d9bb | |||
| dc2997ec16 | |||
| 70877a7ee1 |
5
TODO.md
5
TODO.md
@@ -1,10 +1,7 @@
|
||||
___
|
||||
### Add
|
||||
1. Add TreeSitter
|
||||
1. Add Collapsable code blocks
|
||||
1. Add Godot LSP Client
|
||||
1. Add Terminal plugin
|
||||
1. Add Plugin to <Shift\><Ctrl\>| and <Ctrl\>| to split views up, down, left, right
|
||||
1. Add <Ctrl\>i to **lsp_manager** to list who implements xyz
|
||||
|
||||
___
|
||||
@@ -14,6 +11,8 @@ ___
|
||||
|
||||
___
|
||||
### Fix
|
||||
- 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?
|
||||
- Fix on lsp client unload to close files lsp side and unload server endpoint
|
||||
|
||||
___
|
||||
|
||||
3
plugins/code/commands/split_pane_manager/__init__.py
Normal file
3
plugins/code/commands/split_pane_manager/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/commands/split_pane_manager/__main__.py
Normal file
3
plugins/code/commands/split_pane_manager/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
64
plugins/code/commands/split_pane_manager/close_split_view.py
Normal file
64
plugins/code/commands/split_pane_manager/close_split_view.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# 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 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 = remaining.get_child()
|
||||
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()
|
||||
@@ -0,0 +1,66 @@
|
||||
# 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)
|
||||
|
||||
pane.show_all()
|
||||
|
||||
is_control, is_shift, is_alt = modkeys_states
|
||||
if is_control and is_shift:
|
||||
pane.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
elif is_control:
|
||||
pane.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
source_view2.grab_focus()
|
||||
source_view2.command.exec("new_file")
|
||||
@@ -7,6 +7,7 @@ gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
@@ -18,5 +19,4 @@ def execute(
|
||||
):
|
||||
logger.debug("Command: Focus Left Sibling")
|
||||
if not view.sibling_left: return
|
||||
view.sibling_left.get_parent().show()
|
||||
view.sibling_left.grab_focus()
|
||||
@@ -18,5 +18,4 @@ def execute(
|
||||
):
|
||||
logger.debug("Command: Focus Right Sibling")
|
||||
if not view.sibling_right: return
|
||||
view.sibling_right.get_parent().show()
|
||||
view.sibling_right.grab_focus()
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Toggle Source View",
|
||||
"name": "Split Pane Manager",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
100
plugins/code/commands/split_pane_manager/plugin.py
Normal file
100
plugins/code/commands/split_pane_manager/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 = "<Shift><Control>w"
|
||||
)
|
||||
|
||||
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,3 +0,0 @@
|
||||
"""
|
||||
Plugin Module
|
||||
"""
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Plugin Package
|
||||
"""
|
||||
@@ -1,64 +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 unload(self):
|
||||
event = Event_Factory.create_event("unregister_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()
|
||||
|
||||
@@ -17,13 +17,22 @@ class Plugin(PluginCode):
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, Code_Event_Types.TextChangedEvent):
|
||||
event.file.check_file_on_disk()
|
||||
if not isinstance(event, Code_Event_Types.FocusedViewEvent): return
|
||||
event = Event_Factory.create_event(
|
||||
"get_file", buffer = event.view.get_buffer()
|
||||
)
|
||||
self.emit_to("files", event)
|
||||
|
||||
if event.file.is_deleted():
|
||||
file_is_deleted(event, self.emit)
|
||||
elif event.file.is_externally_modified():
|
||||
file_is_externally_modified(event, self.emit)
|
||||
file = event.response
|
||||
if not file: return
|
||||
if file.ftype == "buffer": return
|
||||
|
||||
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):
|
||||
...
|
||||
|
||||
@@ -10,23 +10,45 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
|
||||
|
||||
def file_is_deleted(event, emit):
|
||||
event.file.was_deleted = True
|
||||
def ask_yes_no(message):
|
||||
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(
|
||||
"file_externally_deleted",
|
||||
file = event.file,
|
||||
buffer = event.buffer
|
||||
file = file,
|
||||
buffer = file.buffer
|
||||
)
|
||||
emit(event)
|
||||
|
||||
|
||||
def file_is_externally_modified(event, emit):
|
||||
# event = Event_Factory.create_event(
|
||||
# "file_externally_modified",
|
||||
# file = event.file,
|
||||
# buffer = event.buffer
|
||||
# )
|
||||
# emit(event)
|
||||
def file_is_externally_modified(file, emit):
|
||||
event = Event_Factory.create_event(
|
||||
"file_externally_modified",
|
||||
file = file,
|
||||
buffer = file.buffer
|
||||
)
|
||||
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()
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
from .libs.tree_sitter_language_pack import \
|
||||
init, download, get_language, get_parser, available_languages, process, ProcessConfig
|
||||
|
||||
# Optional: Pre-download specific languages for offline use
|
||||
#init(["python", "javascript", "rust"])
|
||||
|
||||
# Get a language (auto-downloads if not cached)
|
||||
language = get_language("python")
|
||||
|
||||
# Get a pre-configured parser (auto-downloads if needed)
|
||||
parser = get_parser("python")
|
||||
tree = parser.parse(b"def hello(): pass")
|
||||
print(tree.root_node)
|
||||
|
||||
# List all available languages
|
||||
for lang in available_languages():
|
||||
print(lang)
|
||||
|
||||
|
||||
# Extract file intelligence (auto-downloads language if needed)
|
||||
result = process(
|
||||
"def hello(): pass",
|
||||
ProcessConfig( language = "python")
|
||||
)
|
||||
print(f"Functions: {len(result['structure'])}")
|
||||
|
||||
# Pre-download languages for offline use
|
||||
download(["python", "javascript"])
|
||||
|
||||
# With chunking
|
||||
result = process(
|
||||
source,
|
||||
ProcessConfig(
|
||||
language = "python",
|
||||
chunk_max_size = 1000,
|
||||
comments = True
|
||||
)
|
||||
)
|
||||
print(f"Chunks: {len(result['chunks'])}")
|
||||
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 "$@"
|
||||
@@ -1,54 +0,0 @@
|
||||
from typing import TypeAlias
|
||||
|
||||
from tree_sitter_language_pack._native import (
|
||||
DownloadError,
|
||||
LanguageNotFoundError,
|
||||
ParseError,
|
||||
ProcessConfig,
|
||||
QueryError,
|
||||
TreeHandle,
|
||||
available_languages,
|
||||
cache_dir,
|
||||
clean_cache,
|
||||
configure,
|
||||
download,
|
||||
download_all,
|
||||
downloaded_languages,
|
||||
get_binding,
|
||||
get_language,
|
||||
get_parser,
|
||||
has_language,
|
||||
init,
|
||||
language_count,
|
||||
manifest_languages,
|
||||
parse_string,
|
||||
process,
|
||||
)
|
||||
|
||||
SupportedLanguage: TypeAlias = str
|
||||
|
||||
__all__ = [
|
||||
"DownloadError",
|
||||
"LanguageNotFoundError",
|
||||
"ParseError",
|
||||
"ProcessConfig",
|
||||
"QueryError",
|
||||
"SupportedLanguage",
|
||||
"TreeHandle",
|
||||
"available_languages",
|
||||
"cache_dir",
|
||||
"clean_cache",
|
||||
"configure",
|
||||
"download",
|
||||
"download_all",
|
||||
"downloaded_languages",
|
||||
"get_binding",
|
||||
"get_language",
|
||||
"get_parser",
|
||||
"has_language",
|
||||
"init",
|
||||
"language_count",
|
||||
"manifest_languages",
|
||||
"parse_string",
|
||||
"process",
|
||||
]
|
||||
@@ -1,276 +0,0 @@
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
from tree_sitter import Language, Parser
|
||||
|
||||
class LanguageNotFoundError(ValueError): ...
|
||||
class DownloadError(RuntimeError): ...
|
||||
|
||||
SupportedLanguage: TypeAlias = Literal[
|
||||
"actionscript",
|
||||
"ada",
|
||||
"agda",
|
||||
"apex",
|
||||
"arduino",
|
||||
"asm",
|
||||
"astro",
|
||||
"bash",
|
||||
"batch",
|
||||
"bazel",
|
||||
"beancount",
|
||||
"bibtex",
|
||||
"bicep",
|
||||
"bitbake",
|
||||
"bsl",
|
||||
"c",
|
||||
"cairo",
|
||||
"capnp",
|
||||
"chatito",
|
||||
"clarity",
|
||||
"clojure",
|
||||
"cmake",
|
||||
"cobol",
|
||||
"comment",
|
||||
"commonlisp",
|
||||
"cpon",
|
||||
"cpp",
|
||||
"css",
|
||||
"csv",
|
||||
"cuda",
|
||||
"d",
|
||||
"dart",
|
||||
"diff",
|
||||
"dockerfile",
|
||||
"doxygen",
|
||||
"dtd",
|
||||
"elisp",
|
||||
"elixir",
|
||||
"elm",
|
||||
"erlang",
|
||||
"fennel",
|
||||
"firrtl",
|
||||
"fish",
|
||||
"fortran",
|
||||
"fsharp",
|
||||
"fsharp_signature",
|
||||
"func",
|
||||
"gdscript",
|
||||
"gitattributes",
|
||||
"gitcommit",
|
||||
"gitignore",
|
||||
"gleam",
|
||||
"glsl",
|
||||
"gn",
|
||||
"go",
|
||||
"gomod",
|
||||
"gosum",
|
||||
"gradle",
|
||||
"graphql",
|
||||
"groovy",
|
||||
"gstlaunch",
|
||||
"hack",
|
||||
"hare",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hcl",
|
||||
"heex",
|
||||
"hlsl",
|
||||
"html",
|
||||
"hyprlang",
|
||||
"ignorefile",
|
||||
"ini",
|
||||
"ispc",
|
||||
"janet",
|
||||
"java",
|
||||
"javascript",
|
||||
"jsdoc",
|
||||
"json",
|
||||
"jsonnet",
|
||||
"julia",
|
||||
"kconfig",
|
||||
"kdl",
|
||||
"kotlin",
|
||||
"latex",
|
||||
"linkerscript",
|
||||
"lisp",
|
||||
"llvm",
|
||||
"lua",
|
||||
"luadoc",
|
||||
"luap",
|
||||
"luau",
|
||||
"magik",
|
||||
"make",
|
||||
"makefile",
|
||||
"markdown",
|
||||
"markdown_inline",
|
||||
"matlab",
|
||||
"mermaid",
|
||||
"meson",
|
||||
"netlinx",
|
||||
"nim",
|
||||
"ninja",
|
||||
"nix",
|
||||
"nqc",
|
||||
"objc",
|
||||
"ocaml",
|
||||
"ocaml_interface",
|
||||
"odin",
|
||||
"org",
|
||||
"pascal",
|
||||
"pem",
|
||||
"perl",
|
||||
"pgn",
|
||||
"php",
|
||||
"pkl",
|
||||
"po",
|
||||
"pony",
|
||||
"powershell",
|
||||
"printf",
|
||||
"prisma",
|
||||
"properties",
|
||||
"proto",
|
||||
"psv",
|
||||
"puppet",
|
||||
"purescript",
|
||||
"pymanifest",
|
||||
"python",
|
||||
"qmldir",
|
||||
"qmljs",
|
||||
"query",
|
||||
"r",
|
||||
"racket",
|
||||
"re2c",
|
||||
"readline",
|
||||
"rego",
|
||||
"requirements",
|
||||
"ron",
|
||||
"rst",
|
||||
"ruby",
|
||||
"rust",
|
||||
"scala",
|
||||
"scheme",
|
||||
"scss",
|
||||
"shell",
|
||||
"smali",
|
||||
"smithy",
|
||||
"solidity",
|
||||
"sparql",
|
||||
"sql",
|
||||
"squirrel",
|
||||
"starlark",
|
||||
"svelte",
|
||||
"swift",
|
||||
"tablegen",
|
||||
"tcl",
|
||||
"terraform",
|
||||
"test",
|
||||
"thrift",
|
||||
"toml",
|
||||
"tsv",
|
||||
"tsx",
|
||||
"twig",
|
||||
"typescript",
|
||||
"typst",
|
||||
"udev",
|
||||
"ungrammar",
|
||||
"uxntal",
|
||||
"v",
|
||||
"verilog",
|
||||
"vhdl",
|
||||
"vim",
|
||||
"vue",
|
||||
"wast",
|
||||
"wat",
|
||||
"wgsl",
|
||||
"xcompose",
|
||||
"xml",
|
||||
"yuck",
|
||||
"zig",
|
||||
]
|
||||
|
||||
class ParseError(RuntimeError): ...
|
||||
class QueryError(ValueError): ...
|
||||
|
||||
class ProcessConfig:
|
||||
language: str
|
||||
structure: bool
|
||||
imports: bool
|
||||
exports: bool
|
||||
comments: bool
|
||||
docstrings: bool
|
||||
symbols: bool
|
||||
diagnostics: bool
|
||||
chunk_max_size: int | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
language: str,
|
||||
*,
|
||||
structure: bool = True,
|
||||
imports: bool = True,
|
||||
exports: bool = True,
|
||||
comments: bool = True,
|
||||
docstrings: bool = True,
|
||||
symbols: bool = True,
|
||||
diagnostics: bool = True,
|
||||
chunk_max_size: int | None = None,
|
||||
) -> None: ...
|
||||
@staticmethod
|
||||
def all(language: str) -> ProcessConfig: ...
|
||||
@staticmethod
|
||||
def minimal(language: str) -> ProcessConfig: ...
|
||||
|
||||
class TreeHandle:
|
||||
def root_node_type(self) -> str: ...
|
||||
def root_child_count(self) -> int: ...
|
||||
def contains_node_type(self, node_type: str) -> bool: ...
|
||||
def has_error_nodes(self) -> bool: ...
|
||||
def to_sexp(self) -> str: ...
|
||||
def error_count(self) -> int: ...
|
||||
def root_node_info(self) -> dict[str, object]: ...
|
||||
def find_nodes_by_type(self, node_type: str) -> list[dict[str, object]]: ...
|
||||
def named_children_info(self) -> list[dict[str, object]]: ...
|
||||
def extract_text(self, start_byte: int, end_byte: int) -> str: ...
|
||||
def run_query(self, language: str, query_source: str) -> list[dict[str, object]]: ...
|
||||
|
||||
__all__ = [
|
||||
"DownloadError",
|
||||
"LanguageNotFoundError",
|
||||
"ParseError",
|
||||
"ProcessConfig",
|
||||
"QueryError",
|
||||
"SupportedLanguage",
|
||||
"TreeHandle",
|
||||
"available_languages",
|
||||
"cache_dir",
|
||||
"clean_cache",
|
||||
"configure",
|
||||
"download",
|
||||
"download_all",
|
||||
"downloaded_languages",
|
||||
"get_binding",
|
||||
"get_language",
|
||||
"get_parser",
|
||||
"has_language",
|
||||
"init",
|
||||
"language_count",
|
||||
"manifest_languages",
|
||||
"parse_string",
|
||||
"process",
|
||||
]
|
||||
|
||||
def get_binding(name: SupportedLanguage) -> object: ...
|
||||
def get_language(name: SupportedLanguage) -> Language: ...
|
||||
def get_parser(name: SupportedLanguage) -> Parser: ...
|
||||
def available_languages() -> list[str]: ...
|
||||
def has_language(name: str) -> bool: ...
|
||||
def language_count() -> int: ...
|
||||
def parse_string(language: str, source: str) -> TreeHandle: ...
|
||||
def process(source: str, config: ProcessConfig) -> dict[str, object]: ...
|
||||
def init(config: dict[str, object]) -> None: ...
|
||||
def configure(*, cache_dir: str | None = None) -> None: ...
|
||||
def download(names: list[str]) -> int: ...
|
||||
def download_all() -> int: ...
|
||||
def manifest_languages() -> list[str]: ...
|
||||
def downloaded_languages() -> list[str]: ...
|
||||
def clean_cache() -> None: ...
|
||||
def cache_dir() -> str: ...
|
||||
@@ -4,6 +4,5 @@
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"pre_launch": true,
|
||||
"autoload": false,
|
||||
"requests": {}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from .tree_sitter import Language
|
||||
|
||||
Language.build_library(
|
||||
"my-languages.so",
|
||||
[
|
||||
"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",
|
||||
"tree-sitter-gdscript",
|
||||
],
|
||||
)
|
||||
@@ -1,121 +0,0 @@
|
||||
#!/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
|
||||
|
||||
|
||||
|
||||
|
||||
function old_build() {
|
||||
touch __init__.py
|
||||
|
||||
cat <<'EOF' > compile.py
|
||||
from tree_sitter import Language
|
||||
|
||||
Language.build_library(
|
||||
"my-languages.so",
|
||||
[
|
||||
"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"
|
||||
"tree-sitter-gdscript",
|
||||
],
|
||||
)
|
||||
EOF
|
||||
|
||||
python compile.py
|
||||
cd ..
|
||||
}
|
||||
|
||||
function build() {
|
||||
touch __init__.py
|
||||
|
||||
cat <<'EOF' > compile.py
|
||||
from tree_sitter_language_pack import init, download, get_language, get_parser, available_languages
|
||||
from tree_sitter_language_pack import process, ProcessConfig
|
||||
|
||||
# Optional: Pre-download specific languages for offline use
|
||||
# init(["python", "javascript", "rust"])
|
||||
|
||||
# Get a language (auto-downloads if not cached)
|
||||
language = get_language("python")
|
||||
|
||||
# Get a pre-configured parser (auto-downloads if needed)
|
||||
parser = get_parser("python")
|
||||
tree = parser.parse(b"def hello(): pass")
|
||||
print(tree.root_node)
|
||||
|
||||
# List all available languages
|
||||
for lang in available_languages():
|
||||
print(lang)
|
||||
|
||||
|
||||
# Extract file intelligence (auto-downloads language if needed)
|
||||
result = process(
|
||||
"def hello(): pass",
|
||||
ProcessConfig(
|
||||
language = "python"
|
||||
)
|
||||
)
|
||||
print(f"Functions: {len(result['structure'])}")
|
||||
|
||||
# Pre-download languages for offline use
|
||||
download(["python", "javascript"])
|
||||
|
||||
# With chunking
|
||||
result = process(
|
||||
source,
|
||||
ProcessConfig(
|
||||
language = "python",
|
||||
chunk_max_size = 1000,
|
||||
comments = True
|
||||
)
|
||||
)
|
||||
print(f"Chunks: {len(result['chunks'])}")
|
||||
|
||||
EOF
|
||||
|
||||
python compile.py
|
||||
cd ..
|
||||
}
|
||||
|
||||
function clone() {
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-python
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-javascript
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-html
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-css
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-json
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-java
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-c
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-cpp
|
||||
git clone --depth 1 https://github.com/tree-sitter/tree-sitter-go
|
||||
# git clone --depth 1 https://github.com/godotengine/tree-sitter-gdscript
|
||||
}
|
||||
|
||||
function setup() {
|
||||
# pip install tree-sitter -t .
|
||||
pip install tree-sitter-language-pack -t .
|
||||
# pip install tree_sitter_languages -t . # Old unmaintained library
|
||||
}
|
||||
|
||||
function main() {
|
||||
cd "$(dirname "$0")"
|
||||
echo "Working Dir: " $(pwd)
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
# clone "$@"
|
||||
setup "$@"
|
||||
build "$@"
|
||||
}
|
||||
main "$@";
|
||||
@@ -1,14 +1,4 @@
|
||||
# Python imports
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
BASE_DIR = os.path.dirname( os.path.realpath(__file__) )
|
||||
LIBS_DIR = f"{BASE_DIR}/libs"
|
||||
|
||||
if str(LIBS_DIR) not in sys.path:
|
||||
sys.path.insert(0, LIBS_DIR)
|
||||
|
||||
|
||||
# Lib imports
|
||||
|
||||
@@ -17,7 +7,7 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
import tree_sitter_language_pack as tslp
|
||||
from .tree_sitter import Parser, get_parser
|
||||
|
||||
|
||||
|
||||
@@ -26,52 +16,48 @@ class Plugin(PluginCode):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, Code_Event_Types.TextChangedEvent):
|
||||
if not tslp.has_language( event.file.ftype ):
|
||||
try:
|
||||
tslp.download( [event.file.ftype] )
|
||||
except Exception:
|
||||
logger.info(
|
||||
f"Tree Sitter Language Pack:\nCouldn't download -> '{event.file.ftype}' language type..."
|
||||
)
|
||||
return
|
||||
def set_ast(self, file):
|
||||
if not hasattr(file, "tree_sitter"):
|
||||
parser = get_parser( file.ftype )
|
||||
if not parser: return
|
||||
|
||||
buffer = event.file.buffer
|
||||
file.tree_sitter = parser
|
||||
|
||||
buffer = file.buffer
|
||||
start_itr, \
|
||||
end_itr = buffer.get_bounds()
|
||||
text = buffer.get_text(start_itr, end_itr, True)
|
||||
result = tslp.process(
|
||||
text,
|
||||
tslp.ProcessConfig(
|
||||
language = event.file.ftype
|
||||
)
|
||||
)
|
||||
|
||||
event.file.tree_sitter_meta = result
|
||||
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):
|
||||
tslp.configure(
|
||||
cache_dir = f"{BASE_DIR}/cache/tree-sitter-language-pack/v1.0.0/libs"
|
||||
)
|
||||
...
|
||||
|
||||
def unload(self):
|
||||
...
|
||||
|
||||
def run(self):
|
||||
# tslp.download(
|
||||
# [
|
||||
# "python",
|
||||
# "java",
|
||||
# "go",
|
||||
# "c",
|
||||
# "cpp",
|
||||
# "javascript",
|
||||
# "html",
|
||||
# "css",
|
||||
# "json"
|
||||
# ]
|
||||
# )
|
||||
# "gdscript"
|
||||
|
||||
...
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"socket": "ws://127.0.0.1:9999/gdscript",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=gdscript",
|
||||
"initialization-options": {
|
||||
"processId": ,
|
||||
"processId": null,
|
||||
"clientInfo": {
|
||||
"name": "Godot",
|
||||
"version": "4.4"
|
||||
|
||||
@@ -19,13 +19,10 @@ class LSPClient(LSPClientWebsocket):
|
||||
def __init__(self):
|
||||
super(LSPClient, self).__init__()
|
||||
|
||||
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
|
||||
# initialize-params-slim.json was created off of jedi_language_server one
|
||||
# self._init_params = settings_manager.get_lsp_init_data()
|
||||
|
||||
self._language: str = ""
|
||||
self._workspace_path: str = ""
|
||||
self._init_params: dict = {}
|
||||
self._event_history: dict[int, str] = {}
|
||||
self._init_opts: dict = {}
|
||||
|
||||
try:
|
||||
_USER_HOME = path.expanduser('~')
|
||||
@@ -33,19 +30,29 @@ class LSPClient(LSPClientWebsocket):
|
||||
_LSP_INIT_CONFIG = f"{_SCRIPT_PTH}/../configs/initialize-params-slim.json"
|
||||
|
||||
with open(_LSP_INIT_CONFIG) as file:
|
||||
data = file.read().replace("{user.home}", _USER_HOME)
|
||||
data = file.read()
|
||||
self._init_params = json.loads(data)
|
||||
except Exception as e:
|
||||
logger.error( f"LSP Controller: {_LSP_INIT_CONFIG}\n\t\t{repr(e)}" )
|
||||
|
||||
self._message_id: int = -1
|
||||
|
||||
self._socket = None
|
||||
self._message_id: int = -1
|
||||
self._event_history: dict[int, str] = {}
|
||||
|
||||
self.read_lock = threading.Lock()
|
||||
self.write_lock = threading.Lock()
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ from ..dto.code.lsp.lsp_messages import symbols_request
|
||||
|
||||
|
||||
class LSPClientEvents:
|
||||
def send_initialize_message(self, init_ops: dict, workspace_file: str, workspace_uri: str):
|
||||
folder_name = os.path.basename(workspace_file)
|
||||
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"] = workspace_file
|
||||
self._init_params["rootPath"] = self._workspace_path
|
||||
self._init_params["rootUri"] = workspace_uri
|
||||
self._init_params["workspaceFolders"] = [
|
||||
{
|
||||
@@ -30,7 +31,7 @@ class LSPClientEvents:
|
||||
}
|
||||
]
|
||||
|
||||
self._init_params["initializationOptions"] = init_ops
|
||||
self._init_params["initializationOptions"] = self._init_opts
|
||||
self.send_request("initialize", self._init_params)
|
||||
|
||||
def send_initialized_message(self):
|
||||
|
||||
@@ -54,17 +54,21 @@ class LSPManager(ControllerBase):
|
||||
self.response_registry.unregister_handler(event.lang_id)
|
||||
self.lsp_manager_ui.remove_client_listing(event.lang_id)
|
||||
|
||||
def _on_create_client(self, ui, lang_id: str, workspace_uri: str) -> bool:
|
||||
def _on_create_client(self, ui, lang_id: str, workspace_path: str) -> bool:
|
||||
init_opts = ui.get_init_opts(lang_id)
|
||||
result = self.create_client(lang_id, workspace_uri, init_opts)
|
||||
result = self.create_client(lang_id, workspace_path, init_opts)
|
||||
|
||||
if result:
|
||||
ui.toggle_client_buttons(show_close = True)
|
||||
|
||||
return result
|
||||
|
||||
def _on_close_client(self, ui, lang_id: str) -> bool:
|
||||
result = self.close_client(lang_id)
|
||||
|
||||
if result:
|
||||
ui.toggle_client_buttons(show_close = False)
|
||||
|
||||
return result
|
||||
|
||||
def handle_destroy(self):
|
||||
@@ -73,12 +77,12 @@ class LSPManager(ControllerBase):
|
||||
|
||||
def create_client(
|
||||
self,
|
||||
lang_id: str = "python",
|
||||
workspace_uri: str = "",
|
||||
init_opts: dict = {}
|
||||
lang_id: str,
|
||||
workspace_path: str,
|
||||
init_opts: dict[str, str]
|
||||
) -> bool:
|
||||
client = self.lsp_manager_client.create_client(
|
||||
lang_id, workspace_uri, init_opts
|
||||
lang_id, workspace_path, init_opts
|
||||
)
|
||||
handler = self.response_registry.get_handler(lang_id)
|
||||
self.lsp_manager_client.active_language_id = lang_id
|
||||
@@ -92,7 +96,7 @@ class LSPManager(ControllerBase):
|
||||
handler.set_response_cache(self.response_cache)
|
||||
|
||||
client.handle_lsp_response = self.server_response
|
||||
client.send_initialize_message(init_opts, "", f"file://{workspace_uri}")
|
||||
client.send_initialize_message()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ class LSPManagerClient(LSPClientEventsMixin):
|
||||
|
||||
def create_client(
|
||||
self,
|
||||
lang_id: str = "python",
|
||||
workspace_uri: str = "",
|
||||
init_opts: dict = {}
|
||||
lang_id: str,
|
||||
workspace_path: str,
|
||||
init_opts: dict[str, str]
|
||||
) -> LSPClient:
|
||||
if lang_id in self.clients: return None
|
||||
|
||||
@@ -33,8 +33,10 @@ class LSPManagerClient(LSPClientEventsMixin):
|
||||
uri = f"ws://{address}:{port}/{lang_id}"
|
||||
client = LSPClient()
|
||||
|
||||
client.set_language(lang_id)
|
||||
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.ws_client.wait_for_connection(timeout = 5.0):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Python imports
|
||||
from os import path
|
||||
import json
|
||||
|
||||
# Lib imports
|
||||
@@ -24,6 +25,8 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
def __init__(self):
|
||||
super(LSPManagerUI, self).__init__()
|
||||
|
||||
self._USER_HOME = path.expanduser('~')
|
||||
|
||||
self.client_configs: dict[str, str] = {}
|
||||
|
||||
self.source_view = None
|
||||
@@ -167,9 +170,11 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
if not lang_id: return
|
||||
|
||||
json_str = self.client_configs[lang_id].replace("{workspace.folder}", workspace_dir)
|
||||
buffer = self.source_view.get_buffer()
|
||||
json_str = self.client_configs[lang_id] \
|
||||
.replace("{workspace.folder}", workspace_dir) \
|
||||
.replace("{user.home}", self._USER_HOME)
|
||||
|
||||
buffer = self.source_view.get_buffer()
|
||||
buffer.set_text(json_str, -1)
|
||||
|
||||
def map_parent_resize_event(self, parent):
|
||||
@@ -204,7 +209,7 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
model = self.combo_box.get_model()
|
||||
|
||||
for i, row in enumerate(model):
|
||||
if row[0] == lang_id: # assuming text is in column 0
|
||||
if row[0] == lang_id:
|
||||
self.combo_box.remove(i)
|
||||
break
|
||||
|
||||
@@ -215,7 +220,9 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
if not lang_id or lang_id not in self.client_configs: return {}
|
||||
|
||||
try:
|
||||
lang_config = json.loads(self.client_configs[lang_id])
|
||||
buffer = self.source_view.get_buffer()
|
||||
json_str = buffer.get_text(*buffer.get_bounds(), -1)
|
||||
lang_config = json.loads(json_str)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Invalid JSON for {lang_id}: {e}")
|
||||
return {}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"info": "https://github.com/python-lsp/python-lsp-server",
|
||||
"command": "lsp-ws-proxy -- pylsp",
|
||||
"alt-command": "pylsp",
|
||||
"alt-command2": "lsp-ws-proxy --listen 4114 -- pylsp",
|
||||
"alt-command3": "pylsp --ws --port 4114",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=pylsp",
|
||||
"initialization-options": {
|
||||
"pylsp": {
|
||||
"rope": {
|
||||
"ropeFolder": "{user.home}/.config/newton/lsps/ropeproject"
|
||||
},
|
||||
"plugins": {
|
||||
"ruff": {
|
||||
"enabled": true,
|
||||
"extendSelect": ["I"],
|
||||
"lineLength": 80
|
||||
},
|
||||
"pycodestyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pyflakes": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylint": {
|
||||
"enabled": true
|
||||
},
|
||||
"mccabe": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylsp_rope": {
|
||||
"rename": false
|
||||
},
|
||||
"rope_rename": {
|
||||
"enabled": false
|
||||
},
|
||||
"rope_autoimport": {
|
||||
"enabled": true
|
||||
},
|
||||
"rope_completion": {
|
||||
"enabled": false,
|
||||
"eager": false
|
||||
},
|
||||
"jedi_rename": {
|
||||
"enabled": true
|
||||
},
|
||||
"jedi_completion": {
|
||||
"enabled": true,
|
||||
"include_class_objects": true,
|
||||
"include_function_objects": true,
|
||||
"fuzzy": false
|
||||
},
|
||||
"jedi": {
|
||||
"root_dir": "file://{workspace.folder}",
|
||||
"extra_paths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"python - jedi-language-server": {
|
||||
"hidden": true,
|
||||
"info": "https://pypi.org/project/jedi-language-server/",
|
||||
"command": "jedi-language-server",
|
||||
"alt-command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jedi-language-server",
|
||||
"initialization-options": {
|
||||
"jediSettings": {
|
||||
"autoImportModules": [],
|
||||
"caseInsensitiveCompletion": true,
|
||||
"debug": false
|
||||
},
|
||||
"completion": {
|
||||
"disableSnippets": false,
|
||||
"resolveEagerly": false,
|
||||
"ignorePatterns": []
|
||||
},
|
||||
"markupKindPreferred": "markdown",
|
||||
"workspace": {
|
||||
"extraPaths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
],
|
||||
"environmentPath": "{user.home}/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
|
||||
"symbols": {
|
||||
"ignoreFolders": [
|
||||
".nox",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pycache__",
|
||||
"venv"
|
||||
],
|
||||
"maxSymbols": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,41 +60,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"python - jedi-language-server": {
|
||||
"hidden": true,
|
||||
"info": "https://pypi.org/project/jedi-language-server/",
|
||||
"command": "jedi-language-server",
|
||||
"alt-command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jedi-language-server",
|
||||
"initialization-options": {
|
||||
"jediSettings": {
|
||||
"autoImportModules": [],
|
||||
"caseInsensitiveCompletion": true,
|
||||
"debug": false
|
||||
},
|
||||
"completion": {
|
||||
"disableSnippets": false,
|
||||
"resolveEagerly": false,
|
||||
"ignorePatterns": []
|
||||
},
|
||||
"markupKindPreferred": "markdown",
|
||||
"workspace": {
|
||||
"extraPaths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
],
|
||||
"environmentPath": "{user.home}/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
|
||||
"symbols": {
|
||||
"ignoreFolders": [
|
||||
".nox",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pycache__",
|
||||
"venv"
|
||||
],
|
||||
"maxSymbols": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
plugins/code/ui/code_fold/__init__.py
Normal file
3
plugins/code/ui/code_fold/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/ui/code_fold/__main__.py
Normal file
3
plugins/code/ui/code_fold/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
42
plugins/code/ui/code_fold/fold_types.py
Normal file
42
plugins/code/ui/code_fold/fold_types.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
FOLD_NODES = {
|
||||
"python": {
|
||||
"function_definition",
|
||||
"class_definition",
|
||||
"if_statement",
|
||||
"for_statement",
|
||||
"while_statement",
|
||||
"with_statement",
|
||||
"try_statement",
|
||||
},
|
||||
"python3": {
|
||||
"function_definition",
|
||||
"class_definition",
|
||||
"if_statement",
|
||||
"for_statement",
|
||||
"while_statement",
|
||||
"with_statement",
|
||||
"try_statement",
|
||||
},
|
||||
"java": {
|
||||
"class_declaration",
|
||||
"method_declaration",
|
||||
"constructor_declaration",
|
||||
"if_statement",
|
||||
"for_statement",
|
||||
"while_statement",
|
||||
"switch_expression",
|
||||
"block",
|
||||
},
|
||||
"json": {
|
||||
"object",
|
||||
"array",
|
||||
},
|
||||
}
|
||||
24
plugins/code/ui/code_fold/folding_actions.py
Normal file
24
plugins/code/ui/code_fold/folding_actions.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def collapse_range(view, fold):
|
||||
buffer = view.get_buffer()
|
||||
start = buffer.get_iter_at_line(fold["start_line"] + 1)
|
||||
end = buffer.get_iter_at_line(fold["end_line"] + 1)
|
||||
|
||||
buffer.apply_tag_by_name("invisible", start, end)
|
||||
|
||||
|
||||
def expand_range(view, fold):
|
||||
buffer = view.get_buffer()
|
||||
start = buffer.get_iter_at_line(fold["start_line"] + 1)
|
||||
end = buffer.get_iter_at_line(fold["end_line"] + 1)
|
||||
|
||||
buffer.remove_tag_by_name("invisible", start, end)
|
||||
|
||||
|
||||
32
plugins/code/ui/code_fold/folding_engine.py
Normal file
32
plugins/code/ui/code_fold/folding_engine.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .fold_types import FOLD_NODES
|
||||
|
||||
|
||||
|
||||
def visit_node(fold_types, node, ranges):
|
||||
if node.type in fold_types:
|
||||
start_line = node.start_point[0]
|
||||
end_line = node.end_point[0]
|
||||
|
||||
if end_line > start_line:
|
||||
ranges.append({
|
||||
"start_line": start_line,
|
||||
"end_line": end_line,
|
||||
"id": (start_line, end_line, node.type),
|
||||
})
|
||||
|
||||
for child in node.children:
|
||||
visit_node(fold_types, child, ranges)
|
||||
|
||||
def get_folding_ranges(lang_name: str, ast):
|
||||
root = ast.root_node
|
||||
fold_types = FOLD_NODES.get(lang_name, set())
|
||||
ranges = []
|
||||
|
||||
visit_node(fold_types, root, ranges)
|
||||
return ranges
|
||||
|
||||
90
plugins/code/ui/code_fold/gutter_renderer.py
Normal file
90
plugins/code/ui/code_fold/gutter_renderer.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# 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 .folding_actions import collapse_range, expand_range
|
||||
|
||||
|
||||
|
||||
def handle_collapse(view, fold):
|
||||
collapse_range(view, fold)
|
||||
|
||||
def handle_expand(view, fold):
|
||||
expand_range(view, fold)
|
||||
|
||||
def handle_block_toggle(collapsed, view, fold):
|
||||
if not collapsed:
|
||||
handle_collapse(view, fold)
|
||||
else:
|
||||
handle_expand(view, fold)
|
||||
|
||||
def is_fold_hidden(buffer, fold):
|
||||
iter_ = buffer.get_iter_at_line(fold["start_line"] + 1)
|
||||
tags = iter_.get_tags()
|
||||
return any(tag.get_property("invisible") for tag in tags)
|
||||
|
||||
|
||||
def on_query_data(renderer, start_iter, end_iter, state, view):
|
||||
line = start_iter.get_line()
|
||||
|
||||
if not line in view.fold_start_set:
|
||||
renderer.set_text("", -1)
|
||||
return
|
||||
|
||||
fold = next(
|
||||
(f for f in view.fold_starts if f["start_line"] == line), None
|
||||
)
|
||||
|
||||
collapsed = fold and is_fold_hidden(view.get_buffer(), fold)
|
||||
|
||||
renderer.set_text("▶" if collapsed else "▼", -1)
|
||||
|
||||
def on_click(view, event, renderer):
|
||||
if not event.button == 1: return False
|
||||
window = view.get_window(Gtk.TextWindowType.LEFT)
|
||||
if not event.window == window: return False
|
||||
|
||||
x, y = view.window_to_buffer_coords(
|
||||
Gtk.TextWindowType.LEFT, int(event.x), int(event.y)
|
||||
)
|
||||
|
||||
_, iter_ = view.get_iter_at_location(x, y)
|
||||
line = iter_.get_line()
|
||||
|
||||
if line not in view.fold_start_set: return False
|
||||
|
||||
for fold in view.fold_starts:
|
||||
if not fold["start_line"] == line: continue
|
||||
|
||||
collapsed = is_fold_hidden(view.get_buffer(), fold)
|
||||
handle_block_toggle(collapsed, view, fold)
|
||||
|
||||
renderer.queue_draw()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def setup_gutter(view):
|
||||
gutter = view.get_gutter(Gtk.TextWindowType.LEFT)
|
||||
buffer = view.get_buffer()
|
||||
|
||||
view.fold_starts = []
|
||||
view.fold_start_set = set()
|
||||
|
||||
renderer = GtkSource.GutterRendererText()
|
||||
renderer.set_size(12)
|
||||
renderer.set_padding(2, -1)
|
||||
|
||||
renderer.query_data_id = renderer.connect("query-data", on_query_data, view)
|
||||
view.collapse_click_id = view.connect("button-press-event", on_click, renderer)
|
||||
|
||||
gutter.insert(renderer, 0)
|
||||
view.fold_renderer = renderer
|
||||
7
plugins/code/ui/code_fold/manifest.json
Normal file
7
plugins/code/ui/code_fold/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Code Fold",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
90
plugins/code/ui/code_fold/plugin.py
Normal file
90
plugins/code/ui/code_fold/plugin.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .fold_types import FOLD_NODES
|
||||
from .folding_actions import collapse_range
|
||||
from .folding_engine import get_folding_ranges
|
||||
from .gutter_renderer import setup_gutter
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def _controller_message(self, event):
|
||||
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 not in FOLD_NODES: return
|
||||
if not hasattr(file, "ast"): return
|
||||
|
||||
buffer = file.buffer
|
||||
if not buffer.get_tag_table().lookup("invisible"):
|
||||
tag = buffer.create_tag("invisible")
|
||||
tag.set_property("invisible", True)
|
||||
|
||||
self.update_gutter(file, self.view)
|
||||
elif isinstance(event, Code_Event_Types.TextChangedEvent):
|
||||
if event.file.ftype not in FOLD_NODES: return
|
||||
if not hasattr(event.file, "ast"): return
|
||||
|
||||
self.schedule_update(event.file, self.view)
|
||||
|
||||
def load(self):
|
||||
event = Event_Factory.create_event("get_source_views")
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
for view in event.response:
|
||||
setup_gutter(view)
|
||||
|
||||
def unload(self):
|
||||
event = Event_Factory.create_event("get_source_views")
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
for view in event.response:
|
||||
view.fold_renderer.disconnect(view.fold_renderer.query_data_id)
|
||||
view.disconnect(view.collapse_click_id)
|
||||
|
||||
gutter = view.get_gutter(Gtk.TextWindowType.LEFT)
|
||||
gutter.remove(view.fold_renderer)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
def schedule_update(self, file, view, delay=250):
|
||||
if hasattr(view, "fold_update_source") and view.fold_update_source:
|
||||
GLib.source_remove(view.fold_update_source)
|
||||
|
||||
def callback():
|
||||
self.update_gutter(file, view)
|
||||
|
||||
if hasattr(view, "fold_renderer"):
|
||||
view.fold_renderer.queue_draw()
|
||||
|
||||
view.fold_update_source = None
|
||||
return False
|
||||
|
||||
view.fold_update_source = GLib.timeout_add(delay, callback)
|
||||
|
||||
def update_gutter(self, file, view):
|
||||
view.fold_starts = get_folding_ranges(file.ftype, file.ast)
|
||||
view.fold_start_set = {
|
||||
fold["start_line"] for fold in view.fold_starts
|
||||
}
|
||||
@@ -52,8 +52,8 @@ class Plugin(PluginCode):
|
||||
)
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
source_view = event.response
|
||||
telescope.set_source_view(source_view)
|
||||
scrolled_win, source_view = event.response
|
||||
telescope.set_source_view(scrolled_win, source_view)
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"register_completer",
|
||||
|
||||
@@ -99,13 +99,9 @@ class Telescope(Gtk.Dialog):
|
||||
def unmap_parent_resize_event(self, parent):
|
||||
parent.disconnect(self.size_allocate_id)
|
||||
|
||||
def set_source_view(self, source_view):
|
||||
scrolled_win = Gtk.ScrolledWindow()
|
||||
def set_source_view(self, scrolled_win, source_view):
|
||||
self.source_view = source_view
|
||||
|
||||
scrolled_win.add(self.source_view)
|
||||
self.main_box.pack_end(scrolled_win, True, True, 0)
|
||||
|
||||
scrolled_win.show_all()
|
||||
|
||||
def _handle_destroy(self, widget):
|
||||
|
||||
@@ -6,9 +6,10 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from core.widgets.save_file_dialog import SaveFileDialog
|
||||
from core.widgets.controls.open_files_button import OpenFilesButton
|
||||
|
||||
from .code.code_container import CodeContainer
|
||||
from ..widgets.save_file_dialog import SaveFileDialog
|
||||
from ..widgets.controls.open_files_button import OpenFilesButton
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ...widgets.code.code_base import CodeBase
|
||||
|
||||
from ...widgets.separator_widget import Separator
|
||||
|
||||
from .editors_container import EditorsContainer
|
||||
|
||||
|
||||
@@ -27,6 +23,9 @@ class CodeContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("code-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
def _setup_signals(self):
|
||||
@@ -37,18 +36,4 @@ class CodeContainer(Gtk.Box):
|
||||
|
||||
def _load_widgets(self):
|
||||
widget_registery.expose_object("code-container", self)
|
||||
|
||||
code_base = CodeBase()
|
||||
|
||||
self.add( self._create_editor_widget(code_base) )
|
||||
|
||||
def _create_editor_widget(self, code_base: CodeBase):
|
||||
editors_container = Gtk.Box()
|
||||
|
||||
widget_registery.expose_object("editors-container", editors_container)
|
||||
|
||||
editors_container.add( Separator("separator_left") )
|
||||
editors_container.add( EditorsContainer(code_base) )
|
||||
editors_container.add( Separator("separator_right") )
|
||||
|
||||
return editors_container
|
||||
self.add( EditorsContainer() )
|
||||
|
||||
@@ -4,18 +4,17 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
#from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from core.widgets.code.code_base import CodeBase
|
||||
from core.widgets.separator_widget import Separator
|
||||
|
||||
|
||||
|
||||
class EditorsContainer(Gtk.Paned):
|
||||
def __init__(self, code_base: any):
|
||||
class EditorsContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(EditorsContainer, self).__init__()
|
||||
|
||||
self.code_base = code_base
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -24,11 +23,11 @@ class EditorsContainer(Gtk.Paned):
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("paned-editors-container")
|
||||
self.ctx.add_class("editors-container")
|
||||
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
self.set_wide_handle(True)
|
||||
self.set_size_request(320, -1)
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("map", self._init_map)
|
||||
@@ -37,29 +36,18 @@ class EditorsContainer(Gtk.Paned):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.scrolled_win1, \
|
||||
self.scrolled_win2 = self._create_views()
|
||||
box = Gtk.Box()
|
||||
widget_registery.expose_object("editors-container", self)
|
||||
self.code_base = CodeBase()
|
||||
scrolled_win, \
|
||||
source_view = self.code_base.create_source_view()
|
||||
|
||||
self.pack1( self.scrolled_win1, True, True )
|
||||
self.pack2( self.scrolled_win2, True, True )
|
||||
|
||||
def _create_views(self):
|
||||
scrolled_win1 = Gtk.ScrolledWindow()
|
||||
scrolled_win2 = Gtk.ScrolledWindow()
|
||||
|
||||
source_view1 = self.code_base.create_source_view()
|
||||
source_view2 = self.code_base.create_source_view()
|
||||
|
||||
source_view1.sibling_right = source_view2
|
||||
source_view2.sibling_left = source_view1
|
||||
|
||||
scrolled_win1.add( source_view1 )
|
||||
scrolled_win2.add( source_view2 )
|
||||
|
||||
return scrolled_win1, scrolled_win2
|
||||
box.add( scrolled_win )
|
||||
self.add( Separator("separator_left") )
|
||||
self.add( box )
|
||||
self.add( Separator("separator_right") )
|
||||
|
||||
def _init_map(self, view):
|
||||
self.disconnect_by_func( self._init_map )
|
||||
self.code_base.first_map_load()
|
||||
self.code_base = None
|
||||
del self.code_base
|
||||
|
||||
@@ -6,8 +6,8 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from ..widgets.vte_widget import VteWidget
|
||||
from core.widgets.separator_widget import Separator
|
||||
from core.widgets.vte_widget import VteWidget
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from core.widgets.separator_widget import Separator
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from core.widgets.separator_widget import Separator
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from core.widgets.separator_widget import Separator
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,16 +18,12 @@ class BaseControllerMixin:
|
||||
files = []
|
||||
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isdir( arg.replace("file://", "") ):
|
||||
files.append( f"DIR|{arg.replace('file://', '')}" )
|
||||
continue
|
||||
if os.path.isfile(arg):
|
||||
files.append(f"{arg}")
|
||||
|
||||
# NOTE: If passing line number with file split against :
|
||||
if os.path.isfile( arg.replace("file://", "").split(":")[0] ):
|
||||
files.append( f"FILE|{arg.replace('file://', '')}" )
|
||||
continue
|
||||
|
||||
logger.info(f"Not a File: {arg}")
|
||||
if os.path.isdir(arg):
|
||||
message = f"DIR|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
if not files: return
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ class CodeBase:
|
||||
completion_controller = CompletionController()
|
||||
source_views_controller = SourceViewsController()
|
||||
|
||||
# self.controller_manager.register_controller("base", self)
|
||||
self.controller_manager.register_controller("files", files_controller)
|
||||
self.controller_manager.register_controller("commands", commands_controller)
|
||||
self.controller_manager.register_controller("completion", completion_controller)
|
||||
@@ -43,12 +42,13 @@ class CodeBase:
|
||||
self.controller_manager.register_controller("widgets", widget_registery)
|
||||
|
||||
def create_source_view(self):
|
||||
scrolled_win, \
|
||||
source_view = self.controller_manager["source_views"].create_source_view()
|
||||
self.controller_manager["completion"].register_completer(
|
||||
source_view.get_completion()
|
||||
)
|
||||
|
||||
return source_view
|
||||
return scrolled_win, source_view
|
||||
|
||||
def first_map_load(self):
|
||||
self.controller_manager["source_views"].first_map_load()
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
Code Command System Package
|
||||
"""
|
||||
|
||||
from .command_system import CommandSystem
|
||||
from .source_view_command_system import SourceViewCommandSystem
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from ..mixins.command_system_mixin import CommandSystemMixin
|
||||
from ..source_view import SourceView
|
||||
|
||||
from . import commands
|
||||
|
||||
|
||||
|
||||
class CommandSystem(CommandSystemMixin):
|
||||
def __init__(self):
|
||||
super(CommandSystem, self).__init__()
|
||||
|
||||
self.data: list = ()
|
||||
|
||||
|
||||
def set_data(self, *args, **kwargs):
|
||||
self.data = (args, kwargs)
|
||||
|
||||
def exec(self, command: str) -> any:
|
||||
if not hasattr(commands, command): return
|
||||
method = getattr(commands, command)
|
||||
|
||||
args, kwargs = self.data
|
||||
return method.execute(*args, **kwargs)
|
||||
|
||||
def exec_with_args(self, command: str, *args, **kwargs) -> any:
|
||||
if not hasattr(commands, command): return
|
||||
|
||||
method = getattr(commands, command)
|
||||
return method.execute(*args, **kwargs)
|
||||
|
||||
def add_command(self, command_name: str, command: callable):
|
||||
setattr(commands, command_name, command)
|
||||
|
||||
def remove_command(self, command_name: str, command: callable):
|
||||
if hasattr(commands, command_name):
|
||||
delattr(commands, command_name)
|
||||
|
||||
|
||||
def emit(self, event: Code_Event_Types.CodeEvent):
|
||||
""" Monkey patch 'emit' from command controller... """
|
||||
...
|
||||
|
||||
def emit_to(self, controller: str, event: Code_Event_Types.CodeEvent):
|
||||
""" Monkey patch 'emit_to' from command controller... """
|
||||
...
|
||||
|
||||
|
||||
# def filter_out_loaded_files(self, uris: list[str]):
|
||||
# event = Event_Factory.create_event(
|
||||
# "filter_out_loaded_files",
|
||||
# uris = uris
|
||||
# )
|
||||
#
|
||||
# self.emit_to("files", event)
|
||||
#
|
||||
# return event.response
|
||||
#
|
||||
# def set_info_labels(self, data: tuple[str]):
|
||||
# event = Event_Factory.create_event(
|
||||
# "set_info_labels",
|
||||
# info = data
|
||||
# )
|
||||
#
|
||||
# self.emit_to("plugins", event)
|
||||
#
|
||||
# def get_file(self, view: SourceView):
|
||||
# event = Event_Factory.create_event(
|
||||
# "get_file",
|
||||
# view = view,
|
||||
# buffer = view.get_buffer()
|
||||
# )
|
||||
#
|
||||
# self.emit_to("files", event)
|
||||
#
|
||||
# return event.response
|
||||
#
|
||||
# def get_swap_file(self, view: SourceView):
|
||||
# event = Event_Factory.create_event(
|
||||
# "get_swap_file",
|
||||
# view = view,
|
||||
# buffer = view.get_buffer()
|
||||
# )
|
||||
#
|
||||
# self.emit_to("files", event)
|
||||
#
|
||||
# return event.response
|
||||
#
|
||||
# def new_file(self, view: SourceView):
|
||||
# event = Event_Factory.create_event("add_new_file", view = view)
|
||||
#
|
||||
# self.emit_to("files", event)
|
||||
#
|
||||
# return event.response
|
||||
#
|
||||
# def remove_file(self, view: SourceView):
|
||||
# event = Event_Factory.create_event(
|
||||
# "remove_file",
|
||||
# view = view,
|
||||
# buffer = view.get_buffer()
|
||||
# )
|
||||
#
|
||||
# self.emit_to("files", event)
|
||||
#
|
||||
# return event.response
|
||||
#
|
||||
# def request_completion(self, view: SourceView):
|
||||
# event = Event_Factory.create_event(
|
||||
# "request_completion",
|
||||
# view = view,
|
||||
# buffer = view.get_buffer()
|
||||
# )
|
||||
#
|
||||
# self.emit_to("completion", event)
|
||||
@@ -20,9 +20,14 @@ def execute(
|
||||
ctx = view.get_parent().get_style_context()
|
||||
ctx.add_class("source-view-focused")
|
||||
|
||||
if view.sibling_right:
|
||||
ctx = view.sibling_right.get_parent().get_style_context()
|
||||
elif view.sibling_left:
|
||||
ctx = view.sibling_left.get_parent().get_style_context()
|
||||
|
||||
lview = view.sibling_left
|
||||
while lview is not None:
|
||||
ctx = lview.get_parent().get_style_context()
|
||||
ctx.remove_class("source-view-focused")
|
||||
lview = lview.sibling_left
|
||||
|
||||
rview = view.sibling_right
|
||||
while rview is not None:
|
||||
ctx = rview.get_parent().get_style_context()
|
||||
ctx.remove_class("source-view-focused")
|
||||
rview = rview.sibling_right
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
from libs.command_system import CommandSystem
|
||||
|
||||
from ..source_view import SourceView
|
||||
|
||||
|
||||
from . import commands
|
||||
|
||||
|
||||
|
||||
class SourceViewCommandSystem(CommandSystem):
|
||||
def __init__(self):
|
||||
super(SourceViewCommandSystem, self).__init__(commands)
|
||||
|
||||
class CommandSystemMixin:
|
||||
def toggle_plugins_ui(self):
|
||||
event = Event_Factory.create_event( "toggle_plugins_ui" )
|
||||
|
||||
@@ -81,3 +88,11 @@ class CommandSystemMixin:
|
||||
)
|
||||
|
||||
self.emit_to("completion", event)
|
||||
|
||||
def emit(self, event: Code_Event_Types.CodeEvent):
|
||||
""" Monkey patch 'emit' from command controller... """
|
||||
...
|
||||
|
||||
def emit_to(self, controller: str, event: Code_Event_Types.CodeEvent):
|
||||
""" Monkey patch 'emit_to' from command controller... """
|
||||
...
|
||||
@@ -7,7 +7,7 @@ from libs.controllers.controller_base import ControllerBase
|
||||
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from ..command_system import CommandSystem
|
||||
from ..command_system import SourceViewCommandSystem
|
||||
|
||||
|
||||
|
||||
@@ -17,14 +17,19 @@ class CommandsController(ControllerBase, list):
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, Code_Event_Types.GetNewCommandSystemEvent):
|
||||
event.response = self.get_new_command_system()
|
||||
if isinstance(event, Code_Event_Types.CreateCommandSystemEvent):
|
||||
event.response = self.create_command_system()
|
||||
elif isinstance(event, Code_Event_Types.RemovedSourceViewEvent):
|
||||
self.remove_command_system(event)
|
||||
|
||||
def get_new_command_system(self):
|
||||
command_system = CommandSystem()
|
||||
def create_command_system(self):
|
||||
command_system = SourceViewCommandSystem()
|
||||
command_system.emit = self.emit
|
||||
command_system.emit_to = self.emit_to
|
||||
|
||||
self.append(command_system)
|
||||
|
||||
return command_system
|
||||
|
||||
def remove_command_system(self, event: Code_Event_Types.RemovedSourceViewEvent):
|
||||
self.remove(event.view.command)
|
||||
|
||||
@@ -46,14 +46,24 @@ class MarkerManager(MarkSupportMixin):
|
||||
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||
|
||||
self._proc_move(
|
||||
buffer, is_forward, is_selection, mode, mark_hash,
|
||||
start_mark, end_mark, has_selection, start_itr, end_itr
|
||||
)
|
||||
|
||||
def _proc_move(
|
||||
self, buffer, is_forward: bool, is_selection: bool, mode: str,
|
||||
mark_hash, start_mark, end_mark, has_selection, start_itr, end_itr
|
||||
):
|
||||
if is_selection:
|
||||
if mark_hash:
|
||||
self.buffer_markers[mark_hash]["is_selection"] = True
|
||||
|
||||
self._move_iter(buffer, end_itr, mode, is_forward)
|
||||
buffer.move_mark(end_mark, end_itr)
|
||||
|
||||
self._apply_selection(buffer, start_itr, end_itr)
|
||||
continue
|
||||
return
|
||||
|
||||
if has_selection:
|
||||
caret_itr = buffer.get_iter_at_mark(end_mark)
|
||||
@@ -67,15 +77,14 @@ class MarkerManager(MarkSupportMixin):
|
||||
|
||||
self.collapse_selection(buffer, mark_hash, start_mark, end_mark, is_forward)
|
||||
if mode == "word":
|
||||
if not can_move: continue
|
||||
if not can_move: return
|
||||
|
||||
itr = caret_itr
|
||||
self._move_iter(buffer, itr, mode, is_forward)
|
||||
buffer.move_mark(start_mark, itr)
|
||||
buffer.move_mark(end_mark, itr)
|
||||
|
||||
continue
|
||||
|
||||
return
|
||||
|
||||
# No selection - move both anchor and caret together
|
||||
self._move_iter(buffer, end_itr, mode, is_forward)
|
||||
@@ -86,6 +95,7 @@ class MarkerManager(MarkSupportMixin):
|
||||
def collapse_selection(self,
|
||||
buffer, mark_hash, start_mark, end_mark, is_forward: bool
|
||||
):
|
||||
if mark_hash:
|
||||
self.buffer_markers[mark_hash]["is_selection"] = False
|
||||
|
||||
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||
@@ -105,19 +115,28 @@ class MarkerManager(MarkSupportMixin):
|
||||
buffer.move_mark(start_mark, collapse_itr)
|
||||
buffer.move_mark(end_mark, collapse_itr)
|
||||
|
||||
def move_word_snake_case(self, itr: Gtk.TextIter, count: int):
|
||||
def is_word(ch):
|
||||
def move_along_word(self, itr: Gtk.TextIter, count: int):
|
||||
def not_is_word(ch: str):
|
||||
return not is_word(ch)
|
||||
|
||||
def is_word(ch: str):
|
||||
return ch and (ch.isalnum() or ch == "_")
|
||||
|
||||
def step(fwd):
|
||||
def is_special(ch: str):
|
||||
return ch in "-"
|
||||
|
||||
def is_punct(ch: str):
|
||||
return ch in ".;?!"
|
||||
|
||||
def step(fwd: bool):
|
||||
return itr.forward_cursor_position() if fwd else itr.backward_cursor_position()
|
||||
|
||||
def peek(fwd):
|
||||
def peek(fwd: bool):
|
||||
if fwd: return itr.get_char()
|
||||
tmp = itr.copy()
|
||||
return tmp.backward_cursor_position() and tmp.get_char()
|
||||
|
||||
def walk(fwd, cond):
|
||||
def walk(fwd, cond: callable):
|
||||
while True:
|
||||
ch = peek(fwd)
|
||||
if not cond(ch): break
|
||||
@@ -126,23 +145,22 @@ class MarkerManager(MarkSupportMixin):
|
||||
return True
|
||||
|
||||
fwd = count > 0
|
||||
|
||||
for _ in range( abs(count) ):
|
||||
ch = itr.get_char() if fwd else peek(False)
|
||||
ch = peek(fwd)
|
||||
|
||||
if is_word(ch):
|
||||
# inside word
|
||||
if is_special(ch) or is_punct(ch):
|
||||
step(fwd)
|
||||
elif is_word(ch):
|
||||
if not walk(fwd, is_word): return
|
||||
else:
|
||||
# in separators -> skip them, then the word
|
||||
if not walk(fwd, lambda c: not is_word(c)): return
|
||||
if not walk(fwd, not_is_word): return
|
||||
if not walk(fwd, is_word): return
|
||||
|
||||
def _move_iter(self, buffer, itr_, mode: str, is_forward: bool):
|
||||
if mode == "char":
|
||||
itr_.forward_char() if is_forward else itr_.backward_char()
|
||||
elif mode == "word":
|
||||
self.move_word_snake_case(itr_, 1 if is_forward else -1)
|
||||
self.move_along_word(itr_, 1 if is_forward else -1)
|
||||
elif mode == "line":
|
||||
line = itr_.get_line()
|
||||
offset = itr_.get_line_offset()
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from libs.controllers.controller_base import ControllerBase
|
||||
@@ -29,6 +32,8 @@ class SourceViewsController(ControllerBase, list):
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, Code_Event_Types.CreateSourceViewEvent):
|
||||
event.response = self.create_source_view(event.state)
|
||||
elif isinstance(event, Code_Event_Types.RemoveSourceViewEvent):
|
||||
self._remove_source_view(event)
|
||||
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
||||
self._remove_file(event)
|
||||
elif isinstance(event, Code_Event_Types.RegisterCommandEvent):
|
||||
@@ -86,7 +91,7 @@ class SourceViewsController(ControllerBase, list):
|
||||
)
|
||||
|
||||
def _get_command_system(self):
|
||||
event = Event_Factory.create_event("get_new_command_system")
|
||||
event = Event_Factory.create_event("create_command_system")
|
||||
self.message_to("commands", event)
|
||||
command = event.response
|
||||
|
||||
@@ -103,15 +108,33 @@ class SourceViewsController(ControllerBase, list):
|
||||
|
||||
source_view.set_buffer(event.next_file.buffer)
|
||||
|
||||
def _remove_source_view(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
event = Event_Factory.create_event("removed_source_view", view = event.view)
|
||||
self.message(event)
|
||||
|
||||
self.remove(event.view)
|
||||
self.signal_mapper.disconnect_signals(event.view)
|
||||
|
||||
def create_source_view(self, state: SourceViewStates = SourceViewStates.INSERT):
|
||||
scrolled_win: Gtk.ScrolledWindow = Gtk.ScrolledWindow()
|
||||
source_view: SourceView = SourceView(state)
|
||||
source_view.command = self._get_command_system()
|
||||
source_view.command.set_data(source_view)
|
||||
|
||||
scrolled_win.set_hexpand(True)
|
||||
scrolled_win.set_vexpand(True)
|
||||
|
||||
source_view.command.set_data(source_view)
|
||||
self.signal_mapper.connect_signals(source_view)
|
||||
|
||||
self.append(source_view)
|
||||
return source_view
|
||||
scrolled_win.add(source_view)
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"created_source_view", view = source_view
|
||||
)
|
||||
self.emit(event)
|
||||
|
||||
return scrolled_win, source_view
|
||||
|
||||
def first_map_load(self):
|
||||
for source_view in self:
|
||||
|
||||
@@ -59,30 +59,56 @@ class SourceViewsMultiInsertState(SourceViewsBaseState):
|
||||
buffer.insert(start_itr, text, -1)
|
||||
|
||||
self.marker_manager.apply_to_marks(buffer, replace_word)
|
||||
|
||||
return True
|
||||
|
||||
def move_cursor(self, source_view, step, count, is_selection, emit):
|
||||
def move_cursor(
|
||||
self, source_view, step, count, is_selection,
|
||||
emit = None, ignore_leader: bool = False
|
||||
):
|
||||
is_forward = count > 0
|
||||
buffer = source_view.get_buffer()
|
||||
|
||||
if step in [
|
||||
Gtk.MovementStep.LOGICAL_POSITIONS,
|
||||
Gtk.MovementStep.VISUAL_POSITIONS
|
||||
]:
|
||||
self.marker_manager.move_by_char(buffer, is_forward, is_selection)
|
||||
elif step == Gtk.MovementStep.WORDS:
|
||||
self.marker_manager.move_by_word(buffer, is_forward, is_selection)
|
||||
elif step == Gtk.MovementStep.DISPLAY_LINES:
|
||||
self.marker_manager.move_by_line(buffer, is_forward, is_selection)
|
||||
start_mark = buffer.get_insert()
|
||||
end_mark = buffer.get_selection_bound()
|
||||
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||
has_selection = not start_itr.equal(end_itr)
|
||||
|
||||
self._signal_cursor_moved(source_view, emit)
|
||||
step_map = {
|
||||
Gtk.MovementStep.LOGICAL_POSITIONS: ("char", self.marker_manager.move_by_char),
|
||||
Gtk.MovementStep.VISUAL_POSITIONS: ("char", self.marker_manager.move_by_char),
|
||||
Gtk.MovementStep.WORDS: ("word", self.marker_manager.move_by_word),
|
||||
Gtk.MovementStep.DISPLAY_LINES: ("line", self.marker_manager.move_by_line),
|
||||
}
|
||||
|
||||
return False
|
||||
kind, move_fn = step_map[step]
|
||||
move_fn(buffer, is_forward, is_selection)
|
||||
|
||||
if ignore_leader: return True
|
||||
|
||||
self.marker_manager._proc_move(
|
||||
buffer,
|
||||
is_forward,
|
||||
is_selection,
|
||||
kind,
|
||||
None,
|
||||
start_mark,
|
||||
end_mark,
|
||||
has_selection,
|
||||
start_itr,
|
||||
end_itr,
|
||||
)
|
||||
|
||||
# self._signal_cursor_moved(source_view, emit)
|
||||
|
||||
return True
|
||||
|
||||
def key_press_event(self, source_view, event, key_mapper):
|
||||
char = key_mapper.get_raw_keyname(event).upper()
|
||||
self.is_control = key_mapper.is_control(event)
|
||||
self.is_shift = key_mapper.is_shift(event)
|
||||
self.is_super = key_mapper.is_super(event)
|
||||
|
||||
if char.upper() in ["BACKSPACE", "DELETE", "ENTER"]:
|
||||
self.marker_manager.process_cursor_action(
|
||||
@@ -91,6 +117,9 @@ class SourceViewsMultiInsertState(SourceViewsBaseState):
|
||||
)
|
||||
return False
|
||||
|
||||
if self._do_cursor_moved(source_view, char):
|
||||
return True
|
||||
|
||||
return super().key_press_event(source_view, event, key_mapper)
|
||||
|
||||
def button_press_event(self, source_view, event):
|
||||
@@ -99,6 +128,56 @@ class SourceViewsMultiInsertState(SourceViewsBaseState):
|
||||
def button_release_event(self, source_view, event):
|
||||
self.marker_manager.button_release_event(source_view, event)
|
||||
|
||||
def _do_cursor_moved(self, source_view, char: str):
|
||||
key = char.upper()
|
||||
if key not in {"LEFT", "RIGHT", "UP", "DOWN"}: return False
|
||||
|
||||
direction = {
|
||||
"LEFT": -1,
|
||||
"RIGHT": 1,
|
||||
"UP": -1,
|
||||
"DOWN": 1,
|
||||
}[key]
|
||||
|
||||
is_horizontal = key in {"LEFT", "RIGHT"}
|
||||
|
||||
step = \
|
||||
Gtk.MovementStep.VISUAL_POSITIONS if is_horizontal else Gtk.MovementStep.DISPLAY_LINES
|
||||
count = direction
|
||||
is_selection = self.is_shift
|
||||
|
||||
if is_horizontal:
|
||||
if self.is_control:
|
||||
step = Gtk.MovementStep.WORDS
|
||||
if self.is_control and self.is_shift:
|
||||
is_selection = True
|
||||
if self.is_super:
|
||||
return self.move_cursor(
|
||||
source_view,
|
||||
step,
|
||||
count,
|
||||
is_selection = False,
|
||||
emit = None,
|
||||
ignore_leader = True,
|
||||
)
|
||||
else:
|
||||
if self.is_super:
|
||||
return self.move_cursor(
|
||||
source_view,
|
||||
step,
|
||||
count,
|
||||
is_selection,
|
||||
emit = None,
|
||||
ignore_leader = True,
|
||||
)
|
||||
|
||||
return self.move_cursor(
|
||||
source_view,
|
||||
step = step,
|
||||
count = count,
|
||||
is_selection = is_selection,
|
||||
)
|
||||
|
||||
def _signal_cursor_moved(self, source_view, emit):
|
||||
buffer = source_view.get_buffer()
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
|
||||
@@ -161,6 +161,10 @@ class KeyMapper:
|
||||
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||
return modifiers & Gdk.ModifierType.SHIFT_MASK
|
||||
|
||||
def is_super(self, eve):
|
||||
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||
return modifiers & Gdk.ModifierType.SUPER_MASK
|
||||
|
||||
def get_raw_keyname(self, eve) -> str:
|
||||
return Gdk.keyval_name(eve.keyval)
|
||||
|
||||
|
||||
@@ -155,9 +155,10 @@ class SourceFile(GtkSource.File):
|
||||
self.buffer.unblock_modified_changed_signal()
|
||||
|
||||
def is_externally_modified(self) -> bool:
|
||||
if self.fname == "buffer": return
|
||||
|
||||
stat = os.stat(self.fpath)
|
||||
current = (stat.st_mtime_ns, stat.st_size)
|
||||
|
||||
is_modified = \
|
||||
hasattr(self, "last_state") and not current == self.last_state
|
||||
|
||||
|
||||
50
src/libs/command_system.py
Normal file
50
src/libs/command_system.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Python imports
|
||||
import types
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
|
||||
|
||||
class CommandSystem:
|
||||
def __init__(self, commands: dict | types.ModuleType):
|
||||
super(CommandSystem, self).__init__()
|
||||
|
||||
self.commands: dict | types.ModuleType = commands
|
||||
self.data: tuple = ()
|
||||
|
||||
|
||||
def set_data(self, *args, **kwargs):
|
||||
self.data = (args, kwargs)
|
||||
|
||||
def exec(self, command: str) -> any:
|
||||
"""
|
||||
The 'exec' method passes the default 'self.data' to commands where custom args are not needed.
|
||||
Ex: The 'code' widget has many internally created commands that
|
||||
only need 'source_view' and so 'set_data' is called to set that.
|
||||
"""
|
||||
if not hasattr(self.commands, command): return
|
||||
method = getattr(self.commands, command)
|
||||
|
||||
args, kwargs = self.data
|
||||
return method.execute(*args, **kwargs)
|
||||
|
||||
def exec_with_args(self, command: str, *args, **kwargs) -> any:
|
||||
"""
|
||||
The 'exec_with_args' method passes custom args with the understanding
|
||||
that the recipient has proper method signature to accept it- whether
|
||||
*args or **kwargs or something else entirely.
|
||||
"""
|
||||
if not hasattr(self.commands, command): return
|
||||
|
||||
method = getattr(self.commands, command)
|
||||
return method.execute(*args, **kwargs)
|
||||
|
||||
def add_command(self, command_name: str, command: callable):
|
||||
setattr(self.commands, command_name, command)
|
||||
|
||||
def remove_command(self, command_name: str, command: callable):
|
||||
if hasattr(self.commands, command_name):
|
||||
delattr(self.commands, command_name)
|
||||
@@ -6,6 +6,9 @@
|
||||
from .code_event import CodeEvent
|
||||
from .toggle_plugins_ui_event import TogglePluginsUiEvent
|
||||
from .create_source_view_event import CreateSourceViewEvent
|
||||
from .created_source_view_event import CreatedSourceViewEvent
|
||||
from .remove_source_view_event import RemoveSourceViewEvent
|
||||
from .removed_source_view_event import RemovedSourceViewEvent
|
||||
from .register_completer_event import RegisterCompleterEvent
|
||||
from .unregister_completer_event import UnregisterCompleterEvent
|
||||
from .register_provider_event import RegisterProviderEvent
|
||||
@@ -20,7 +23,7 @@ from .filter_out_loaded_files_event import FilterOutLoadedFilesEvent
|
||||
from .get_active_view_event import GetActiveViewEvent
|
||||
from .get_source_views_event import GetSourceViewsEvent
|
||||
|
||||
from .get_new_command_system_event import GetNewCommandSystemEvent
|
||||
from .create_command_system_event import CreateCommandSystemEvent
|
||||
from .request_completion_event import RequestCompletionEvent
|
||||
from .cursor_moved_event import CursorMovedEvent
|
||||
from .modified_changed_event import ModifiedChangedEvent
|
||||
|
||||
@@ -9,5 +9,5 @@ from .code_event import CodeEvent
|
||||
|
||||
|
||||
@dataclass
|
||||
class GetNewCommandSystemEvent(CodeEvent):
|
||||
class CreateCommandSystemEvent(CodeEvent):
|
||||
...
|
||||
14
src/libs/dto/code/events/created_source_view_event.py
Normal file
14
src/libs/dto/code/events/created_source_view_event.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .code_event import CodeEvent
|
||||
from libs.dto.states.source_view_states import SourceViewStates
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class CreatedSourceViewEvent(CodeEvent):
|
||||
...
|
||||
14
src/libs/dto/code/events/remove_source_view_event.py
Normal file
14
src/libs/dto/code/events/remove_source_view_event.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .code_event import CodeEvent
|
||||
from libs.dto.states.source_view_states import SourceViewStates
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class RemoveSourceViewEvent(CodeEvent):
|
||||
...
|
||||
14
src/libs/dto/code/events/removed_source_view_event.py
Normal file
14
src/libs/dto/code/events/removed_source_view_event.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .code_event import CodeEvent
|
||||
from libs.dto.states.source_view_states import SourceViewStates
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class RemovedSourceViewEvent(CodeEvent):
|
||||
...
|
||||
@@ -13,9 +13,11 @@ from .requests import Requests
|
||||
class Manifest:
|
||||
name: str = ""
|
||||
author: str = ""
|
||||
credit: str = ""
|
||||
description: str = ""
|
||||
version: str = "0.0.1"
|
||||
support: str = "support@mail.com"
|
||||
credit: str = ""
|
||||
copyright: str = "GPLv2"
|
||||
pre_launch: bool = False
|
||||
autoload: bool = True
|
||||
requests: Requests = field(default_factory = lambda: Requests())
|
||||
|
||||
@@ -44,18 +44,6 @@
|
||||
},
|
||||
"toggle_plugins_ui": {
|
||||
"released": "<Control><Shift>p"
|
||||
},
|
||||
"focus_left_sibling": {
|
||||
"released": "<Control>Page_Up"
|
||||
},
|
||||
"focus_right_sibling": {
|
||||
"released": "<Control>Page_Down"
|
||||
},
|
||||
"move_to_left_sibling": {
|
||||
"released": "<Control><Shift>Up"
|
||||
},
|
||||
"move_to_right_sibling": {
|
||||
"released": "<Control><Shift>Down"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user