Compare commits

..

8 Commits

Author SHA1 Message Date
12a5e4935e Fix plugin lifecycle, tabs cleanup, and add auto-scroll to tabs
- Fix unload() method naming in nanoesq_temp_buffer plugin
- Wrap tabs_widget in ScrolledWindow/Viewport for proper scrolling
- Add auto-scroll to center when switching/adding tabs
- Return manifest_meta in manifest_manager for manual plugins
- Refactor remove_plugin() to properly clean up all manifest lists
- Fix widget references in plugins_ui for proper removal
2026-03-23 23:08:00 -05:00
01ede1ac49 Fixed file_history plugin after breakage from testing a pattern 2026-03-23 21:41:50 -05:00
2758d6b62b Fix multi-select word movement for snake_case and add Ctrl+scroll zoom
- Implement snake_case-aware word movement treating underscores as part of words
- Fix selection edge detection to only move word markers when caret is at appropriate boundary
- Add INSERT state guards to line_up/down commands to prevent movement in non-insert modes
- Add Ctrl+scroll zoom in/out functionality for text size
2026-03-22 23:47:27 -05:00
9f1c3cc452 Made explicit that LSP Manager should pre-launch when autoload true/unset 2026-03-22 17:37:49 -05:00
7c4c9ecf88 Refactor file loading to detect external modifications and add reload capability
- Extract _load_data() method from load_path() for reuse in reload()
- Add is_extters externally_modified() to track file state changes (mtime/size)
- Replace load_bytes() with load_contents() for better error handling
- Add reload() method to re-read file from disk
- Fix file_state_watcher by properly detecting external changes
2026-03-22 00:35:51 -05:00
0b231ac749 feat: Complete plugin lifecycle management with lazy loading and runtime reload
Major changes:
- Add unload() method to all plugins for proper cleanup (unregister commands/providers/LSP clients, destroy widgets, clear state)
- Implement lazy widget loading via "show" signal across all containers
- Add autoload: false manifest option for manual/conditional plugin loading
- Add Plugins UI with runtime load/unload toggle via Ctrl+Shift+p
- Implement controller unregistration system with proper signal disconnection
- Add new events: UnregisterCommandEvent, GetFilesEvent, GetSourceViewsEvent, TogglePluginsUiEvent
- Fix signal leaks by tracking and disconnecting handlers in widgets (search/replace, LSP manager, tabs, telescope, markdown preview)
- Add Save/Save As to tabs context menu
- Improve search/replace behavior (selection handling, focus management)
- Add telescope file initialization from existing loaded files
- Refactor plugin reload watcher to dynamically add/remove plugins on filesystem changes
- Add new plugins: file_history, extend_source_view_menu, godot_lsp_client
- Fix bug in prettify_json (undefined variable reference
2026-03-21 13:26:12 -05:00
0fc440e7ce Add dynamic EventNamespace for event type access and refactor LSP manager initialization
- Create EventNamespace class to enable Code_Event_Types.RegisterLspClientEvent access
- Move set_event_hub call from plugin to lsp_manager._do_bind_mapping
- Update event type references to use Code_Event_Types namespace
2026-03-15 23:40:40 -05:00
080ba41cf1 Remove custom LSP manager plugins and add new language server clients
- Delete old lsp_manager plugin (custom websocket-based LSP client implementation)
- Delete java_lsp_client plugin
- Delete python_lsp_client plugin
- Remove unused LSP DTO files in src/libs/dto/code/lsp/
- Add new language_server_clients plugin directory
- Improve event_factory with register_events method
- Add PYTHONDONTWRITEBYTECODE to user config
- Update events init.py docstring
2026-03-15 20:45:58 -05:00
137 changed files with 1999 additions and 370 deletions

View File

@@ -39,6 +39,24 @@ class Plugin(PluginCode):
self.emit_to("source_views", event)
def unload(self):
event = Event_Factory.create_event("unregister_command",
command_name = "autopairs",
command = Handler,
binding_mode = "held",
binding = [
"'", "`", "[", "]",
'<Shift>"',
'<Shift>(',
'<Shift>)',
'<Shift>{',
'<Shift>}'
]
)
self.emit_to("source_views", event)
autopairs = None
def run(self):
...

View File

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

View File

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

View File

@@ -0,0 +1,97 @@
# Python imports
# Lib imports
# Application imports
class Autopairs:
def __init__(self):
...
def handle_word_wrap(self, buffer, char_str: str):
wrap_block = self.get_wrap_block(char_str)
if not wrap_block: return
selection = buffer.get_selection_bounds()
if not selection:
self.insert_pair(buffer, char_str, wrap_block)
return True
self.wrap_selection(buffer, char_str, wrap_block, selection)
return True
def insert_pair(
self, buffer, char_str: str, wrap_block: tuple
):
buffer.begin_user_action()
left_block, right_block = wrap_block
insert_mark = buffer.get_insert()
insert_itr = buffer.get_iter_at_mark(insert_mark)
buffer.insert(insert_itr, f"{left_block}{right_block}")
insert_itr = buffer.get_iter_at_mark( insert_mark )
insert_itr.backward_char()
buffer.place_cursor(insert_itr)
buffer.end_user_action()
def wrap_selection(
self, buffer, char_str: str, wrap_block: tuple, selection
):
left_block, \
right_block = wrap_block
start_itr, \
end_itr = selection
data = buffer.get_text(
start_itr, end_itr, include_hidden_chars = False
)
start_mark = buffer.create_mark("startclose", start_itr, False)
end_mark = buffer.create_mark("endclose", end_itr, True)
buffer.begin_user_action()
buffer.insert(start_itr, left_block)
end_itr = buffer.get_iter_at_mark(end_mark)
buffer.insert(end_itr, right_block)
start = buffer.get_iter_at_mark(start_mark)
end = buffer.get_iter_at_mark(end_mark)
buffer.select_range(start, end)
buffer.delete_mark_by_name("startclose")
buffer.delete_mark_by_name("endclose")
buffer.end_user_action()
def get_wrap_block(self, char_str) -> tuple:
left_block = ""
right_block = ""
match char_str:
case "(" | ")":
left_block = "("
right_block = ")"
case "[" | "]":
left_block = "["
right_block = "]"
case "{" | "}":
left_block = "{"
right_block = "}"
case '"':
left_block = '"'
right_block = '"'
case "'":
left_block = "'"
right_block = "'"
case "`":
left_block = "`"
right_block = "`"
case _:
return ()
return left_block, right_block

View File

@@ -1,5 +1,5 @@
{
"name": "LSP Manager",
"name": "File History",
"author": "ITDominator",
"version": "0.0.1",
"support": "",

View File

@@ -0,0 +1,65 @@
# Python imports
# Lib imports
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from plugins.plugin_types import PluginCode
history: list = []
history_size: int = 30
class Plugin(PluginCode):
def __init__(self):
super(Plugin, self).__init__()
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.RemovedFileEvent):
if event.file.ftype == "buffer": return
if len(history) == history_size:
history.pop(0)
history.append(event.file.fpath)
def load(self):
self._manage_signals("register_command")
def unload(self):
self._manage_signals("unregister_command")
def _manage_signals(self, action: str):
event = Event_Factory.create_event(action,
command_name = "file_history_pop",
command = Handler,
binding_mode = "released",
binding = "<Shift><Control>t"
)
self.emit_to("source_views", event)
def run(self):
...
class Handler:
@staticmethod
def execute(
view: any,
char_str: str,
*args,
**kwargs
):
logger.debug("Command: File History")
if len(history) == 0: return
view._on_uri_data_received(
[
f"file://{history.pop()}"
]
)

View File

@@ -21,7 +21,13 @@ class Plugin(PluginCode):
...
def load(self):
event = Event_Factory.create_event("register_command",
self._manage_signals("register_command")
def unload(self):
self._manage_signals("unregister_command")
def _manage_signals(self, action: str):
event = Event_Factory.create_event(action,
command_name = "cut_to_temp_buffer",
command = Handler,
binding_mode = "held",
@@ -30,7 +36,7 @@ class Plugin(PluginCode):
self.emit_to("source_views", event)
event = Event_Factory.create_event("register_command",
event = Event_Factory.create_event(action,
command_name = "paste_temp_buffer",
command = Handler2,
binding_mode = "held",

View File

@@ -26,6 +26,16 @@ class Plugin(PluginCode):
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):
...

View File

@@ -35,5 +35,15 @@ class Plugin(PluginCode):
)
self.emit_to("completion", event)
def unload(self):
event = Event_Factory.create_event(
"unregister_provider",
provider_name = "Example Completer"
)
self.emit_to("completion", event)
self.provider = None
del self.provider
def run(self):
...

View File

@@ -35,5 +35,15 @@ class Plugin(PluginCode):
)
self.emit_to("completion", event)
def unload(self):
event = Event_Factory.create_event(
"unregister_provider",
provider_name = "Snippets Completer"
)
self.emit_to("completion", event)
self.provider = None
del self.provider
def run(self):
...

View File

@@ -35,5 +35,15 @@ class Plugin(PluginCode):
)
self.emit_to("completion", event)
def unload(self):
event = Event_Factory.create_event(
"unregister_provider",
provider_name = "Words Completer"
)
self.emit_to("completion", event)
self.provider = None
del self.provider
def run(self):
...

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
{
"name": "Extend Source View Menu",
"author": "ITDominator",
"version": "0.0.1",
"support": "",
"requests": {}
}

View File

@@ -0,0 +1,29 @@
# Python imports
# Lib imports
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from plugins.plugin_types import PluginCode
from .source_view_menu import extend_source_view_menu
class Plugin(PluginCode):
def __init__(self):
super(Plugin, self).__init__()
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.PopulateSourceViewPopupEvent):
extend_source_view_menu(event.buffer, event.menu)
def load(self):
...
def unload(self):
...
def run(self):
...

View File

@@ -0,0 +1,68 @@
# Python imports
import json
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
def on_case_handle(menuitem, buffer, action):
start_itr, \
end_itr = buffer.get_selection_bounds()
data = buffer.get_text(start_itr, end_itr, False)
text = data
if action == "on_all_upper":
text = data.upper()
elif action == "on_all_lower":
text = data.lower()
elif action == "on_invert":
text = data.swapcase()
elif action == "on_title":
text = data.title()
elif action == "on_title_strip":
text = data.title().replace("-", "").replace("_", "").replace(" ", "")
buffer.begin_user_action()
buffer.delete(start_itr, end_itr)
buffer.insert(start_itr, text)
buffer.end_user_action()
def extend_source_view_menu(buffer, menu):
if not buffer.get_selection_bounds(): return
for child in menu.get_children():
if not child.get_label() == "C_hange Case": continue
menu.remove(child)
change_case_item = Gtk.MenuItem(label = "Change Case")
case_menu = Gtk.Menu()
au_case_item = Gtk.MenuItem(label = "All Upper Case")
al_case_item = Gtk.MenuItem(label = "All Lower Case")
inver_case_item = Gtk.MenuItem(label = "Invert Case")
title_case_item = Gtk.MenuItem(label = "Title Case")
title_strip_case_item = Gtk.MenuItem(label = "Title Strip Case")
au_case_item.connect("activate", on_case_handle, buffer, "on_all_upper")
al_case_item.connect("activate", on_case_handle, buffer, "on_all_lower")
inver_case_item.connect("activate", on_case_handle, buffer, "on_invert")
title_case_item.connect("activate", on_case_handle, buffer, "on_title")
title_strip_case_item.connect("activate", on_case_handle, buffer, "on_title_strip")
case_menu.append(au_case_item)
case_menu.append(al_case_item)
case_menu.append(inver_case_item)
case_menu.append(title_case_item)
case_menu.append(title_strip_case_item)
change_case_item.set_submenu(case_menu)
menu.append(change_case_item)

View File

@@ -17,16 +17,27 @@ 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)
elif event.file.is_externally_modified():
file_is_externally_modified(event)
file = event.response
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):
...
def unload(self):
...
def run(self):
...

View File

@@ -10,23 +10,45 @@ from libs.event_factory import Event_Factory, Code_Event_Types
def file_is_deleted(event):
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
)
self.emit(event)
emit(event)
def file_is_externally_modified(event):
# event = Event_Factory.create_event(
# "file_externally_modified",
# file = event.file,
# buffer = event.buffer
# )
# self.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()

View File

@@ -32,5 +32,8 @@ class Plugin(PluginCode):
def load(self):
...
def unload(self):
...
def run(self):
...

View File

@@ -13,8 +13,6 @@ from gi.repository import Gtk
def add_prettify_json(buffer, menu):
menu.append( Gtk.SeparatorMenuItem() )
def on_prettify_json(menuitem, buffer):
start_itr, \
end_itr = buffer.get_start_iter(), buffer.get_end_iter()

View File

@@ -0,0 +1,214 @@
{
"info": "https://download.eclipse.org/jdtls/",
"info-init-options": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line",
"info-import-build": "https://www.javahotchocolate.com/tutorials/build-path.html",
"info-external-class-paths": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/issues/3291",
"link": "https://download.eclipse.org/jdtls/milestones/?d",
"command": "lsp-ws-proxy --listen 4114 -- jdtls",
"alt-command": "lsp-ws-proxy -- jdtls",
"alt-command2": "java-language-server",
"socket": "ws://127.0.0.1:9999/java",
"socket-two": "ws://127.0.0.1:9999/?name=jdtls",
"alt-socket": "ws://127.0.0.1:9999/?name=java-language-server",
"initialization-options": {
"bundles": [
"intellicode-core.jar"
],
"workspaceFolders": [
"file://{workspace.folder}"
],
"extendedClientCapabilities": {
"classFileContentsSupport": true,
"executeClientCommandSupport": false
},
"settings": {
"java": {
"autobuild": {
"enabled": true
},
"jdt": {
"ls": {
"javac": {
"enabled": true
},
"java": {
"home": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2"
},
"lombokSupport": {
"enabled": true
},
"protobufSupport":{
"enabled": true
},
"androidSupport": {
"enabled": true
}
}
},
"configuration": {
"updateBuildConfiguration": "automatic",
"maven": {
"userSettings": "{user.home}/.config/jdtls/settings.xml",
"globalSettings": "{user.home}/.config/jdtls/settings.xml"
},
"runtimes": [
{
"name": "JavaSE-17",
"path": "/usr/lib/jvm/java-17-openjdk",
"javadoc": "https://docs.oracle.com/en/java/javase/17/docs/api/",
"default": false
},
{
"name": "JavaSE-22",
"path": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2",
"javadoc": "https://docs.oracle.com/en/java/javase/22/docs/api/",
"default": true
}
]
},
"classPath": [
"{user.home}/.config/jdtls/m2/repository/**/*-sources.jar",
"lib/**/*-sources.jar"
],
"docPath": [
"{user.home}/.config/jdtls/m2/repository/**/*-javadoc.jar",
"lib/**/*-javadoc.jar"
],
"project": {
"encoding": "ignore",
"outputPath": "bin",
"referencedLibraries": [
"{user.home}/.config/jdtls/m2/repository/**/*.jar",
"lib/**/*.jar"
],
"importOnFirstTimeStartup": "automatic",
"importHint": true,
"resourceFilters": [
"node_modules",
"\\.git"
],
"sourcePaths": [
"src",
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
]
},
"sources": {
"organizeImports": {
"starThreshold": 99,
"staticStarThreshold": 99
}
},
"imports": {
"gradle": {
"wrapper": {
"checksums": []
}
}
},
"import": {
"maven": {
"enabled": true,
"offline": {
"enabled": false
},
"disableTestClasspathFlag": false
},
"gradle": {
"enabled": false,
"wrapper": {
"enabled": true
},
"version": "",
"home": "abs(static/gradle-7.3.3)",
"java": {
"home": "abs(static/launch_jres/17.0.6-linux-x86_64)"
},
"offline": {
"enabled": false
},
"arguments": [],
"jvmArguments": [],
"user": {
"home": ""
},
"annotationProcessing": {
"enabled": true
}
},
"exclusions": [
"**/node_modules/**",
"**/.metadata/**",
"**/archetype-resources/**",
"**/META-INF/maven/**"
],
"generatesMetadataFilesAtProjectRoot": false
},
"maven": {
"downloadSources": true,
"updateSnapshots": true
},
"silentNotification": true,
"contentProvider": {
"preferred": "fernflower"
},
"signatureHelp": {
"enabled": true,
"description": {
"enabled": true
}
},
"completion": {
"enabled": true,
"engine": "ecj",
"matchCase": "firstletter",
"maxResults": 25,
"guessMethodArguments": true,
"lazyResolveTextEdit": {
"enabled": true
},
"postfix": {
"enabled": true
},
"favoriteStaticMembers": [
"org.junit.Assert.*",
"org.junit.Assume.*",
"org.junit.jupiter.api.Assertions.*",
"org.junit.jupiter.api.Assumptions.*",
"org.junit.jupiter.api.DynamicContainer.*",
"org.junit.jupiter.api.DynamicTest.*"
],
"importOrder": [
"#",
"java",
"javax",
"org",
"com"
]
},
"references": {
"includeAccessors": true,
"includeDecompiledSources": true
},
"codeGeneration": {
"toString": {
"template": "${object.className}{${member.name()}=${member.value}, ${otherMembers}}"
},
"insertionLocation": "afterCursor",
"useBlocks": true
},
"implementationsCodeLens": {
"enabled": true
},
"referencesCodeLens": {
"enabled": true
},
"progressReports": {
"enabled": false
},
"saveActions": {
"organizeImports": true
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "Java LSP Client",
"author": "ITDominator",
"version": "0.0.1",
"support": "",
"autoload": false,
"requests": {}
}

View File

@@ -0,0 +1,43 @@
# Python imports
from os import path
# Lib imports
import gi
from gi.repository import GLib
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from plugins.plugin_types import PluginCode
from .response_handler import JavaHandler
class Plugin(PluginCode):
def __init__(self):
super(Plugin, self).__init__()
def _controller_message(self, event: Code_Event_Types.CodeEvent):
...
def load(self):
dirPth = path.dirname( path.realpath(__file__) )
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
config = f.read()
event = Event_Factory.create_event("register_lsp_client",
lang_id = "java",
lang_config = config,
handler = JavaHandler
)
self.emit_to("lsp_manager", event)
def unload(self):
event = Event_Factory.create_event("unregister_lsp_client",
lang_id = "java"
)
self.emit_to("lsp_manager", event)
def run(self):
...

View File

@@ -0,0 +1 @@
from .java import JavaHandler

View File

@@ -9,7 +9,7 @@ from gi.repository import GtkSource
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from .default import DefaultHandler
from lsp_manager.response_handlers.default import DefaultHandler

View File

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

View File

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

View File

@@ -8,8 +8,9 @@ import gi
from gi.repository import GLib
# Application imports
from libs.dto.code.lsp.lsp_messages import get_message_str
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, ClientRequest, ClientNotification
from ..dto.code.lsp.lsp_messages import get_message_str
from ..dto.code.lsp.lsp_message_structs import \
LSPResponseTypes, ClientRequest, ClientNotification
from .lsp_client_websocket import LSPClientWebsocket

View File

@@ -3,8 +3,9 @@
# Lib imports
# Application imports
from ..dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
from .lsp_client_events import LSPClientEvents
from libs.dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification

View File

@@ -4,15 +4,15 @@ import os
# Lib imports
# Application imports
from libs.dto.code.lsp.lsp_messages import get_message_obj
from libs.dto.code.lsp.lsp_messages import didopen_notification
from libs.dto.code.lsp.lsp_messages import didsave_notification
from libs.dto.code.lsp.lsp_messages import didclose_notification
from libs.dto.code.lsp.lsp_messages import didchange_notification
from libs.dto.code.lsp.lsp_messages import completion_request
from libs.dto.code.lsp.lsp_messages import definition_request
from libs.dto.code.lsp.lsp_messages import references_request
from libs.dto.code.lsp.lsp_messages import symbols_request
from ..dto.code.lsp.lsp_messages import get_message_obj
from ..dto.code.lsp.lsp_messages import didopen_notification
from ..dto.code.lsp.lsp_messages import didsave_notification
from ..dto.code.lsp.lsp_messages import didclose_notification
from ..dto.code.lsp.lsp_messages import didchange_notification
from ..dto.code.lsp.lsp_messages import completion_request
from ..dto.code.lsp.lsp_messages import definition_request
from ..dto.code.lsp.lsp_messages import references_request
from ..dto.code.lsp.lsp_messages import symbols_request

View File

@@ -5,8 +5,8 @@ from gi.repository import GLib
# Application imports
# from libs import websockets
from libs.dto.code.lsp.lsp_messages import get_message_str, get_message_obj
from libs.dto.code.lsp.lsp_message_structs import \
from ..dto.code.lsp.lsp_messages import get_message_str, get_message_obj
from ..dto.code.lsp.lsp_message_structs import \
LSPResponseTypes, ClientRequest, ClientNotification, \
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification

View File

@@ -0,0 +1,8 @@
"""
Libs Code DTO(s) Events Package
"""
from .lsp_event import LspEvent
from .register_lsp_client_event import RegisterLspClientEvent
from .unregister_lsp_client_event import UnregisterLspClientEvent

View File

@@ -0,0 +1,13 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
from libs.dto.code.events import CodeEvent
@dataclass
class LspEvent(CodeEvent):
...

View File

@@ -0,0 +1,17 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
from ....response_handlers.base_handler import BaseHandler
from .lsp_event import LspEvent
@dataclass
class RegisterLspClientEvent(LspEvent):
lang_id: str = ""
lang_config: str = "{}"
handler: BaseHandler = None

View File

@@ -0,0 +1,13 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
from .lsp_event import LspEvent
@dataclass
class UnregisterLspClientEvent(LspEvent):
lang_id: str = ""

View File

@@ -3,7 +3,13 @@
# Lib imports
# Application imports
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, LSPResponseRequest, LSPResponseNotification
from libs.controllers.controller_base import ControllerBase
from libs.event_factory import Event_Factory, Code_Event_Types
from .dto.code.events import \
RegisterLspClientEvent, UnregisterLspClientEvent
from .dto.code.lsp.lsp_message_structs import \
LSPResponseTypes, LSPResponseRequest, LSPResponseNotification
from .provider import Provider
from .provider_response_cache import ProviderResponseCache
@@ -13,7 +19,7 @@ from .response_handlers.response_registry import ResponseRegistry
class LSPManager:
class LSPManager(ControllerBase):
def __init__(self):
super(LSPManager, self).__init__()
@@ -34,8 +40,19 @@ class LSPManager:
self.lsp_manager_ui.connect('close-client', self._on_close_client)
def _do_bind_mapping(self):
self.response_cache.set_lsp_client(self.lsp_manager_client)
self.response_cache.set_lsp_manager_client(self.lsp_manager_client)
self.provider.response_cache = self.response_cache
self.response_registry.set_event_hub(
self.emit, self.emit_to, self.provider
)
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.RegisterLspClientEvent):
self.response_registry.register_handler(event.lang_id, event.handler)
self.lsp_manager_ui.add_client_listing(event.lang_id, event.lang_config)
elif isinstance(event, Code_Event_Types.UnregisterLspClientEvent):
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:
init_opts = ui.get_init_opts(lang_id)
@@ -50,6 +67,10 @@ class LSPManager:
ui.toggle_client_buttons(show_close=False)
return result
def handle_destroy(self):
self.lsp_manager_ui.disconnect_by_func(self._on_create_client)
self.lsp_manager_ui.disconnect_by_func(self._on_close_client)
def create_client(
self,
lang_id: str = "python",

View File

@@ -1,5 +1,4 @@
# Python imports
from os import path
import json
# Lib imports
@@ -25,12 +24,8 @@ class LSPManagerUI(Gtk.Dialog):
def __init__(self):
super(LSPManagerUI, self).__init__()
self._SCRIPT_PTH: str = path.dirname( path.realpath(__file__) )
self._USER_HOME: str = path.expanduser('~')
self._LSP_SERVERS_CONFIG: str = ""
self.servers_config: dict = {}
self.client_configs: dict[str, str] = {}
self.parent = None
self.source_view = None
self._setup_styling()
@@ -46,7 +41,8 @@ class LSPManagerUI(Gtk.Dialog):
self.set_hexpand(True)
def _setup_signals(self):
self.connect("show", self._show)
self.connect("show", self._handle_show)
self.connect("destroy", self._handle_destroy)
def _subscribe_to_events(self):
...
@@ -69,10 +65,11 @@ class LSPManagerUI(Gtk.Dialog):
self.path_entry.set_can_focus(False)
self.path_entry.set_placeholder_text("Workspace Folder...")
self.path_entry.connect("changed", self._path_changed, bttn_box)
self.path_bttn.set_halign(Gtk.Align.FILL)
self.path_bttn.connect("file-set", self._file_set)
self.path_bttn.set_halign(Gtk.Align.FILL)
self.hide_bttn.connect("clicked", lambda widget: self.hide())
self.combo_box.connect("changed", self._on_combo_changed)
self.hide_bttn_id = self.hide_bttn.connect("clicked", lambda widget: self.hide())
self.create_client_bttn.connect("clicked", self._create_client, self.close_client_bttn)
self.close_client_bttn.connect("clicked", self._close_client, self.create_client_bttn)
@@ -96,9 +93,18 @@ class LSPManagerUI(Gtk.Dialog):
self.close_client_bttn.hide()
bttn_box.hide()
def _show(self, widget):
def _handle_show(self, widget):
GLib.idle_add(self.path_entry.grab_focus)
def _handle_destroy(self, widget):
self.disconnect_by_func(self._show)
self.disconnect_by_func(self._handle_destroy)
self.path_bttn.disconnect_by_func(self._file_set)
self.combo_box.disconnect_by_func(self._on_combo_changed)
self.hide_bttn.disconnect(self.hide_bttn_id)
self.create_client_bttn.disconnect_by_func(self._create_client)
self.close_client_bttn.disconnect_by_func(self._close_client)
def _map_resize(self, widget, parent):
parent_x, parent_y = parent.get_position()
parent_width, parent_height = parent.get_size()
@@ -115,19 +121,62 @@ class LSPManagerUI(Gtk.Dialog):
def _path_changed(self, widget, buttons_widget):
if not widget.get_text():
self.path_bttn.unselect_all()
self.path_bttn.emit("file-set")
buttons_widget.hide()
return
self.set_source_view_text( self.path_entry.get_text() )
buttons_widget.show()
def _file_set(self, widget):
self.path_entry.set_text(
widget.get_filename()
fname = widget.get_filename()
fname = "" if not fname else fname
self.path_entry.set_text(fname)
lang_id = self.combo_box.get_active_text()
if not lang_id or lang_id not in self.client_configs: return
self.set_source_view_text(
"{workspace.folder}" if not fname else fname
)
self.load_lsp_servers_config_placeholders()
def _create_client(self, widget, sibling):
if not self.source_view: return
buffer = self.source_view.get_buffer()
lang_id = self.combo_box.get_active_text()
if not lang_id: return
workspace_dir = self.path_entry.get_text()
self.emit('create-client', lang_id, workspace_dir)
def _close_client(self, widget, sibling):
lang_id = self.combo_box.get_active_text()
if not lang_id: return
self.emit('close-client', lang_id)
def _on_combo_changed(self, combo: Gtk.ComboBoxText):
lang_id = combo.get_active_text()
self.set_source_view_text( self.path_entry.get_text() )
def set_source_view_text(self, workspace_dir: str):
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()
buffer.set_text(json_str, -1)
def map_parent_resize_event(self, parent):
parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
self.size_allocate_id = parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
def unmap_parent_resize_event(self, parent):
parent.disconnect(self.size_allocate_id)
def set_source_view(self, source_view):
scrolled_win = Gtk.ScrolledWindow()
@@ -147,68 +196,31 @@ class LSPManagerUI(Gtk.Dialog):
scrolled_win.show_all()
def load_lsp_servers_config(self):
try:
with open(f"{self._SCRIPT_PTH}/configs/lsp-servers-config.json") as file:
self._LSP_SERVERS_CONFIG = file.read()
except FileNotFoundError:
logger.error(f"Config file not found: {self._SCRIPT_PTH}/configs/lsp-servers-config.json")
def add_client_listing(self, lang_id: str, lang_config: str):
self.combo_box.append_text(lang_id)
self.client_configs[lang_id] = lang_config
def load_lsp_servers_config_placeholders(self):
if not self._LSP_SERVERS_CONFIG: return
if not self.source_view: return
def remove_client_listing(self, lang_id: str):
model = self.combo_box.get_model()
data = self._LSP_SERVERS_CONFIG \
.replace("{user.home}", self._USER_HOME) \
.replace("{workspace.folder}", self.path_entry.get_text())
for i, row in enumerate(model):
if row[0] == lang_id: # assuming text is in column 0
self.combo_box.remove(i)
break
self.servers_config = json.loads(data)
buffer = self.source_view.get_buffer()
start_itr, \
end_itr = buffer.get_bounds()
buffer.delete(start_itr, end_itr)
buffer.insert(start_itr, data, -1)
self.set_language_combo_box( list(self.servers_config.keys()) )
def set_language_combo_box(self, lang_ids: list[str]):
self.combo_box.remove_all()
for lang_id in lang_ids:
self.combo_box.append_text(lang_id)
if lang_id in self.client_configs:
del self.client_configs[lang_id]
def get_init_opts(self, lang_id: str) -> dict:
buffer = self.source_view.get_buffer()
if not lang_id or lang_id not in self.client_configs: return {}
try:
self.servers_config = json.loads(
buffer.get_text( *buffer.get_bounds() )
)
lang_config = json.loads(self.client_configs[lang_id])
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON: {e}")
logger.error(f"Invalid JSON for {lang_id}: {e}")
return {}
if not lang_id or not lang_id in self.servers_config: return {}
return self.servers_config[lang_id].get("initialization-options", {})
def _create_client(self, widget, sibling):
if not self.source_view: return
buffer = self.source_view.get_buffer()
lang_id = self.combo_box.get_active_text()
if not lang_id: return
workspace_dir = self.path_entry.get_text()
self.emit('create-client', lang_id, workspace_dir)
def _close_client(self, widget, sibling):
lang_id = self.combo_box.get_active_text()
if not lang_id: return
self.emit('close-client', lang_id)
return lang_config.get("initialization-options", {})
def toggle_client_buttons(self, show_close: bool):
self.create_client_bttn.set_visible(not show_close)

View File

@@ -0,0 +1,9 @@
{
"name": "LSP Manager",
"author": "ITDominator",
"version": "0.0.1",
"support": "",
"pre_launch": true,
"autoload": false,
"requests": {}
}

View File

@@ -11,6 +11,7 @@ from libs.dto.states import SourceViewStates
from plugins.plugin_types import PluginCode
from .dto.code import events as lsp_events
from .lsp_manager import LSPManager
@@ -28,6 +29,10 @@ class Plugin(PluginCode):
...
def load(self):
Event_Factory.register_events( lsp_events.__dict__.items() )
self.register_controller("lsp_manager", lsp_manager)
window = self.request_ui_element("main-window")
lsp_manager.lsp_manager_ui.map_parent_resize_event(window)
@@ -55,11 +60,32 @@ class Plugin(PluginCode):
self.emit_to("source_views", event)
source_view = event.response
lsp_manager.lsp_manager_ui.load_lsp_servers_config()
lsp_manager.lsp_manager_ui.set_source_view(source_view)
lsp_manager.lsp_manager_ui.load_lsp_servers_config_placeholders()
lsp_manager.response_registry.set_event_hub(self.emit, self.emit_to, lsp_manager.provider)
def unload(self):
Event_Factory.unregister_events( lsp_events.__dict__.items() )
self.unregister_controller("lsp_manager")
window = self.request_ui_element("main-window")
lsp_manager.lsp_manager_ui.unmap_parent_resize_event(window)
event = Event_Factory.create_event("unregister_command",
command_name = "LSP Manager",
command = Handler,
binding_mode = "released",
binding = ["<Shift><Control>l", "<Control>g", "<Control>i"]
)
self.emit_to("source_views", event)
event = Event_Factory.create_event(
"unregister_provider",
provider_name = "LSP Completer"
)
self.emit_to("completion", event)
lsp_manager.handle_destroy()
def run(self):
...

View File

@@ -15,27 +15,27 @@ class ProviderResponseCache(ProviderResponseCacheBase):
def __init__(self):
super(ProviderResponseCache, self).__init__()
self.matchers: dict = {}
self._lsp_client = None
self.matchers: dict = {}
self.lsp_manager_client = None
def set_lsp_client(self, lsp_client):
self._lsp_client = lsp_client
def set_lsp_manager_client(self, lsp_client):
self.lsp_manager_client = lsp_client
def process_file_load(self, event):
if self._lsp_client:
self._lsp_client.process_file_load(event)
if self.lsp_manager_client:
self.lsp_manager_client.process_file_load(event)
def process_file_close(self, event):
if self._lsp_client:
self._lsp_client.process_file_close(event)
if self.lsp_manager_client:
self.lsp_manager_client.process_file_close(event)
def process_file_save(self, event):
if self._lsp_client:
self._lsp_client.process_file_save(event)
if self.lsp_manager_client:
self.lsp_manager_client.process_file_save(event)
def process_file_change(self, event):
if self._lsp_client:
self._lsp_client.process_file_change(event)
if self.lsp_manager_client:
self.lsp_manager_client.process_file_change(event)
def filter(self, word: str) -> list[dict]:
return []

View File

@@ -0,0 +1,3 @@
from .base_handler import BaseHandler
from .default import DefaultHandler
from .response_registry import ResponseRegistry

View File

@@ -8,7 +8,7 @@ from gi.repository import GLib
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from .base import BaseHandler
from .base_handler import BaseHandler

View File

@@ -3,10 +3,8 @@
# Lib imports
# Application imports
from .base import BaseHandler
from .base_handler import BaseHandler
from .default import DefaultHandler
from .python import PythonHandler
from .java import JavaHandler
@@ -15,12 +13,11 @@ class ResponseRegistry:
self._instances: dict = {}
self._lang_handlers: dict = {
"default": DefaultHandler,
"python": PythonHandler,
"java": JavaHandler,
"default": DefaultHandler
}
def set_event_hub(self, emit, emit_to, provider=None):
def set_event_hub(self, emit, emit_to, provider = None):
self.emit = emit
self.emit_to = emit_to
self._provider = provider
@@ -36,6 +33,9 @@ class ResponseRegistry:
def register_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
self._lang_handlers[lang_id] = handler_cls
def unregister_handler(self, lang_id: str):
del self._lang_handlers[lang_id]
def get_handler(self, lang_id: str = "", method: str = ""):
handler_cls = self._lang_handlers.get(
lang_id, self._lang_handlers.get("default", DefaultHandler)

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
{
"name": "Python LSP Client",
"author": "ITDominator",
"version": "0.0.1",
"support": "",
"autoload": false,
"requests": {}
}

View File

@@ -0,0 +1,43 @@
# Python imports
from os import path
# Lib imports
import gi
from gi.repository import GLib
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
from plugins.plugin_types import PluginCode
from .response_handler import PythonHandler
class Plugin(PluginCode):
def __init__(self):
super(Plugin, self).__init__()
def _controller_message(self, event: Code_Event_Types.CodeEvent):
...
def load(self):
dirPth = path.dirname( path.realpath(__file__) )
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
config = f.read()
event = Event_Factory.create_event("register_lsp_client",
lang_id = "python",
lang_config = config,
handler = PythonHandler
)
self.emit_to("lsp_manager", event)
def unload(self):
event = Event_Factory.create_event("unregister_lsp_client",
lang_id = "python"
)
self.emit_to("lsp_manager", event)
def run(self):
...

View File

@@ -0,0 +1 @@
from .python import PythonHandler

View File

@@ -3,7 +3,7 @@
# Lib imports
# Application imports
from .default import DefaultHandler
from lsp_manager.response_handlers.default import DefaultHandler

View File

@@ -28,5 +28,12 @@ class Plugin(PluginCode):
editors_container = self.request_ui_element("editors-container")
editors_container.add( code_minimap )
event = Event_Factory.create_event("get_active_view")
self.emit_to("source_views", event)
code_minimap.set_smini_view(event.response)
def unload(self):
code_minimap.destroy()
def run(self):
...

View File

@@ -35,7 +35,6 @@ class InfoBarWidget(Gtk.Box):
def _subscribe_to_events(self):
...
def _load_widgets(self):
self.path_label = Gtk.Label(label = "...")
self.line_char_label = Gtk.Label(label = "1:0")
@@ -92,5 +91,3 @@ class InfoBarWidget(Gtk.Box):
encoding_type = "utf-8" if not encoding_type else encoding_type
self.encoding_label.set_text(encoding_type)

View File

@@ -28,5 +28,8 @@ class Plugin(PluginCode):
header = self.request_ui_element("header-container")
header.add( info_bar_widget )
def unload(self):
info_bar_widget.destroy()
def run(self):
...

View File

@@ -1,5 +0,0 @@
from .base import BaseHandler
from .default import DefaultHandler
from .python import PythonHandler
from .java import JavaHandler
from .response_registry import ResponseRegistry

View File

@@ -1,6 +1,9 @@
# Python imports
# Lib imports
import gi
from gi.repository import Gtk
# Application imports
from libs.event_factory import Event_Factory, Code_Event_Types
@@ -20,13 +23,45 @@ class Plugin(PluginCode):
...
def load(self):
tabs_controller = TabsController()
self.tabs_controller = TabsController()
code_container = self.request_ui_element("code-container")
self.register_controller("tabs", tabs_controller)
self.register_controller("tabs", self.tabs_controller)
code_container.add( tabs_controller.tabs_widget )
code_container.reorder_child(tabs_controller.tabs_widget, 0)
scrolled_win = Gtk.ScrolledWindow()
viewport = Gtk.Viewport()
scrolled_win.set_overlay_scrolling(False)
scrolled_win.set_size_request(-1, 50)
viewport.add( self.tabs_controller.tabs_widget )
scrolled_win.add( viewport )
code_container.add( scrolled_win )
code_container.reorder_child(scrolled_win, 0)
viewport.show()
scrolled_win.show()
event = Event_Factory.create_event("get_files")
self.emit_to("files", event)
for file in event.response:
self.tabs_controller.add_tab(file)
def unload(self):
self.unregister_controller("tabs")
self.tabs_controller.unload_tabs()
tabs_widget = self.tabs_controller.tabs_widget
viewport = tabs_widget.get_parent()
scrolled_win = viewport.get_parent()
tabs_widget.destroy()
viewport.destroy()
scrolled_win.destroy()
self.tabs_controller.tabs_widget = None
self.tabs_controller = None
del self.tabs_controller
def run(self):
...

View File

@@ -32,7 +32,6 @@ class TabWidget(Gtk.Box):
self.set_orientation(0)
self.set_hexpand(False)
self.set_vexpand(False)
self.set_can_focus(False)
self.set_size_request(-1, 12)
def _setup_signals(self):
@@ -44,10 +43,6 @@ class TabWidget(Gtk.Box):
self.close_bttn = Gtk.Button()
icon = Gtk.Image(stock = Gtk.STOCK_CLOSE)
self.event_box.set_can_focus(False)
self.label.set_can_focus(False)
self.close_bttn.set_can_focus(False)
self.event_box.set_above_child(True)
ctx = self.label.get_style_context()
ctx.add_class("tab-label")

View File

@@ -16,7 +16,6 @@ from .tab_widget import TabWidget
class TabsController(ControllerBase):
def __init__(self):
super(TabsController, self).__init__()
@@ -35,7 +34,7 @@ class TabsController(ControllerBase):
elif isinstance(event, Code_Event_Types.FileExternallyDeletedEvent):
self.tabs_widget.externally_deleted( event.buffer )
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
self.add_tab(event)
self.add_tab(event.file)
elif isinstance(event, Code_Event_Types.PoppedFileEvent):
...
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
@@ -53,11 +52,11 @@ class TabsController(ControllerBase):
break
def add_tab(self, event: Code_Event_Types.AddedNewFileEvent):
def add_tab(self, file):
tab = TabWidget()
tab.file = event.file
tab.file = file
tab.label.set_label(event.file.fname)
tab.label.set_label(file.fname)
self.tabs_widget.append_page(Gtk.Separator(), tab)
tab.show_all()
@@ -73,3 +72,13 @@ class TabsController(ControllerBase):
)
break
def unload_tabs(self):
for page_widget in self.tabs_widget.get_children():
tab = self.tabs_widget.get_tab_label(page_widget)
tab.clear_signals_and_data()
self.tabs_widget.remove_page(
self.tabs_widget.page_num(page_widget)
)

View File

@@ -27,12 +27,13 @@ class TabsWidget(Gtk.Notebook):
def _setup_styling(self):
self.set_scrollable(True)
...
def _setup_signals(self):
self.connect("page-added", self._page_added)
self.switch_page_id = \
self.connect_after("switch-page", self._switch_page)
self.connect("destroy", self._handle_destroy)
def _subscribe_to_events(self):
...
@@ -66,6 +67,7 @@ class TabsWidget(Gtk.Notebook):
)
self.emit(event)
self._scroll_to_center(tab)
def _bind_tab_menu(self, tab, page_widget):
def do_context_menu(tab, eve, page_widget):
@@ -80,26 +82,54 @@ class TabsWidget(Gtk.Notebook):
page_widget
)
def _scroll_to_center(self, tab):
scrolled_win = self.get_parent().get_parent()
alloc = tab.get_allocation()
tab_x = alloc.x
tab_width = alloc.width
view_width = scrolled_win.get_allocated_width()
target = tab_x + tab_width / 2 - view_width / 2
adj = scrolled_win.get_hadjustment()
lower = adj.get_lower()
upper = adj.get_upper()
page_size = adj.get_page_size()
target = max(lower, min(target, upper - page_size))
adj.set_value(target)
def create_menu(self, page_widget) -> Gtk.Menu:
context_menu = Gtk.Menu()
context_menu = Gtk.Menu()
close_submenu = Gtk.Menu()
save_item = Gtk.MenuItem(label = "Save")
save_as_item = Gtk.MenuItem(label = "Save As")
close_item = Gtk.MenuItem(label = "Close Tab")
close_left_item = Gtk.MenuItem(label = "Close Tabs Left")
close_right_item = Gtk.MenuItem(label = "Close Tabs Right")
close_other_item = Gtk.MenuItem(label = "Close Other Tabs")
close_all_item = Gtk.MenuItem(label = "Close All Tabs")
close_actions_menu = Gtk.MenuItem(label = "Close Actions")
close_item = Gtk.MenuItem(label = "Close Tab")
close_left_item = Gtk.MenuItem(label = "Close Tabs Left")
close_right_item = Gtk.MenuItem(label = "Close Tabs Right")
close_other_item = Gtk.MenuItem(label = "Close Other Tabs")
close_all_item = Gtk.MenuItem(label = "Close All Tabs")
close_item.connect("activate", self.close_item, page_widget)
close_left_item.connect("activate", self.close_left_items, page_widget)
save_item.connect("activate", self.save_item, page_widget)
save_as_item.connect("activate", self.save_as_item, page_widget)
close_item.connect("activate", self.close_item, page_widget)
close_left_item.connect("activate", self.close_left_items, page_widget)
close_right_item.connect("activate", self.close_right_items, page_widget)
close_other_item.connect("activate", self.close_other_items, page_widget)
close_all_item.connect("activate", self.close_all_items, page_widget)
close_all_item.connect("activate", self.close_all_items, page_widget)
context_menu.append(close_item)
context_menu.append(close_left_item)
context_menu.append(close_right_item)
context_menu.append(close_other_item)
context_menu.append(close_all_item)
close_submenu.append(close_item)
close_submenu.append(close_left_item)
close_submenu.append(close_right_item)
close_submenu.append(close_other_item)
close_submenu.append(close_all_item)
close_actions_menu.set_submenu(close_submenu)
context_menu.append(save_item)
context_menu.append(save_as_item)
context_menu.append(close_actions_menu)
context_menu.show_all()
@@ -115,8 +145,8 @@ class TabsWidget(Gtk.Notebook):
self.set_current_page(
self.page_num(page_widget)
)
self.handler_unblock(self.switch_page_id)
self._scroll_to_center(tab)
break
@@ -143,6 +173,14 @@ class TabsWidget(Gtk.Notebook):
break
def save_item(self, menu_item, page_widget):
tab = self.get_tab_label(page_widget)
tab.file.save()
def save_as_item(self, menu_item, page_widget):
tab = self.get_tab_label(page_widget)
tab.file.save_as()
def close_item(self, menu_item, page_widget):
tab = self.get_tab_label(page_widget)
tab.close_bttn.clicked()
@@ -177,3 +215,9 @@ class TabsWidget(Gtk.Notebook):
for widget in children[ : ]:
tab = self.get_tab_label(widget)
tab.close_bttn.clicked()
def _handle_destroy(self, widget):
self.disconnect_by_func(self._page_added)
self.disconnect_by_func(self._switch_page)
self.disconnect_by_func(self._handle_destroy)

View File

@@ -24,8 +24,16 @@ class Plugin(PluginUI):
ui_element = self.request_ui_element("header-container")
ui_element.add( self.generate_plugin_element() )
def unload(self):
ui_element = self.request_ui_element("header-container")
self.button = self.generate_plugin_element()
ui_element.add( self.button )
def run(self):
...
self.button.disconnect_by_func(self.send_message)
self.button.destroy()
del button
def generate_plugin_element(self):
button = Gtk.Button(label = "Hello, World!")

View File

@@ -19,7 +19,6 @@ class BaseContainer(Gtk.Box):
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -32,12 +31,16 @@ class BaseContainer(Gtk.Box):
self._update_transparency()
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
event_system.subscribe("update-transparency", self._update_transparency)
event_system.subscribe("remove-transparency", self._remove_transparency)
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("base-container", self)

View File

@@ -19,7 +19,6 @@ class BodyContainer(Gtk.Box):
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -29,14 +28,17 @@ class BodyContainer(Gtk.Box):
self.ctx.add_class("body-container")
self.set_orientation(Gtk.Orientation.HORIZONTAL)
self.set_homogeneous(True)
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
...
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("body-container", self)

View File

@@ -14,11 +14,9 @@ class CenterContainer(Gtk.Box):
def __init__(self):
super(CenterContainer, self).__init__()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -32,11 +30,15 @@ class CenterContainer(Gtk.Box):
self.set_vexpand(True)
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
...
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("center-container", self)

View File

@@ -4,7 +4,7 @@
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GLib
#from gi.repository import GLib
# Application imports
@@ -31,7 +31,7 @@ class EditorsContainer(Gtk.Paned):
self.set_wide_handle(True)
def _setup_signals(self):
self.map_id = self.connect("map", self._init_map)
self.connect("map", self._init_map)
def _subscribe_to_events(self):
...
@@ -59,13 +59,6 @@ class EditorsContainer(Gtk.Paned):
return scrolled_win1, scrolled_win2
def _init_map(self, view):
def _first_show_init():
self.disconnect(self.map_id)
del self.map_id
self.code_base.first_map_load()
del self.code_base
return False
GLib.timeout_add(100, _first_show_init)
self.disconnect_by_func( self._init_map )
self.code_base.first_map_load()
del self.code_base

View File

@@ -17,7 +17,6 @@ class FooterContainer(Gtk.Box):
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -30,11 +29,15 @@ class FooterContainer(Gtk.Box):
self.set_hexpand(True)
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
...
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("footer-container", self)

View File

@@ -19,7 +19,6 @@ class HeaderContainer(Gtk.Box):
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -32,11 +31,15 @@ class HeaderContainer(Gtk.Box):
self.set_hexpand(True)
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
event_system.subscribe("tggl-top-main-menubar", self.tggl_top_main_menubar)
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("header-container", self)

View File

@@ -18,7 +18,6 @@ class LeftContainer(Gtk.Box):
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
@@ -31,11 +30,15 @@ class LeftContainer(Gtk.Box):
self.set_vexpand(True)
def _setup_signals(self):
...
self.connect("show", self._handle_show)
def _subscribe_to_events(self):
...
def _handle_show(self, widget):
self.disconnect_by_func( self._handle_show )
self._load_widgets()
def _load_widgets(self):
widget_registery.expose_object("left-container", self)

Some files were not shown because too many files have changed in this diff Show More