refactor(code): move temp cut buffer feature and clean up related code

- Moved cut_to_temp_buffer and paste_temp_buffer commands to plugin
- Remove temporary cut buffer logic from SourceView
- Remove related keybindings (Ctrl+K / Ctrl+U)
- Fix word-end detection in ProviderResponseCacheBase to avoid extending past line end
- Improve completion controller to support RequestCompletionEvent with optional provider filtering
- Add GetActiveViewEvent handling in SourceViewsController
- Ensure view scrolls to cursor after buffer switch via GLib.idle_add
- Emit focus-in-event after DnD file load to restore focus behavior
- Prevent "buffer" pseudo-path from interfering with loaded file filtering
- Remove obsolete AGENTS.md from LSP manager plugin
This commit is contained in:
2026-03-08 14:57:19 -05:00
parent 220a8c2743
commit 9987a1a21e
18 changed files with 194 additions and 259 deletions

View File

@@ -0,0 +1,3 @@
"""
Pligin Module
"""

View File

@@ -0,0 +1,3 @@
"""
Pligin Package
"""

View File

@@ -0,0 +1,44 @@
# 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()
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 = ""
line_str = buffer.get_text(start_itr, end_itr, True)
view._cut_buffer += line_str
buffer.delete(start_itr, end_itr)
set_temp_cut_buffer_delayed(view)

View 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)

View File

@@ -0,0 +1,7 @@
{
"name": "Nanoesq Temp Buffer",
"author": "ITDominator",
"version": "0.0.1",
"support": "",
"requests": {}
}

View File

@@ -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)

View File

@@ -0,0 +1,43 @@
# 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):
event = Event_Factory.create_event("register_command",
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("register_command",
command_name = "paste_temp_buffer",
command = Handler2,
binding_mode = "held",
binding = "<Control>u"
)
self.emit_to("source_views", event)
def run(self):
...

View File

@@ -1,159 +0,0 @@
# AGENTS.md - LSP Manager Plugin
## Project Overview
This is a Newton editor plugin providing LSP (Language Server Protocol) code completion via WebSocket. Written in Python using GTK3/GtkSource.
## Build/Lint/Test Commands
### Running Tests
```bash
# Run all websocket library tests
python -m unittest discover -s libs/websocket/tests
# Run a single test file
python -m unittest libs.websocket.tests.test_websocket
# Run a single test
python -m unittest libs.websocket.tests.test_websocket.WebSocketTest.test_default_timeout
```
### Environment
- Python 3.x
- GTK 3.0 with GtkSource 4
- No build system (pyproject.toml/setup.py) - direct execution
## Code Style Guidelines
### Import Organization
Always use three-section ordering:
```python
# Python imports
import json
from os import path
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
# Application imports
from libs.event_factory import Event_Factory
from plugins.plugin_types import PluginCode
from .lsp_manager import LSPManager
```
### Formatting
- 4-space indentation
- Line length: ~100 chars (soft limit)
- No trailing whitespace
- Use f-strings for string formatting: `f"{variable} text"`
### Naming Conventions
- **Classes**: PascalCase (`LSPManager`, `ProviderResponseCache`)
- **Methods/functions**: snake_case (`create_client`, `load_lsp_servers_config`)
- **Private members**: leading underscore (`_setup_styling`, `_init_params`)
- **Constants**: SCREAMING_SNAKE_CASE
### Type Hints
- Use Python 3.x type hints
- Common types: `str`, `int`, `dict`, `list`, `bool`
- For untyped parameters, use `any`:
```python
def execute(view: any, *args, **kwargs)
```
### Error Handling
- Use try/except blocks with specific exception types
- Use `logger.error()` for logging errors with context
- Return early on failure conditions:
```python
if not lang_id: return
if not lang_id in self.servers_config: return
```
### Class Structure
```python
class LSPManager(Gtk.Dialog):
def __init__(self):
super(LSPManager, self).__init__()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
def _setup_styling(self):
...
def _setup_signals(self):
...
```
### GTK Patterns
- Use `gi.require_version()` before importing GTK modules
- Use `GLib.idle_add()` for deferred UI updates
- Connect signals with `widget.connect("signal_name", handler)`
### Empty Methods
Use ellipsis for stub/placeholder methods:
```python
def _subscribe_to_events(self):
...
```
### Logging
- Import `logger` from application (available globally)
- Use `logger.debug()`, `logger.error()` for appropriate levels
- Include context in error messages:
```python
logger.error( f"LSP Controller: {_LSP_INIT_CONFIG}\n\t\t{repr(e)}" )
```
### Inheritance Patterns
```python
class Provider(GObject.GObject, GtkSource.CompletionProvider):
__gtype_name__ = 'LSPProvider'
def do_get_name(self):
return "LSP Code Completion"
```
### Testing Patterns (websocket library)
- Use `unittest.TestCase`
- Skip tests with decorators:
```python
@unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
def test_remote(self):
...
```
- Environment variables for test configuration:
- `TEST_WITH_INTERNET=1` - enable internet tests
- `LOCAL_WS_SERVER_PORT=9999` - enable local server tests
### File Organization
- Main plugin: `plugin.py`
- Core logic: `lsp_manager.py`, `provider.py`, `provider_response_cache.py`
- Controllers: `controllers/` directory
- Config: `configs/` directory
- Embedded libs: `libs/websocket/`
### Anti-Patterns to Avoid
- Avoid bare `except:` - use specific exceptions
- Avoid global mutable state where possible
- Don't commit secrets or credentials