Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 22abc02d25 | |||
| 8ee2106f50 | |||
| 1447a68fb0 | |||
| b724d41f6c | |||
| 597ac2b06a | |||
| 2e84ad9fc1 | |||
| a2b8232d5e | |||
| 0b3579d485 | |||
| ec571ffa90 | |||
| 3b205e28e6 | |||
| 24bf1e471b | |||
| 824dd93696 | |||
| 7c7e88aaed | |||
| 67300bc180 | |||
| 55d2d99d68 | |||
| eb9e124df5 | |||
| 6714053776 | |||
| 69c8418a72 | |||
| d4dc972c6d | |||
| 6c42ff7c7d | |||
| b922415f98 | |||
| 5273c58ed6 | |||
| 4ce4d85842 | |||
| c6b10ceb17 | |||
| a036dc428b | |||
| b8ce6e160a | |||
| e2f29207ba | |||
| 99f1bffefb | |||
| f7d944f7a9 | |||
| 4469e8189f | |||
| a507469bf8 | |||
| a07123d165 | |||
| 00c72a7117 | |||
| f8d73ad74a | |||
| 04e0c3caf6 | |||
| a57bfd94fc | |||
| c2060963cc | |||
| 8253e250d8 | |||
| be608f645e | |||
| 356da04f46 | |||
| 48182f9775 | |||
| 90b2f050c6 | |||
| 79375d34b1 | |||
| 5ee587e205 | |||
| 3fc39042f1 | |||
| e18be655e8 | |||
| 12ada8568e | |||
| 4c179974c0 | |||
| 6acbcb53c2 | |||
| ce22ed6a53 | |||
| c16493037d | |||
| 849e7611ca | |||
| 2c453bc621 | |||
| 530fe7c3ab | |||
| 5e5cc50ba8 |
@@ -1,31 +0,0 @@
|
||||
### Note
|
||||
Copy the example and rename it to your desired name. Plugins define a ui target slot with the 'ui_target' requests data but don't have to if not directly interacted with.
|
||||
Plugins must have a run method defined; though, you do not need to necessarily do anything within it. The run method implies that the passed in event system or other data is ready for the plugin to use.
|
||||
|
||||
|
||||
### Manifest Example (All are required even if empty.)
|
||||
```
|
||||
class Manifest:
|
||||
name: str = "Example Plugin"
|
||||
author: str = "John Doe"
|
||||
version: str = "0.0.1"
|
||||
support: str = ""
|
||||
requests: {} = {
|
||||
'pass_ui_objects': ["plugin_control_list"],
|
||||
'pass_events': "true",
|
||||
'bind_keys': []
|
||||
}
|
||||
pre_launch: bool = False
|
||||
```
|
||||
|
||||
|
||||
### Requests
|
||||
```
|
||||
requests: {} = {
|
||||
'pass_events': "true", # If empty or not present will be ignored.
|
||||
"pass_ui_objects": [""], # Request reference to a UI component. Will be passed back as array to plugin.
|
||||
'bind_keys': [f"{name}||send_message:<Control>f"],
|
||||
f"{name}||do_save:<Control>s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right.
|
||||
|
||||
}
|
||||
```
|
||||
3
plugins/code/commands/autopairs/__init__.py
Normal file
3
plugins/code/commands/autopairs/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Plugin Module
|
||||
"""
|
||||
3
plugins/code/commands/autopairs/__main__.py
Normal file
3
plugins/code/commands/autopairs/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Plugin Package
|
||||
"""
|
||||
97
plugins/code/commands/autopairs/autopairs.py
Normal file
97
plugins/code/commands/autopairs/autopairs.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class Autopairs:
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def handle_word_wrap(self, buffer, char_str: str):
|
||||
wrap_block = self.get_wrap_block(char_str)
|
||||
if not wrap_block: return
|
||||
|
||||
selection = buffer.get_selection_bounds()
|
||||
if not selection:
|
||||
self.insert_pair(buffer, char_str, wrap_block)
|
||||
return True
|
||||
|
||||
self.wrap_selection(buffer, char_str, wrap_block, selection)
|
||||
|
||||
return True
|
||||
|
||||
def insert_pair(
|
||||
self, buffer, char_str: str, wrap_block: tuple
|
||||
):
|
||||
buffer.begin_user_action()
|
||||
|
||||
left_block, right_block = wrap_block
|
||||
insert_mark = buffer.get_insert()
|
||||
|
||||
insert_itr = buffer.get_iter_at_mark(insert_mark)
|
||||
buffer.insert(insert_itr, f"{left_block}{right_block}")
|
||||
insert_itr = buffer.get_iter_at_mark( insert_mark )
|
||||
insert_itr.backward_char()
|
||||
|
||||
buffer.place_cursor(insert_itr)
|
||||
|
||||
buffer.end_user_action()
|
||||
|
||||
def wrap_selection(
|
||||
self, buffer, char_str: str, wrap_block: tuple, selection
|
||||
):
|
||||
left_block, \
|
||||
right_block = wrap_block
|
||||
start_itr, \
|
||||
end_itr = selection
|
||||
data = buffer.get_text(
|
||||
start_itr, end_itr, include_hidden_chars = False
|
||||
)
|
||||
start_mark = buffer.create_mark("startclose", start_itr, False)
|
||||
end_mark = buffer.create_mark("endclose", end_itr, True)
|
||||
|
||||
buffer.begin_user_action()
|
||||
|
||||
buffer.insert(start_itr, left_block)
|
||||
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||
buffer.insert(end_itr, right_block)
|
||||
|
||||
start = buffer.get_iter_at_mark(start_mark)
|
||||
end = buffer.get_iter_at_mark(end_mark)
|
||||
|
||||
buffer.select_range(start, end)
|
||||
buffer.delete_mark_by_name("startclose")
|
||||
buffer.delete_mark_by_name("endclose")
|
||||
|
||||
buffer.end_user_action()
|
||||
|
||||
def get_wrap_block(self, char_str) -> tuple:
|
||||
left_block = ""
|
||||
right_block = ""
|
||||
|
||||
match char_str:
|
||||
case "(" | ")":
|
||||
left_block = "("
|
||||
right_block = ")"
|
||||
case "[" | "]":
|
||||
left_block = "["
|
||||
right_block = "]"
|
||||
case "{" | "}":
|
||||
left_block = "{"
|
||||
right_block = "}"
|
||||
case '"':
|
||||
left_block = '"'
|
||||
right_block = '"'
|
||||
case "'":
|
||||
left_block = "'"
|
||||
right_block = "'"
|
||||
case "`":
|
||||
left_block = "`"
|
||||
right_block = "`"
|
||||
case _:
|
||||
return ()
|
||||
|
||||
return left_block, right_block
|
||||
7
plugins/code/commands/autopairs/manifest.json
Normal file
7
plugins/code/commands/autopairs/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Autopairs",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
55
plugins/code/commands/autopairs/plugin.py
Normal file
55
plugins/code/commands/autopairs/plugin.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .autopairs import Autopairs
|
||||
|
||||
|
||||
|
||||
autopairs = Autopairs()
|
||||
|
||||
|
||||
|
||||
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 = "autopairs",
|
||||
command = Handler,
|
||||
binding_mode = "held",
|
||||
binding = [
|
||||
"'", "`", "[", "]",
|
||||
'<Shift>"',
|
||||
'<Shift>(',
|
||||
'<Shift>)',
|
||||
'<Shift>{',
|
||||
'<Shift>}'
|
||||
]
|
||||
)
|
||||
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
|
||||
class Handler:
|
||||
@staticmethod
|
||||
def execute(
|
||||
view: any,
|
||||
char_str: str,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Autopairs")
|
||||
autopairs.handle_word_wrap(view.get_buffer(), char_str)
|
||||
7
plugins/code/commands/prettify_json/manifest.json
Normal file
7
plugins/code/commands/prettify_json/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Prettify JSON",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
55
plugins/code/commands/prettify_json/plugin.py
Normal file
55
plugins/code/commands/prettify_json/plugin.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Python imports
|
||||
import json
|
||||
|
||||
# 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 plugins.plugin_types import PluginCode
|
||||
|
||||
|
||||
|
||||
def _load_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()
|
||||
data = buffer.get_text(start_itr, end_itr, False)
|
||||
text = json.dumps(json.loads(data), separators = (',', ':'), indent = 4)
|
||||
|
||||
buffer.begin_user_action()
|
||||
buffer.delete(start_itr, end_itr)
|
||||
buffer.insert(start_itr, text)
|
||||
buffer.end_user_action()
|
||||
|
||||
item = Gtk.MenuItem(label = "Prettify JSON")
|
||||
item.connect("activate", on_prettify_json, buffer)
|
||||
menu.append(item)
|
||||
|
||||
|
||||
|
||||
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):
|
||||
language = event.buffer.get_language()
|
||||
if not language: return
|
||||
|
||||
if language.get_id() == "json":
|
||||
_load_prettify_json(event.buffer, event.menu)
|
||||
|
||||
def load(self):
|
||||
...
|
||||
|
||||
def run(self):
|
||||
...
|
||||
3
plugins/code/commands/toggle_source_view/__init__.py
Normal file
3
plugins/code/commands/toggle_source_view/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Plugin Module
|
||||
"""
|
||||
3
plugins/code/commands/toggle_source_view/__main__.py
Normal file
3
plugins/code/commands/toggle_source_view/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Plugin Package
|
||||
"""
|
||||
7
plugins/code/commands/toggle_source_view/manifest.json
Normal file
7
plugins/code/commands/toggle_source_view/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Toggle Source View",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
54
plugins/code/commands/toggle_source_view/plugin.py
Normal file
54
plugins/code/commands/toggle_source_view/plugin.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
event = Event_Factory.create_event("register_command",
|
||||
command_name = "toggle_source_view",
|
||||
command = Handler,
|
||||
binding_mode = "released",
|
||||
binding = "<Shift><Control>h"
|
||||
)
|
||||
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
|
||||
class Handler:
|
||||
@staticmethod
|
||||
def execute(
|
||||
view: any,
|
||||
char_str: str,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Toggle Source View")
|
||||
target = view.get_parent()
|
||||
target.hide() if target.is_visible() else target.show()
|
||||
|
||||
if view.sibling_left:
|
||||
target = view.sibling_left.get_parent()
|
||||
target.show()
|
||||
view.sibling_left.grab_focus()
|
||||
|
||||
if view.sibling_right:
|
||||
target = view.sibling_right.get_parent()
|
||||
target.show()
|
||||
view.sibling_right.grab_focus()
|
||||
|
||||
3
plugins/code/completers/example_completer/__init__.py
Normal file
3
plugins/code/completers/example_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/completers/example_completer/__main__.py
Normal file
3
plugins/code/completers/example_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
7
plugins/code/completers/example_completer/manifest.json
Normal file
7
plugins/code/completers/example_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Example Completer",
|
||||
"author": "John Doe",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
39
plugins/code/completers/example_completer/plugin.py
Normal file
39
plugins/code/completers/example_completer/plugin.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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 plugins.plugin_types import PluginCode
|
||||
|
||||
from .provider import Provider
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
self.provider: Provider = None
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
self.provider = Provider()
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"register_provider",
|
||||
provider_name = "Example Completer",
|
||||
provider = self.provider,
|
||||
language_ids = []
|
||||
)
|
||||
self.emit_to("completion", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
76
plugins/code/completers/example_completer/provider.py
Normal file
76
plugins/code/completers/example_completer/provider.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
|
||||
|
||||
|
||||
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This is a custom Completion Example Provider.
|
||||
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||
"""
|
||||
__gtype_name__ = 'ExampleCompletionProvider'
|
||||
|
||||
def __init__(self):
|
||||
super(Provider, self).__init__()
|
||||
|
||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||
|
||||
|
||||
def do_get_name(self):
|
||||
""" Returns: a new string containing the name of the provider. """
|
||||
return 'Example Code Completion'
|
||||
|
||||
def do_match(self, context):
|
||||
# Note: If provider is in interactive activation then need to check
|
||||
# view focus as otherwise non focus views start trying to grab it.
|
||||
completion = context.get_property("completion")
|
||||
if not completion.get_view().has_focus(): return
|
||||
|
||||
word = self.response_cache.get_word(context)
|
||||
if not word or len(word) < 2: return False
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
""" Determin position in result list along other providor results. """
|
||||
return 5
|
||||
|
||||
def do_activate_proposal(self, proposal, iter_):
|
||||
""" Manually handle actual completion insert or set flags and handle normally. """
|
||||
|
||||
buffer = iter_.get_buffer()
|
||||
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||
# to insure marker processes inserted text correctly.
|
||||
buffer.is_processing_completion = True
|
||||
return False
|
||||
|
||||
def do_get_activation(self):
|
||||
""" The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
# return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
# return GtkSource.CompletionActivation.USER_REQUESTED | GtkSource.CompletionActivation.INTERACTIVE
|
||||
return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
results = self.response_cache.filter_with_context(context)
|
||||
proposals = []
|
||||
|
||||
for entry in results:
|
||||
proposals.append(
|
||||
self.response_cache.create_completion_item(
|
||||
entry["label"],
|
||||
entry["text"],
|
||||
entry["info"]
|
||||
)
|
||||
)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Python imports
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import re
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||
|
||||
|
||||
|
||||
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||
def __init__(self):
|
||||
super(ProviderResponseCache, self).__init__()
|
||||
|
||||
# Note: Using asyncio.run causes a keyboard trap that prevents app
|
||||
# closure from terminal. ThreadPoolExecutor seems to not have such issues...
|
||||
self.executor = ThreadPoolExecutor(max_workers = 1)
|
||||
self.matchers: dict = {
|
||||
"hello": {
|
||||
"label": "Hello, World!",
|
||||
"text": "Hello, World!",
|
||||
"info": GLib.markup_escape_text( "<b>Says the first ever program developers write...</b>" )
|
||||
},
|
||||
"foo": {
|
||||
"label": "foo",
|
||||
"text": "foo }}"
|
||||
},
|
||||
"bar": {
|
||||
"label": "bar",
|
||||
"text": "bar }}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
...
|
||||
|
||||
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||
...
|
||||
|
||||
def filter(self, word: str) -> list[dict]:
|
||||
...
|
||||
|
||||
def filter_with_context(self, context) -> list[dict]:
|
||||
"""
|
||||
In this instance, it will do 2 things:
|
||||
1) always provide Hello World! (Not ideal but an option so its in the example)
|
||||
2) Utilizes the Gtk.TextIter from the TextBuffer to determine if there is a jinja
|
||||
example of '{{ custom.' if so it will provide you with the options of foo and bar.
|
||||
If selected it will insert foo }} or bar }}, completing your syntax...
|
||||
|
||||
PLEASE NOTE the GtkTextIter Logic and regex are really rough and should be adjusted and tuned
|
||||
"""
|
||||
|
||||
proposals: list[dict] = [
|
||||
{
|
||||
"label": self.matchers[ "hello" ]["label"],
|
||||
"text": self.matchers[ "hello" ]["text"],
|
||||
"info": self.matchers[ "hello" ]["info"]
|
||||
}
|
||||
]
|
||||
|
||||
# Gtk Versions differ on get_iter responses...
|
||||
end_iter = context.get_iter()
|
||||
if not isinstance(end_iter, Gtk.TextIter):
|
||||
_, end_iter = context.get_iter()
|
||||
|
||||
if not end_iter: return
|
||||
|
||||
buf = end_iter.get_buffer()
|
||||
mov_iter = end_iter.copy()
|
||||
if mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY):
|
||||
mov_iter, _ = mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY)
|
||||
left_text = buf.get_text(mov_iter, end_iter, True)
|
||||
else:
|
||||
left_text = ''
|
||||
|
||||
if re.match(r'.*\{\{\s*custom\.$', left_text):
|
||||
# optionally proposed based on left search via regex
|
||||
proposals.append(
|
||||
{
|
||||
"label": self.matchers[ "foo" ]["label"],
|
||||
"text": self.matchers[ "foo" ]["text"],
|
||||
"info": ""
|
||||
}
|
||||
)
|
||||
|
||||
# optionally proposed based on left search via regex
|
||||
proposals.append(
|
||||
{
|
||||
"label": self.matchers[ "bar" ]["label"],
|
||||
"text": self.matchers[ "bar" ]["text"],
|
||||
"info": ""
|
||||
}
|
||||
)
|
||||
|
||||
return proposals
|
||||
3
plugins/code/completers/lsp_completer/__init__.py
Normal file
3
plugins/code/completers/lsp_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/completers/lsp_completer/__main__.py
Normal file
3
plugins/code/completers/lsp_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
7
plugins/code/completers/lsp_completer/manifest.json
Normal file
7
plugins/code/completers/lsp_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "LSP Completer",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
42
plugins/code/completers/lsp_completer/plugin.py
Normal file
42
plugins/code/completers/lsp_completer/plugin.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# 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 plugins.plugin_types import PluginCode
|
||||
|
||||
from .provider import Provider
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
self.provider: Provider = None
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
self.provider = Provider()
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"register_provider",
|
||||
provider_name = "LSP Completer",
|
||||
provider = self.provider,
|
||||
language_ids = []
|
||||
)
|
||||
self.emit_to("completion", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
def generate_plugin_element(self):
|
||||
...
|
||||
82
plugins/code/completers/lsp_completer/provider.py
Normal file
82
plugins/code/completers/lsp_completer/provider.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
|
||||
|
||||
|
||||
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This code is an LSP code completion plugin for Newton.
|
||||
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
|
||||
"""
|
||||
__gtype_name__ = 'LSPProvider'
|
||||
|
||||
def __init__(self):
|
||||
super(Provider, self).__init__()
|
||||
|
||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||
|
||||
|
||||
def pre_populate(self, context):
|
||||
...
|
||||
|
||||
def do_get_name(self):
|
||||
return "LSP Code Completion"
|
||||
|
||||
def do_match(self, context):
|
||||
word = self.response_cache.get_word(context)
|
||||
if not word or len(word) < 2: return False
|
||||
|
||||
iter = self.response_cache.get_iter_correctly(context)
|
||||
iter.backward_char()
|
||||
ch = iter.get_char()
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
buffer = iter.get_buffer()
|
||||
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 5
|
||||
|
||||
def do_activate_proposal(self, proposal, iter_):
|
||||
buffer = iter_.get_buffer()
|
||||
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||
# to insure marker processes inserted text correctly.
|
||||
buffer.is_processing_completion = True
|
||||
return False
|
||||
|
||||
def do_get_activation(self):
|
||||
""" The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
# return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
results = self.response_cache.filter_with_context(context)
|
||||
proposals = []
|
||||
|
||||
for entry in results:
|
||||
proposals.append(
|
||||
self.response_cache.create_completion_item(
|
||||
entry["label"],
|
||||
entry["text"],
|
||||
entry["info"]
|
||||
)
|
||||
)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Python imports
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||
|
||||
|
||||
|
||||
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||
def __init__(self):
|
||||
super(ProviderResponseCache, self).__init__()
|
||||
|
||||
self.executor = ThreadPoolExecutor(max_workers = 1)
|
||||
self.matchers: dict = {}
|
||||
|
||||
|
||||
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
buffer = event.file.buffer
|
||||
self.executor.submit(self._handle_change, buffer)
|
||||
|
||||
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||
buffer = event.file.buffer
|
||||
self.executor.submit(self._handle_change, buffer)
|
||||
|
||||
def _handle_change(self, buffer):
|
||||
...
|
||||
|
||||
|
||||
def filter(self, word: str) -> list[dict]:
|
||||
return []
|
||||
|
||||
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||
proposals = [
|
||||
{
|
||||
"label": "LSP Class",
|
||||
"text": "LSP Code",
|
||||
"info": "A test LSP completion item..."
|
||||
}
|
||||
]
|
||||
|
||||
return proposals
|
||||
3
plugins/code/completers/snippets_completer/__init__.py
Normal file
3
plugins/code/completers/snippets_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/completers/snippets_completer/__main__.py
Normal file
3
plugins/code/completers/snippets_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
@@ -0,0 +1,3 @@
|
||||
from .parser import load, loads
|
||||
from .writer import dump, dumps
|
||||
from .speg import ParseError
|
||||
295
plugins/code/completers/snippets_completer/cson/parser.py
Normal file
295
plugins/code/completers/snippets_completer/cson/parser.py
Normal file
@@ -0,0 +1,295 @@
|
||||
from .speg import peg
|
||||
import re, sys
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
_chr = unichr
|
||||
else:
|
||||
_chr = chr
|
||||
|
||||
def load(fin):
|
||||
return loads(fin.read())
|
||||
|
||||
def loads(s):
|
||||
if isinstance(s, bytes):
|
||||
s = s.decode('utf-8')
|
||||
if s.startswith(u'\ufeff'):
|
||||
s = s[1:]
|
||||
return peg(s.replace('\r\n', '\n'), _p_root)
|
||||
|
||||
def _p_ws(p):
|
||||
p('[ \t]*')
|
||||
|
||||
def _p_nl(p):
|
||||
p(r'([ \t]*(?:#[^\n]*)?\r?\n)+')
|
||||
|
||||
def _p_ews(p):
|
||||
with p:
|
||||
p(_p_nl)
|
||||
p(_p_ws)
|
||||
|
||||
def _p_id(p):
|
||||
return p(r'[$a-zA-Z_][$0-9a-zA-Z_]*')
|
||||
|
||||
_escape_table = {
|
||||
'r': '\r',
|
||||
'n': '\n',
|
||||
't': '\t',
|
||||
'f': '\f',
|
||||
'b': '\b',
|
||||
}
|
||||
def _p_unescape(p):
|
||||
esc = p('\\\\(?:u[0-9a-fA-F]{4}|[^\n])')
|
||||
if esc[1] == 'u':
|
||||
return _chr(int(esc[2:], 16))
|
||||
return _escape_table.get(esc[1:], esc[1:])
|
||||
|
||||
_re_indent = re.compile(r'[ \t]*')
|
||||
def _p_block_str(p, c):
|
||||
p(r'{c}{c}{c}'.format(c=c))
|
||||
lines = [['']]
|
||||
with p:
|
||||
while True:
|
||||
s = p(r'(?:{c}(?!{c}{c})|[^{c}\\])*'.format(c=c))
|
||||
l = s.split('\n')
|
||||
lines[-1].append(l[0])
|
||||
lines.extend([x] for x in l[1:])
|
||||
if p(r'(?:\\\n[ \t]*)*'):
|
||||
continue
|
||||
p.commit()
|
||||
lines[-1].append(p(_p_unescape))
|
||||
p(r'{c}{c}{c}'.format(c=c))
|
||||
|
||||
lines = [''.join(l) for l in lines]
|
||||
strip_ws = len(lines) > 1
|
||||
if strip_ws and all(c in ' \t' for c in lines[-1]):
|
||||
lines.pop()
|
||||
|
||||
indent = None
|
||||
for line in lines[1:]:
|
||||
if not line:
|
||||
continue
|
||||
if indent is None:
|
||||
indent = _re_indent.match(line).group(0)
|
||||
continue
|
||||
for i, (c1, c2) in enumerate(zip(indent, line)):
|
||||
if c1 != c2:
|
||||
indent = indent[:i]
|
||||
break
|
||||
|
||||
ind_len = len(indent or '')
|
||||
if strip_ws and all(c in ' \t' for c in lines[0]):
|
||||
lines = [line[ind_len:] for line in lines[1:]]
|
||||
else:
|
||||
lines[1:] = [line[ind_len:] for line in lines[1:]]
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
_re_mstr_nl = re.compile(r'(?:[ \t]*\n)+[ \t]*')
|
||||
_re_mstr_trailing_nl = re.compile(_re_mstr_nl.pattern + r'\Z')
|
||||
def _p_multiline_str(p, c):
|
||||
p('{c}(?!{c}{c})(?:[ \t]*\n[ \t]*)?'.format(c=c))
|
||||
string_parts = []
|
||||
with p:
|
||||
while True:
|
||||
string_parts.append(p(r'[^{c}\\]*'.format(c=c)))
|
||||
if p(r'(?:\\\n[ \t]*)*'):
|
||||
string_parts.append('')
|
||||
continue
|
||||
p.commit()
|
||||
string_parts.append(p(_p_unescape))
|
||||
p(c)
|
||||
string_parts[-1] = _re_mstr_trailing_nl.sub('', string_parts[-1])
|
||||
string_parts[::2] = [_re_mstr_nl.sub(' ', part) for part in string_parts[::2]]
|
||||
return ''.join(string_parts)
|
||||
|
||||
def _p_string(p):
|
||||
with p:
|
||||
return p(_p_block_str, '"')
|
||||
with p:
|
||||
return p(_p_block_str, "'")
|
||||
with p:
|
||||
return p(_p_multiline_str, '"')
|
||||
return p(_p_multiline_str, "'")
|
||||
|
||||
def _p_array_value(p):
|
||||
with p:
|
||||
p(_p_nl)
|
||||
return p(_p_object)
|
||||
with p:
|
||||
p(_p_ws)
|
||||
return p(_p_line_object)
|
||||
p(_p_ews)
|
||||
return p(_p_simple_value)
|
||||
|
||||
def _p_key(p):
|
||||
with p:
|
||||
return p(_p_id)
|
||||
return p(_p_string)
|
||||
|
||||
def _p_flow_kv(p):
|
||||
k = p(_p_key)
|
||||
p(_p_ews)
|
||||
p(':')
|
||||
with p:
|
||||
p(_p_nl)
|
||||
return k, p(_p_object)
|
||||
with p:
|
||||
p(_p_ws)
|
||||
return k, p(_p_line_object)
|
||||
p(_p_ews)
|
||||
return k, p(_p_simple_value)
|
||||
|
||||
def _p_flow_obj_sep(p):
|
||||
with p:
|
||||
p(_p_ews)
|
||||
p(',')
|
||||
p(_p_ews)
|
||||
return
|
||||
|
||||
p(_p_nl)
|
||||
p(_p_ws)
|
||||
|
||||
def _p_simple_value(p):
|
||||
with p:
|
||||
p('null')
|
||||
return None
|
||||
|
||||
with p:
|
||||
p('false')
|
||||
return False
|
||||
with p:
|
||||
p('true')
|
||||
return True
|
||||
|
||||
with p:
|
||||
return int(p('0b[01]+')[2:], 2)
|
||||
with p:
|
||||
return int(p('0o[0-7]+')[2:], 8)
|
||||
with p:
|
||||
return int(p('0x[0-9a-fA-F]+')[2:], 16)
|
||||
with p:
|
||||
return float(p(r'-?(?:[1-9][0-9]*|0)?\.[0-9]+(?:[Ee][\+-]?[0-9]+)?|(?:[1-9][0-9]*|0)(?:\.[0-9]+)?[Ee][\+-]?[0-9]+'))
|
||||
with p:
|
||||
return int(p('-?[1-9][0-9]*|0'), 10)
|
||||
|
||||
with p:
|
||||
return p(_p_string)
|
||||
|
||||
with p:
|
||||
p(r'\[')
|
||||
r = []
|
||||
with p:
|
||||
p.set('I', '')
|
||||
r.append(p(_p_array_value))
|
||||
with p:
|
||||
while True:
|
||||
with p:
|
||||
p(_p_ews)
|
||||
p(',')
|
||||
rr = p(_p_array_value)
|
||||
if not p:
|
||||
p(_p_nl)
|
||||
with p:
|
||||
rr = p(_p_object)
|
||||
if not p:
|
||||
p(_p_ews)
|
||||
rr = p(_p_simple_value)
|
||||
r.append(rr)
|
||||
p.commit()
|
||||
with p:
|
||||
p(_p_ews)
|
||||
p(',')
|
||||
p(_p_ews)
|
||||
p(r'\]')
|
||||
return r
|
||||
|
||||
p(r'\{')
|
||||
|
||||
r = {}
|
||||
p(_p_ews)
|
||||
with p:
|
||||
p.set('I', '')
|
||||
k, v = p(_p_flow_kv)
|
||||
r[k] = v
|
||||
with p:
|
||||
while True:
|
||||
p(_p_flow_obj_sep)
|
||||
k, v = p(_p_flow_kv)
|
||||
r[k] = v
|
||||
p.commit()
|
||||
p(_p_ews)
|
||||
with p:
|
||||
p(',')
|
||||
p(_p_ews)
|
||||
p(r'\}')
|
||||
return r
|
||||
|
||||
def _p_line_kv(p):
|
||||
k = p(_p_key)
|
||||
p(_p_ws)
|
||||
p(':')
|
||||
p(_p_ws)
|
||||
with p:
|
||||
p(_p_nl)
|
||||
p(p.get('I'))
|
||||
return k, p(_p_indented_object)
|
||||
with p:
|
||||
return k, p(_p_line_object)
|
||||
with p:
|
||||
return k, p(_p_simple_value)
|
||||
p(_p_nl)
|
||||
p(p.get('I'))
|
||||
p('[ \t]')
|
||||
p(_p_ws)
|
||||
return k, p(_p_simple_value)
|
||||
|
||||
def _p_line_object(p):
|
||||
k, v = p(_p_line_kv)
|
||||
r = { k: v }
|
||||
with p:
|
||||
while True:
|
||||
p(_p_ws)
|
||||
p(',')
|
||||
p(_p_ws)
|
||||
k, v = p(_p_line_kv)
|
||||
r[k] = v # uniqueness
|
||||
p.commit()
|
||||
return r
|
||||
|
||||
def _p_object(p):
|
||||
p.set('I', p.get('I') + p('[ \t]*'))
|
||||
r = p(_p_line_object)
|
||||
with p:
|
||||
while True:
|
||||
p(_p_ws)
|
||||
with p:
|
||||
p(',')
|
||||
p(_p_nl)
|
||||
p(p.get('I'))
|
||||
rr = p(_p_line_object)
|
||||
r.update(rr) # unqueness
|
||||
p.commit()
|
||||
return r
|
||||
|
||||
def _p_indented_object(p):
|
||||
p.set('I', p.get('I') + p('[ \t]'))
|
||||
return p(_p_object)
|
||||
|
||||
def _p_root(p):
|
||||
with p:
|
||||
p(_p_nl)
|
||||
|
||||
with p:
|
||||
p.set('I', '')
|
||||
r = p(_p_object)
|
||||
p(_p_ws)
|
||||
with p:
|
||||
p(',')
|
||||
|
||||
if not p:
|
||||
p(_p_ws)
|
||||
r = p(_p_simple_value)
|
||||
|
||||
p(_p_ews)
|
||||
p(p.eof)
|
||||
return r
|
||||
@@ -0,0 +1 @@
|
||||
from .peg import peg, ParseError
|
||||
147
plugins/code/completers/snippets_completer/cson/speg/peg.py
Normal file
147
plugins/code/completers/snippets_completer/cson/speg/peg.py
Normal file
@@ -0,0 +1,147 @@
|
||||
import sys, re
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, msg, text, offset, line, col):
|
||||
self.msg = msg
|
||||
self.text = text
|
||||
self.offset = offset
|
||||
self.line = line
|
||||
self.col = col
|
||||
super(ParseError, self).__init__(msg, offset, line, col)
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
_basestr = basestring
|
||||
else:
|
||||
_basestr = str
|
||||
|
||||
def peg(s, r):
|
||||
p = _Peg(s)
|
||||
try:
|
||||
return p(r)
|
||||
except _UnexpectedError as e:
|
||||
offset = max(p._errors)
|
||||
err = p._errors[offset]
|
||||
raise ParseError(err.msg, s, offset, err.line, err.col)
|
||||
|
||||
class _UnexpectedError(RuntimeError):
|
||||
def __init__(self, state, expr):
|
||||
self.state = state
|
||||
self.expr = expr
|
||||
|
||||
class _PegState:
|
||||
def __init__(self, pos, line, col):
|
||||
self.pos = pos
|
||||
self.line = line
|
||||
self.col = col
|
||||
self.vars = {}
|
||||
self.commited = False
|
||||
|
||||
class _PegError:
|
||||
def __init__(self, msg, line, col):
|
||||
self.msg = msg
|
||||
self.line = line
|
||||
self.col = col
|
||||
|
||||
class _Peg:
|
||||
def __init__(self, s):
|
||||
self._s = s
|
||||
self._states = [_PegState(0, 1, 1)]
|
||||
self._errors = {}
|
||||
self._re_cache = {}
|
||||
|
||||
def __call__(self, r, *args, **kw):
|
||||
if isinstance(r, _basestr):
|
||||
compiled = self._re_cache.get(r)
|
||||
if not compiled:
|
||||
compiled = re.compile(r)
|
||||
self._re_cache[r] = compiled
|
||||
st = self._states[-1]
|
||||
m = compiled.match(self._s[st.pos:])
|
||||
if not m:
|
||||
self.error(expr=r, err=kw.get('err'))
|
||||
|
||||
ms = m.group(0)
|
||||
st.pos += len(ms)
|
||||
nl_pos = ms.rfind('\n')
|
||||
if nl_pos < 0:
|
||||
st.col += len(ms)
|
||||
else:
|
||||
st.col = len(ms) - nl_pos
|
||||
st.line += ms[:nl_pos].count('\n') + 1
|
||||
return ms
|
||||
else:
|
||||
kw.pop('err', None)
|
||||
return r(self, *args, **kw)
|
||||
|
||||
def __repr__(self):
|
||||
pos = self._states[-1].pos
|
||||
vars = {}
|
||||
for st in self._states:
|
||||
vars.update(st.vars)
|
||||
return '_Peg(%r, %r)' % (self._s[:pos] + '*' + self._s[pos:], vars)
|
||||
|
||||
@staticmethod
|
||||
def eof(p):
|
||||
if p._states[-1].pos != len(p._s):
|
||||
p.error()
|
||||
|
||||
def error(self, err=None, expr=None):
|
||||
st = self._states[-1]
|
||||
if err is None:
|
||||
err = 'expected {!r}, found {!r}'.format(expr, self._s[st.pos:st.pos+4])
|
||||
self._errors[st.pos] = _PegError(err, st.line, st.col)
|
||||
raise _UnexpectedError(st, expr)
|
||||
|
||||
def get(self, key, default=None):
|
||||
for state in self._states[::-1]:
|
||||
if key in state.vars:
|
||||
return state.vars[key][0]
|
||||
return default
|
||||
|
||||
def set(self, key, value):
|
||||
self._states[-1].vars[key] = value, False
|
||||
|
||||
def set_global(self, key, value):
|
||||
self._states[-1].vars[key] = value, True
|
||||
|
||||
def opt(self, *args, **kw):
|
||||
with self:
|
||||
return self(*args, **kw)
|
||||
|
||||
def not_(self, s, *args, **kw):
|
||||
with self:
|
||||
self(s)
|
||||
self.error()
|
||||
|
||||
def __enter__(self):
|
||||
self._states[-1].committed = False
|
||||
self._states.append(_PegState(self._states[-1].pos, self._states[-1].line, self._states[-1].col))
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if type is None:
|
||||
self.commit()
|
||||
self._states.pop()
|
||||
return type == _UnexpectedError
|
||||
|
||||
def commit(self):
|
||||
cur = self._states[-1]
|
||||
prev = self._states[-2]
|
||||
|
||||
for key in cur.vars:
|
||||
val, g = cur.vars[key]
|
||||
if not g:
|
||||
continue
|
||||
if key in prev.vars:
|
||||
prev.vars[key] = val, prev.vars[key][1]
|
||||
else:
|
||||
prev.vars[key] = val, True
|
||||
|
||||
prev.pos = cur.pos
|
||||
prev.line = cur.line
|
||||
prev.col = cur.col
|
||||
prev.committed = True
|
||||
|
||||
def __nonzero__(self):
|
||||
return self._states[-1].committed
|
||||
|
||||
__bool__ = __nonzero__
|
||||
191
plugins/code/completers/snippets_completer/cson/writer.py
Normal file
191
plugins/code/completers/snippets_completer/cson/writer.py
Normal file
@@ -0,0 +1,191 @@
|
||||
import re, json, sys
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
def _is_num(o):
|
||||
return isinstance(o, int) or isinstance(o, long) or isinstance(o, float)
|
||||
def _stringify(o):
|
||||
if isinstance(o, str):
|
||||
return unicode(o)
|
||||
if isinstance(o, unicode):
|
||||
return o
|
||||
return None
|
||||
else:
|
||||
def _is_num(o):
|
||||
return isinstance(o, int) or isinstance(o, float)
|
||||
def _stringify(o):
|
||||
if isinstance(o, bytes):
|
||||
return o.decode()
|
||||
if isinstance(o, str):
|
||||
return o
|
||||
return None
|
||||
|
||||
_id_re = re.compile(r'[$a-zA-Z_][$0-9a-zA-Z_]*\Z')
|
||||
|
||||
class CSONEncoder:
|
||||
def __init__(self, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False,
|
||||
indent=None, default=None):
|
||||
self._skipkeys = skipkeys
|
||||
self._ensure_ascii = ensure_ascii
|
||||
self._allow_nan = allow_nan
|
||||
self._sort_keys = sort_keys
|
||||
self._indent = ' ' * (indent or 4)
|
||||
self._default = default
|
||||
if check_circular:
|
||||
self._obj_stack = set()
|
||||
else:
|
||||
self._obj_stack = None
|
||||
|
||||
def _format_simple_val(self, o):
|
||||
if o is None:
|
||||
return 'null'
|
||||
if isinstance(o, bool):
|
||||
return 'true' if o else 'false'
|
||||
if _is_num(o):
|
||||
return str(o)
|
||||
s = _stringify(o)
|
||||
if s is not None:
|
||||
return self._escape_string(s)
|
||||
return None
|
||||
|
||||
def _escape_string(self, s):
|
||||
r = json.dumps(s, ensure_ascii=self._ensure_ascii)
|
||||
return u"'{}'".format(r[1:-1].replace("'", r"\'"))
|
||||
|
||||
def _escape_key(self, s):
|
||||
if s is None or isinstance(s, bool) or _is_num(s):
|
||||
s = str(s)
|
||||
s = _stringify(s)
|
||||
if s is None:
|
||||
if self._skipkeys:
|
||||
return None
|
||||
raise TypeError('keys must be a string')
|
||||
if not _id_re.match(s):
|
||||
return self._escape_string(s)
|
||||
return s
|
||||
|
||||
def _push_obj(self, o):
|
||||
if self._obj_stack is not None:
|
||||
if id(o) in self._obj_stack:
|
||||
raise ValueError('Circular reference detected')
|
||||
self._obj_stack.add(id(o))
|
||||
|
||||
def _pop_obj(self, o):
|
||||
if self._obj_stack is not None:
|
||||
self._obj_stack.remove(id(o))
|
||||
|
||||
def _encode(self, o, obj_val=False, indent='', force_flow=False):
|
||||
if isinstance(o, list):
|
||||
if not o:
|
||||
if obj_val:
|
||||
yield ' []\n'
|
||||
else:
|
||||
yield indent
|
||||
yield '[]\n'
|
||||
else:
|
||||
if obj_val:
|
||||
yield ' [\n'
|
||||
else:
|
||||
yield indent
|
||||
yield '[\n'
|
||||
indent = indent + self._indent
|
||||
self._push_obj(o)
|
||||
for v in o:
|
||||
for chunk in self._encode(v, obj_val=False, indent=indent, force_flow=True):
|
||||
yield chunk
|
||||
self._pop_obj(o)
|
||||
yield indent[:-len(self._indent)]
|
||||
yield ']\n'
|
||||
elif isinstance(o, dict):
|
||||
items = [(self._escape_key(k), v) for k, v in o.items()]
|
||||
if self._skipkeys:
|
||||
items = [(k, v) for k, v in items if k is not None]
|
||||
if self._sort_keys:
|
||||
items.sort()
|
||||
if force_flow or not items:
|
||||
if not items:
|
||||
if obj_val:
|
||||
yield ' {}\n'
|
||||
else:
|
||||
yield indent
|
||||
yield '{}\n'
|
||||
else:
|
||||
if obj_val:
|
||||
yield ' {\n'
|
||||
else:
|
||||
yield indent
|
||||
yield '{\n'
|
||||
indent = indent + self._indent
|
||||
self._push_obj(o)
|
||||
for k, v in items:
|
||||
yield indent
|
||||
yield k
|
||||
yield ':'
|
||||
for chunk in self._encode(v, obj_val=True, indent=indent + self._indent, force_flow=False):
|
||||
yield chunk
|
||||
self._pop_obj(o)
|
||||
yield indent[:-len(self._indent)]
|
||||
yield '}\n'
|
||||
else:
|
||||
if obj_val:
|
||||
yield '\n'
|
||||
self._push_obj(o)
|
||||
for k, v in items:
|
||||
yield indent
|
||||
yield k
|
||||
yield ':'
|
||||
for chunk in self._encode(v, obj_val=True, indent=indent + self._indent, force_flow=False):
|
||||
yield chunk
|
||||
self._pop_obj(o)
|
||||
else:
|
||||
v = self._format_simple_val(o)
|
||||
if v is None:
|
||||
self._push_obj(o)
|
||||
v = self.default(o)
|
||||
for chunk in self._encode(v, obj_val=obj_val, indent=indent, force_flow=force_flow):
|
||||
yield chunk
|
||||
self._pop_obj(o)
|
||||
else:
|
||||
if obj_val:
|
||||
yield ' '
|
||||
else:
|
||||
yield indent
|
||||
yield v
|
||||
yield '\n'
|
||||
|
||||
def iterencode(self, o):
|
||||
return self._encode(o)
|
||||
|
||||
def encode(self, o):
|
||||
return ''.join(self.iterencode(o))
|
||||
|
||||
def default(self, o):
|
||||
if self._default is None:
|
||||
raise TypeError('Cannot serialize an object of type {}'.format(type(o).__name__))
|
||||
return self._default(o)
|
||||
|
||||
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None,
|
||||
indent=None, default=None, sort_keys=False, **kw):
|
||||
if indent is None and cls is None:
|
||||
return json.dump(obj, fp, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
|
||||
allow_nan=allow_nan, default=default, sort_keys=sort_keys, separators=(',', ':'))
|
||||
|
||||
if cls is None:
|
||||
cls = CSONEncoder
|
||||
encoder = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
|
||||
allow_nan=allow_nan, sort_keys=sort_keys, indent=indent, default=default, **kw)
|
||||
|
||||
for chunk in encoder.iterencode(obj):
|
||||
fp.write(chunk)
|
||||
|
||||
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None,
|
||||
default=None, sort_keys=False, **kw):
|
||||
if indent is None and cls is None:
|
||||
return json.dumps(obj, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
|
||||
allow_nan=allow_nan, default=default, sort_keys=sort_keys, separators=(',', ':'))
|
||||
|
||||
if cls is None:
|
||||
cls = CSONEncoder
|
||||
encoder = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
|
||||
allow_nan=allow_nan, sort_keys=sort_keys, indent=indent, default=default, **kw)
|
||||
|
||||
return encoder.encode(obj)
|
||||
7
plugins/code/completers/snippets_completer/manifest.json
Normal file
7
plugins/code/completers/snippets_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Snippets Completer",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
39
plugins/code/completers/snippets_completer/plugin.py
Normal file
39
plugins/code/completers/snippets_completer/plugin.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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 plugins.plugin_types import PluginCode
|
||||
|
||||
from .provider import Provider
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
self.provider: Provider = None
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
self.provider = Provider()
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"register_provider",
|
||||
provider_name = "Snippets Completer",
|
||||
provider = self.provider,
|
||||
language_ids = []
|
||||
)
|
||||
self.emit_to("completion", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
68
plugins/code/completers/snippets_completer/provider.py
Normal file
68
plugins/code/completers/snippets_completer/provider.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# Python imports
|
||||
import re
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
|
||||
|
||||
|
||||
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This is a Snippits Completion Provider.
|
||||
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||
"""
|
||||
__gtype_name__ = 'SnippetsCompletionProvider'
|
||||
|
||||
def __init__(self):
|
||||
super(Provider, self).__init__()
|
||||
|
||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||
|
||||
|
||||
def do_get_name(self):
|
||||
return 'Snippits Completion'
|
||||
|
||||
def do_match(self, context):
|
||||
word = self.response_cache.get_word(context)
|
||||
if not word or len(word) < 2: return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 2
|
||||
|
||||
def do_activate_proposal(self, proposal, iter_):
|
||||
buffer = iter_.get_buffer()
|
||||
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||
# to insure marker processes inserted text correctly.
|
||||
buffer.is_processing_completion = True
|
||||
return False
|
||||
|
||||
def do_get_activation(self):
|
||||
""" The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
# return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
word = self.response_cache.get_word(context)
|
||||
results = self.response_cache.filter(word)
|
||||
proposals = []
|
||||
|
||||
for entry in results:
|
||||
proposals.append(
|
||||
self.response_cache.create_completion_item(
|
||||
entry["label"],
|
||||
entry["text"],
|
||||
entry["info"]
|
||||
)
|
||||
)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
@@ -0,0 +1,68 @@
|
||||
# Python imports
|
||||
from os import path
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||
|
||||
from . import cson
|
||||
|
||||
|
||||
|
||||
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||
def __init__(self):
|
||||
super(ProviderResponseCache, self).__init__()
|
||||
|
||||
self.matchers: dict = {}
|
||||
|
||||
self.load_snippets()
|
||||
|
||||
|
||||
def load_snippets(self):
|
||||
fpath = path.join(path.dirname(path.realpath(__file__)), "snippets.cson")
|
||||
with open(fpath, 'rb') as f:
|
||||
self.snippets = cson.load(f)
|
||||
for group in self.snippets:
|
||||
self.snippets[group]
|
||||
for entry in self.snippets[group]:
|
||||
data = self.snippets[group][entry]
|
||||
self.matchers[ data["prefix"] ] = {
|
||||
"label": entry,
|
||||
"text": data["body"],
|
||||
"info": GLib.markup_escape_text( data["body"] )
|
||||
}
|
||||
|
||||
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
...
|
||||
|
||||
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||
...
|
||||
|
||||
def filter(self, word: str) -> list[dict]:
|
||||
response: list[dict] = []
|
||||
|
||||
for entry in self.matchers:
|
||||
if not word in entry: continue
|
||||
data = self.matchers[entry]
|
||||
response.append(data)
|
||||
|
||||
return response
|
||||
|
||||
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||
response: list[dict] = []
|
||||
|
||||
return response
|
||||
614
plugins/code/completers/snippets_completer/snippets.cson
Normal file
614
plugins/code/completers/snippets_completer/snippets.cson
Normal file
@@ -0,0 +1,614 @@
|
||||
# Your snippets
|
||||
#
|
||||
# Atom snippets allow you to enter a simple prefix in the editor and hit tab to
|
||||
# expand the prefix into a larger code block with templated values.
|
||||
#
|
||||
# You can create a new snippet in this file by typing "snip" and then hitting
|
||||
# tab.
|
||||
#
|
||||
# An example CoffeeScript snippet to expand log to console.log:
|
||||
#
|
||||
# '.source.coffee':
|
||||
# 'Console log':
|
||||
# 'prefix': 'log'
|
||||
# 'body': 'console.log $1'
|
||||
#
|
||||
# Each scope (e.g. '.source.coffee' above) can only be declared once.
|
||||
#
|
||||
# This file uses CoffeeScript Object Notation (CSON).
|
||||
# If you are unfamiliar with CSON, you can read more about it in the
|
||||
# Atom Flight Manual:
|
||||
# http://flight-manual.atom.io/using-atom/sections/basic-customization/#_cson
|
||||
|
||||
|
||||
### HTML SNIPPETS ###
|
||||
'.text.html.basic':
|
||||
|
||||
'HTML Template':
|
||||
'prefix': 'html'
|
||||
'body': """<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<link rel="shortcut icon" href="fave_icon.png">
|
||||
<link rel="stylesheet" href="resources/css/base.css">
|
||||
<link rel="stylesheet" href="resources/css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="resources/js/.js" charset="utf-8"></script>
|
||||
<script src="resources/js/.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
'Canvas Tag':
|
||||
'prefix': 'canvas'
|
||||
'body': """<canvas id="canvas" width="800" height="600" style="border:1px solid #c3c3c3;"></canvas>"""
|
||||
|
||||
'Img Tag':
|
||||
'prefix': 'img'
|
||||
'body': """<img class="" src="" alt="" />"""
|
||||
|
||||
'Br Tag':
|
||||
'prefix': 'br'
|
||||
'body': """<br/>"""
|
||||
|
||||
'Hr Tag':
|
||||
'prefix': 'hr'
|
||||
'body': """<hr/>"""
|
||||
|
||||
'Server Side Events':
|
||||
'prefix': 'sse'
|
||||
'body': """// SSE events if supported
|
||||
if(typeof(EventSource) !== "undefined") {
|
||||
let source = new EventSource("resources/php/sse.php");
|
||||
source.onmessage = (event) => {
|
||||
if (event.data === "<yourDataStringToLookFor>") {
|
||||
// code here
|
||||
}
|
||||
};
|
||||
} else {
|
||||
console.log("SSE Not Supported In Browser...");
|
||||
}
|
||||
"""
|
||||
|
||||
'AJAX Template Function':
|
||||
'prefix': 'ajax template'
|
||||
'body': """const doAjax = async (actionPath, data) => {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
if (this.responseText != null) { // this.responseXML if getting XML fata
|
||||
handleReturnData(JSON.parse(this.responseText));
|
||||
} else {
|
||||
console.log("No content returned. Check the file path.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhttp.open("POST", actionPath, true);
|
||||
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
// Force return to be JSON NOTE: Use application/xml to force XML
|
||||
xhttp.overrideMimeType('application/json');
|
||||
xhttp.send(data);
|
||||
}
|
||||
"""
|
||||
|
||||
'CSS Message Colors':
|
||||
'prefix': 'css colors'
|
||||
'body': """.error { color: rgb(255, 0, 0); }
|
||||
.warning { color: rgb(255, 168, 0); }
|
||||
.success { color: rgb(136, 204, 39); }
|
||||
"""
|
||||
|
||||
|
||||
### JS SNIPPETS ###
|
||||
'.source.js':
|
||||
|
||||
'Server Side Events':
|
||||
'prefix': 'sse'
|
||||
'body': """// SSE events if supported
|
||||
if(typeof(EventSource) !== "undefined") {
|
||||
let source = new EventSource("resources/php/sse.php");
|
||||
source.onmessage = (event) => {
|
||||
if (event.data === "<yourDataStringToLookFor>") {
|
||||
// code here
|
||||
}
|
||||
};
|
||||
} else {
|
||||
console.log("SSE Not Supported In Browser...");
|
||||
}
|
||||
"""
|
||||
|
||||
'AJAX Template Function':
|
||||
'prefix': 'ajax template'
|
||||
'body': """const doAjax = async (actionPath, data) => {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
if (this.responseText != null) { // this.responseXML if getting XML fata
|
||||
handleReturnData(JSON.parse(this.responseText));
|
||||
} else {
|
||||
console.log("No content returned. Check the file path.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhttp.open("POST", actionPath, true);
|
||||
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
// Force return to be JSON NOTE: Use application/xml to force XML
|
||||
xhttp.overrideMimeType('application/json');
|
||||
xhttp.send(data);
|
||||
}
|
||||
"""
|
||||
|
||||
'SE6 Function':
|
||||
'prefix': 'function se6'
|
||||
'body': """const funcName = (arg = "") => {
|
||||
|
||||
}
|
||||
"""
|
||||
|
||||
### CSS SNIPPETS ###
|
||||
'.source.css':
|
||||
|
||||
'CSS Message Colors':
|
||||
'prefix': 'css colors'
|
||||
'body': """.error { color: rgb(255, 0, 0); }
|
||||
.warning { color: rgb(255, 168, 0); }
|
||||
.success { color: rgb(136, 204, 39); }
|
||||
"""
|
||||
|
||||
### PHP SNIPPETS ###
|
||||
'.text.html.php':
|
||||
|
||||
'SSE PHP':
|
||||
'prefix': 'sse php'
|
||||
'body': """<?php
|
||||
// Start the session
|
||||
session_start();
|
||||
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
|
||||
echo "data:dataToReturn\\\\n\\\\n";
|
||||
|
||||
flush();
|
||||
?>
|
||||
"""
|
||||
|
||||
'PHP Template':
|
||||
'prefix': 'php'
|
||||
'body': """<?php
|
||||
// Start the session
|
||||
session_start();
|
||||
|
||||
|
||||
// Determin action
|
||||
chdir("../../"); // Note: If in resources/php/
|
||||
if (isset($_POST['yourPostID'])) {
|
||||
// code here
|
||||
} else {
|
||||
$message = "Server: [Error] --> Illegal Access Method!";
|
||||
serverMessage("error", $message);
|
||||
}
|
||||
?>
|
||||
"""
|
||||
'HTML Template':
|
||||
'prefix': 'html'
|
||||
'body': """<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<link rel="shortcut icon" href="fave_icon.png">
|
||||
<link rel="stylesheet" href="resources/css/base.css">
|
||||
<link rel="stylesheet" href="resources/css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="resources/js/.js" charset="utf-8"></script>
|
||||
<script src="resources/js/.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
### BASH SNIPPETS ###
|
||||
'.source.shell':
|
||||
|
||||
'Bash or Shell Template':
|
||||
'prefix': 'bash template'
|
||||
'body': """#!/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 main() {
|
||||
cd "$(dirname "$0")"
|
||||
echo "Working Dir: " $(pwd)
|
||||
|
||||
file="$1"
|
||||
if [ -z "${file}" ]; then
|
||||
echo "ERROR: No file argument supplied..."
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ -f "${file}" ]]; then
|
||||
echo "SUCCESS: The path and file exists!"
|
||||
else
|
||||
echo "ERROR: The path or file '${file}' does NOT exist..."
|
||||
fi
|
||||
}
|
||||
main "$@";
|
||||
"""
|
||||
|
||||
|
||||
'Bash or Shell Config':
|
||||
'prefix': 'bash config'
|
||||
'body': """#!/bin/bash
|
||||
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias echo="echo -e"
|
||||
"""
|
||||
|
||||
|
||||
### PYTHON SNIPPETS ###
|
||||
'.source.python':
|
||||
|
||||
'Glade __main__ Class Template':
|
||||
'prefix': 'glade __main__ class'
|
||||
'body': """#!/usr/bin/python3
|
||||
|
||||
|
||||
# Python imports
|
||||
import argparse
|
||||
import faulthandler
|
||||
import traceback
|
||||
import signal
|
||||
from setproctitle import setproctitle
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from app import Application
|
||||
|
||||
|
||||
def run():
|
||||
try:
|
||||
setproctitle('<replace this>')
|
||||
faulthandler.enable() # For better debug info
|
||||
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Add long and short arguments
|
||||
parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.")
|
||||
parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.")
|
||||
parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.")
|
||||
|
||||
parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.")
|
||||
parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.")
|
||||
|
||||
# Read arguments (If any...)
|
||||
args, unknownargs = parser.parse_known_args()
|
||||
|
||||
main = Application(args, unknownargs)
|
||||
Gtk.main()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
quit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
''' Set process title, get arguments, and create GTK main thread. '''
|
||||
run()
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
'Glade __main__ Testing Template':
|
||||
'prefix': 'glade testing class'
|
||||
'body': """#!/usr/bin/python3
|
||||
|
||||
|
||||
# Python imports
|
||||
import traceback
|
||||
import faulthandler
|
||||
import signal
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
app_name = "Gtk Quick Test"
|
||||
|
||||
|
||||
class Application(Gtk.ApplicationWindow):
|
||||
def __init__(self):
|
||||
super(Application, self).__init__()
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
self.add(Gtk.Box())
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_default_size(1670, 830)
|
||||
self.set_title(f"{app_name}")
|
||||
# self.set_icon_from_file( settings.get_window_icon() )
|
||||
self.set_gravity(5) # 5 = CENTER
|
||||
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("delete-event", Gtk.main_quit)
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
|
||||
|
||||
|
||||
def run():
|
||||
try:
|
||||
faulthandler.enable() # For better debug info
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit)
|
||||
|
||||
main = Application()
|
||||
Gtk.main()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
quit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
''' Set process title, get arguments, and create GTK main thread. '''
|
||||
run()
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
'Glade _init_ Class Template':
|
||||
'prefix': 'glade __init__ class'
|
||||
'body': """# Python imports
|
||||
import inspect
|
||||
|
||||
|
||||
# Lib imports
|
||||
|
||||
|
||||
# Application imports
|
||||
from utils import Settings
|
||||
from signal_classes import CrossClassSignals
|
||||
|
||||
|
||||
class Main:
|
||||
def __init__(self, args):
|
||||
settings = Settings()
|
||||
builder = settings.returnBuilder()
|
||||
|
||||
# Gets the methods from the classes and sets to handler.
|
||||
# Then, builder connects to any signals it needs.
|
||||
classes = [CrossClassSignals(settings)]
|
||||
|
||||
handlers = {}
|
||||
for c in classes:
|
||||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
|
||||
builder.connect_signals(handlers)
|
||||
window = settings.createWindow()
|
||||
window.show()
|
||||
|
||||
"""
|
||||
|
||||
'Class Method':
|
||||
'prefix': 'def1'
|
||||
'body': """
|
||||
def fname(self):
|
||||
...
|
||||
"""
|
||||
|
||||
'Gtk Class Method':
|
||||
'prefix': 'def2'
|
||||
'body': """
|
||||
def fname(self, widget, eve):
|
||||
...
|
||||
"""
|
||||
|
||||
|
||||
'Python Glade Settings Template':
|
||||
'prefix': 'glade settings class'
|
||||
'body': """# Python imports
|
||||
import os
|
||||
|
||||
# Lib imports
|
||||
import gi, cairo
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
class Settings:
|
||||
def __init__(self):
|
||||
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/"
|
||||
self.builder = Gtk.Builder()
|
||||
self.builder.add_from_file(self.SCRIPT_PTH + "../resources/Main_Window.glade")
|
||||
|
||||
# 'Filters'
|
||||
self.office = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm',
|
||||
'.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf')
|
||||
self.vids = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv',
|
||||
'.mpeg', '.mp4', '.webm')
|
||||
self.txt = ('.txt', '.text', '.sh', '.cfg', '.conf')
|
||||
self.music = ('.psf', '.mp3', '.ogg' , '.flac')
|
||||
self.images = ('.png', '.jpg', '.jpeg', '.gif')
|
||||
self.pdf = ('.pdf')
|
||||
|
||||
|
||||
def createWindow(self):
|
||||
# Get window and connect signals
|
||||
window = self.builder.get_object("Main_Window")
|
||||
window.connect("delete-event", gtk.main_quit)
|
||||
self.setWindowData(window, False)
|
||||
return window
|
||||
|
||||
def setWindowData(self, window, paintable):
|
||||
screen = window.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
|
||||
if visual != None and screen.is_composited():
|
||||
window.set_visual(visual)
|
||||
|
||||
# bind css file
|
||||
cssProvider = gtk.CssProvider()
|
||||
cssProvider.load_from_path(self.SCRIPT_PTH + '../resources/stylesheet.css')
|
||||
screen = Gdk.Screen.get_default()
|
||||
styleContext = Gtk.StyleContext()
|
||||
styleContext.add_provider_for_screen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
window.set_app_paintable(paintable)
|
||||
if paintable:
|
||||
window.connect("draw", self.area_draw)
|
||||
|
||||
def getMonitorData(self):
|
||||
screen = self.builder.get_object("Main_Window").get_screen()
|
||||
monitors = []
|
||||
for m in range(screen.get_n_monitors()):
|
||||
monitors.append(screen.get_monitor_geometry(m))
|
||||
|
||||
for monitor in monitors:
|
||||
print(str(monitor.width) + "x" + str(monitor.height) + "+" + str(monitor.x) + "+" + str(monitor.y))
|
||||
|
||||
return monitors
|
||||
|
||||
def area_draw(self, widget, cr):
|
||||
cr.set_source_rgba(0, 0, 0, 0.54)
|
||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
cr.set_operator(cairo.OPERATOR_OVER)
|
||||
|
||||
|
||||
def returnBuilder(self): return self.builder
|
||||
|
||||
# Filter returns
|
||||
def returnOfficeFilter(self): return self.office
|
||||
def returnVidsFilter(self): return self.vids
|
||||
def returnTextFilter(self): return self.txt
|
||||
def returnMusicFilter(self): return self.music
|
||||
def returnImagesFilter(self): return self.images
|
||||
def returnPdfFilter(self): return self.pdf
|
||||
|
||||
"""
|
||||
|
||||
'Python Glade CrossClassSignals Template':
|
||||
'prefix': 'glade crossClassSignals class'
|
||||
'body': """# Python imports
|
||||
import threading
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
def threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class CrossClassSignals:
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
self.builder = self.settings.returnBuilder()
|
||||
|
||||
|
||||
def getClipboardData(self):
|
||||
proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE)
|
||||
retcode = proc.wait()
|
||||
data = proc.stdout.read()
|
||||
return data.decode("utf-8").strip()
|
||||
|
||||
def setClipboardData(self, data):
|
||||
proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
|
||||
proc.stdin.write(data)
|
||||
proc.stdin.close()
|
||||
retcode = proc.wait()
|
||||
|
||||
"""
|
||||
|
||||
|
||||
'Python Glade Generic Template':
|
||||
'prefix': 'glade generic class'
|
||||
'body': """# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
class GenericClass:
|
||||
def __init__(self):
|
||||
super(GenericClass, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
...
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
"""
|
||||
3
plugins/code/completers/words_completer/__init__.py
Normal file
3
plugins/code/completers/words_completer/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/completers/words_completer/__main__.py
Normal file
3
plugins/code/completers/words_completer/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
68
plugins/code/completers/words_completer/default_provider.py
Normal file
68
plugins/code/completers/words_completer/default_provider.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# Python imports
|
||||
import re
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
|
||||
|
||||
|
||||
class Provider(GtkSource.CompletionWords):
|
||||
"""
|
||||
This is a Words Completion Provider.
|
||||
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||
"""
|
||||
__gtype_name__ = 'WordsCompletionProvider'
|
||||
|
||||
def __init__(self):
|
||||
super(Provider, self).__init__()
|
||||
|
||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||
|
||||
|
||||
def do_get_name(self):
|
||||
return 'Words Completion'
|
||||
|
||||
def do_match(self, context):
|
||||
# Note: If provider is in interactive activation then need to check
|
||||
# view focus as otherwise non focus views start trying to grab it.
|
||||
completion = context.get_property("completion")
|
||||
if not completion.get_view().has_focus(): return
|
||||
|
||||
word = self.response_cache.get_word(context)
|
||||
if not word or len(word) < 2: return False
|
||||
|
||||
iter = self.response_cache.get_iter_correctly(context)
|
||||
iter.backward_char()
|
||||
ch = iter.get_char()
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 0
|
||||
|
||||
def do_activate_proposal(self, proposal, iter_):
|
||||
buffer = iter_.get_buffer()
|
||||
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||
# to insure marker processes inserted text correctly.
|
||||
buffer.is_processing_completion = True
|
||||
return False
|
||||
|
||||
def do_get_activation(self):
|
||||
""" The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
# return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
return GtkSource.CompletionActivation.INTERACTIVE
|
||||
@@ -0,0 +1,29 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||
|
||||
|
||||
|
||||
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||
def __init__(self):
|
||||
super(ProviderResponseCache, self).__init__()
|
||||
|
||||
self.matchers: dict = {}
|
||||
|
||||
|
||||
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
...
|
||||
|
||||
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||
...
|
||||
7
plugins/code/completers/words_completer/manifest.json
Normal file
7
plugins/code/completers/words_completer/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Words Completer",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
39
plugins/code/completers/words_completer/plugin.py
Normal file
39
plugins/code/completers/words_completer/plugin.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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 plugins.plugin_types import PluginCode
|
||||
|
||||
from .provider import Provider
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
self.provider: Provider = None
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
self.provider = Provider()
|
||||
|
||||
event = Event_Factory.create_event(
|
||||
"register_provider",
|
||||
provider_name = "Words Completer",
|
||||
provider = self.provider,
|
||||
language_ids = []
|
||||
)
|
||||
self.emit_to("completion", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
86
plugins/code/completers/words_completer/provider.py
Normal file
86
plugins/code/completers/words_completer/provider.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# Python imports
|
||||
import re
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
|
||||
|
||||
|
||||
class Provider(GObject.GObject, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This is a Words Completion Provider.
|
||||
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||
"""
|
||||
__gtype_name__ = 'WordsCompletionProvider'
|
||||
|
||||
def __init__(self):
|
||||
super(Provider, self).__init__()
|
||||
|
||||
self.response_cache: ProviderResponseCache = ProviderResponseCache()
|
||||
|
||||
|
||||
def do_get_name(self):
|
||||
return 'Words Completion'
|
||||
|
||||
def do_match(self, context):
|
||||
# Note: If provider is in interactive activation then need to check
|
||||
# view focus as otherwise non focus views start trying to grab it.
|
||||
completion = context.get_property("completion")
|
||||
if not completion.get_view().has_focus(): return
|
||||
|
||||
word = self.response_cache.get_word(context)
|
||||
if not word or len(word) < 2: return False
|
||||
|
||||
iter = self.response_cache.get_iter_correctly(context)
|
||||
iter.backward_char()
|
||||
ch = iter.get_char()
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 0
|
||||
|
||||
def do_activate_proposal(self, proposal, iter_):
|
||||
buffer = iter_.get_buffer()
|
||||
# Note: Flag mostly intended for SourceViewsMultiInsertState
|
||||
# to insure marker processes inserted text correctly.
|
||||
buffer.is_processing_completion = True
|
||||
return False
|
||||
|
||||
def do_get_activation(self):
|
||||
""" The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
# return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
word = self.response_cache.get_word(context)
|
||||
results = self.response_cache.filter_with_context(context)
|
||||
# results = self.response_cache.filter(word)
|
||||
|
||||
# if not results:
|
||||
# results = self.response_cache.filter_with_context(context)
|
||||
|
||||
proposals = []
|
||||
for entry in results:
|
||||
proposals.append(
|
||||
self.response_cache.create_completion_item(
|
||||
entry["label"],
|
||||
entry["text"],
|
||||
entry["info"]
|
||||
)
|
||||
)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
@@ -0,0 +1,136 @@
|
||||
# Python imports
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Code_Event_Types
|
||||
|
||||
from core.widgets.code.completion_providers.provider_response_cache_base import ProviderResponseCacheBase
|
||||
|
||||
|
||||
|
||||
class ProviderResponseCache(ProviderResponseCacheBase):
|
||||
def __init__(self):
|
||||
super(ProviderResponseCache, self).__init__()
|
||||
|
||||
self.matchers: dict = {}
|
||||
self._temp_timeout_id: int = None
|
||||
|
||||
|
||||
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
buffer = event.file.buffer
|
||||
with ThreadPoolExecutor(max_workers = 1) as executor:
|
||||
executor.submit(self._handle_change, buffer)
|
||||
|
||||
def process_file_close(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
self.matchers[event.file.buffer] = set()
|
||||
del self.matchers[event.file.buffer]
|
||||
|
||||
def process_file_save(self, event: Code_Event_Types.SavedFileEvent):
|
||||
...
|
||||
|
||||
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
|
||||
buffer = event.file.buffer
|
||||
self._clear_temp_delay()
|
||||
self._set_temp_delay(buffer)
|
||||
|
||||
def _clear_temp_delay(self):
|
||||
if self._temp_timeout_id:
|
||||
GLib.source_remove(self._temp_timeout_id)
|
||||
|
||||
def _set_temp_delay(self, buffer):
|
||||
def run_refresh_update(buffer):
|
||||
with ThreadPoolExecutor(max_workers = 1) as executor:
|
||||
executor.submit(self._handle_change, buffer)
|
||||
|
||||
return False
|
||||
|
||||
self._temp_timeout_id = GLib.timeout_add(1500, run_refresh_update, buffer)
|
||||
|
||||
def _handle_change(self, buffer):
|
||||
start_itr = buffer.get_start_iter()
|
||||
end_itr = buffer.get_end_iter()
|
||||
data = buffer.get_text(start_itr, end_itr, False)
|
||||
|
||||
if not data:
|
||||
GLib.idle_add(self.load_empty_set, buffer)
|
||||
return
|
||||
|
||||
if not buffer in self.matchers:
|
||||
GLib.idle_add(self.load_as_new_set, buffer, data)
|
||||
return
|
||||
|
||||
new_words = self.get_all_words(data)
|
||||
GLib.idle_add(self.load_into_set, buffer, new_words)
|
||||
|
||||
def filter(self, word: str) -> list[dict]:
|
||||
response: list[dict] = []
|
||||
|
||||
for entry in self.matchers:
|
||||
if not word in entry: continue
|
||||
data = self.matchers[entry]
|
||||
response.append(data)
|
||||
|
||||
return response
|
||||
|
||||
def filter_with_context(self, context: GtkSource.CompletionContext) -> list[dict]:
|
||||
buffer = self.get_iter_correctly(context).get_buffer()
|
||||
word = self.get_word(context).rstrip()
|
||||
|
||||
if not buffer in self.matchers:
|
||||
self.matchers[buffer] = set()
|
||||
|
||||
response: list[dict] = []
|
||||
for entry in self.matchers[buffer]:
|
||||
if not entry.rstrip().startswith(word): continue
|
||||
|
||||
data = {
|
||||
"label": entry,
|
||||
"text": entry,
|
||||
"info": ""
|
||||
}
|
||||
|
||||
response.append(data)
|
||||
|
||||
return response
|
||||
|
||||
def load_empty_set(self, buffer):
|
||||
self.matchers[buffer] = set()
|
||||
|
||||
def load_into_set(self, buffer, new_words):
|
||||
# self.matchers[buffer].update(new_words)
|
||||
self.matchers[buffer] = new_words
|
||||
|
||||
def load_as_new_set(self, buffer, data):
|
||||
self.matchers[buffer] = self.get_all_words(data)
|
||||
|
||||
def get_all_words(self, data: str):
|
||||
words = set()
|
||||
|
||||
def is_word_char(c):
|
||||
return c.isalnum() or c == '_'
|
||||
|
||||
size = len(data)
|
||||
i = 0
|
||||
|
||||
while i < size:
|
||||
# Skip non-word characters
|
||||
while i < size and not is_word_char(data[i]):
|
||||
i += 1
|
||||
|
||||
start = i
|
||||
# Consume word characters
|
||||
while i < size and is_word_char(data[i]):
|
||||
i += 1
|
||||
|
||||
word = data[start:i]
|
||||
if not word: continue
|
||||
words.add(word)
|
||||
|
||||
return words
|
||||
3
plugins/code/ui/code_minimap/__init__.py
Normal file
3
plugins/code/ui/code_minimap/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/ui/code_minimap/__main__.py
Normal file
3
plugins/code/ui/code_minimap/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
50
plugins/code/ui/code_minimap/code_minimap.py
Normal file
50
plugins/code/ui/code_minimap/code_minimap.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
from gi.repository.GtkSource import Map
|
||||
from gi.repository import Pango
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class CodeMiniMap(Map):
|
||||
def __init__(self):
|
||||
super(CodeMiniMap, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("mini-view")
|
||||
|
||||
self.set_hexpand(False)
|
||||
self._set_font_desc()
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe(f"set-mini-view", self.set_smini_view)
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _set_font_desc(self):
|
||||
default_font = 'Monospace 1'
|
||||
desc = Pango.FontDescription(default_font)
|
||||
|
||||
desc.set_size(Pango.SCALE) # Set size to 1pt
|
||||
desc.set_family('BuilderBlocks,' + desc.get_family())
|
||||
self.set_property('font-desc', desc)
|
||||
|
||||
def set_smini_view(self, source_view):
|
||||
self.set_view(source_view)
|
||||
7
plugins/code/ui/code_minimap/manifest.json
Normal file
7
plugins/code/ui/code_minimap/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Code MiniMap",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
32
plugins/code/ui/code_minimap/plugin.py
Normal file
32
plugins/code/ui/code_minimap/plugin.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .code_minimap import CodeMiniMap
|
||||
|
||||
|
||||
|
||||
code_minimap = CodeMiniMap()
|
||||
|
||||
|
||||
|
||||
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.FocusedViewEvent):
|
||||
code_minimap.set_smini_view(event.view)
|
||||
|
||||
def load(self):
|
||||
editors_container = self.request_ui_element("editors-container")
|
||||
editors_container.add( code_minimap )
|
||||
|
||||
def run(self):
|
||||
...
|
||||
3
plugins/code/ui/info_bar/__init__.py
Normal file
3
plugins/code/ui/info_bar/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/ui/info_bar/__main__.py
Normal file
3
plugins/code/ui/info_bar/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
96
plugins/code/ui/info_bar/info_bar_widget.py
Normal file
96
plugins/code/ui/info_bar/info_bar_widget.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Pango
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class InfoBarWidget(Gtk.Box):
|
||||
""" docstring for InfoBarWidget. """
|
||||
|
||||
def __init__(self):
|
||||
super(InfoBarWidget, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_margin_start(25)
|
||||
self.set_margin_end(25)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
self.path_label = Gtk.Label(label = "...")
|
||||
self.line_char_label = Gtk.Label(label = "1:0")
|
||||
self.encoding_label = Gtk.Label(label = "utf-8")
|
||||
self.file_type_label = Gtk.Label(label = "buffer")
|
||||
|
||||
self.add(self.path_label)
|
||||
self.add(self.line_char_label)
|
||||
self.add(self.encoding_label)
|
||||
self.add(self.file_type_label)
|
||||
|
||||
self.path_label.set_hexpand(True)
|
||||
self.path_label.set_ellipsize(Pango.EllipsizeMode.START)
|
||||
self.path_label.set_single_line_mode(True)
|
||||
self.path_label.set_max_width_chars(48)
|
||||
|
||||
self.line_char_label.set_hexpand(True)
|
||||
self.encoding_label.set_hexpand(True)
|
||||
self.file_type_label.set_hexpand(True)
|
||||
|
||||
def _set_info_labels(
|
||||
self,
|
||||
path: Gio.File or str = None,
|
||||
line_char: str = None,
|
||||
file_type: str = None,
|
||||
encoding_type: str = None
|
||||
):
|
||||
self._set_path_label(path)
|
||||
self._set_line_char_label(line_char)
|
||||
self._set_file_type_label(file_type)
|
||||
self._set_encoding_label(encoding_type)
|
||||
|
||||
def _set_path_label(self, gfile: Gio.File or str = "..."):
|
||||
gfile = "" if not gfile else gfile
|
||||
|
||||
if isinstance(gfile, str):
|
||||
self.path_label.set_text( gfile )
|
||||
self.path_label.set_tooltip_text( gfile )
|
||||
else:
|
||||
self.path_label.set_text( gfile.get_path() )
|
||||
self.path_label.set_tooltip_text( gfile.get_path() )
|
||||
|
||||
def _set_line_char_label(self, line_char = "1:1"):
|
||||
line_char = "1:1" if not line_char else line_char
|
||||
|
||||
self.line_char_label.set_text(line_char)
|
||||
|
||||
def _set_file_type_label(self, file_type = "buffer"):
|
||||
file_type = "buffer" if not file_type else file_type
|
||||
|
||||
self.file_type_label.set_text(file_type)
|
||||
|
||||
def _set_encoding_label(self, encoding_type = "utf-8"):
|
||||
encoding_type = "utf-8" if not encoding_type else encoding_type
|
||||
|
||||
self.encoding_label.set_text(encoding_type)
|
||||
|
||||
|
||||
7
plugins/code/ui/info_bar/manifest.json
Normal file
7
plugins/code/ui/info_bar/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Info Bar",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
32
plugins/code/ui/info_bar/plugin.py
Normal file
32
plugins/code/ui/info_bar/plugin.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .info_bar_widget import InfoBarWidget
|
||||
|
||||
|
||||
|
||||
info_bar_widget = InfoBarWidget()
|
||||
|
||||
|
||||
|
||||
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.SetInfoLabelsEvent):
|
||||
info_bar_widget._set_info_labels(*event.info)
|
||||
|
||||
def load(self):
|
||||
header = self.request_ui_element("header-container")
|
||||
header.add( info_bar_widget )
|
||||
|
||||
def run(self):
|
||||
...
|
||||
3
plugins/code/ui/tabs_bar/__init__.py
Normal file
3
plugins/code/ui/tabs_bar/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/ui/tabs_bar/__main__.py
Normal file
3
plugins/code/ui/tabs_bar/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
7
plugins/code/ui/tabs_bar/manifest.json
Normal file
7
plugins/code/ui/tabs_bar/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Tabs Bar",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
32
plugins/code/ui/tabs_bar/plugin.py
Normal file
32
plugins/code/ui/tabs_bar/plugin.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .tabs_controller import TabsController
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
tabs_controller = TabsController()
|
||||
code_container = self.request_ui_element("code-container")
|
||||
|
||||
self.register_controller("tabs", tabs_controller)
|
||||
|
||||
code_container.add( tabs_controller.tabs_widget )
|
||||
code_container.reorder_child(tabs_controller.tabs_widget, 0)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
84
plugins/code/ui/tabs_bar/tab_widget.py
Normal file
84
plugins/code/ui/tabs_bar/tab_widget.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class TabWidget(Gtk.Box):
|
||||
"""docstring for TabWidget"""
|
||||
|
||||
def __init__(self):
|
||||
super(TabWidget, self).__init__()
|
||||
|
||||
self.file = None
|
||||
|
||||
self._handler_id = None
|
||||
self._eve_handler_id = None
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("tab-widget")
|
||||
|
||||
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):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.event_box = Gtk.EventBox()
|
||||
self.label = Gtk.Label()
|
||||
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")
|
||||
ctx = self.close_bttn.get_style_context()
|
||||
ctx.add_class("tab-close-bttn")
|
||||
|
||||
self.label.set_xalign(0.0)
|
||||
self.label.set_margin_left(25)
|
||||
self.label.set_margin_right(25)
|
||||
self.label.set_hexpand(True)
|
||||
|
||||
self.close_bttn.add(icon)
|
||||
self.event_box.add(self.label)
|
||||
self.add(self.event_box)
|
||||
self.add(self.close_bttn)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def clear_signals_and_data(self):
|
||||
self.close_bttn.disconnect(self._handler_id)
|
||||
self.event_box.disconnect(self._eve_handler_id)
|
||||
self._handler_id = None
|
||||
|
||||
for child in self.get_children():
|
||||
child.unparent()
|
||||
child.run_dispose()
|
||||
child.destroy()
|
||||
|
||||
def set_close_signal(self, callback):
|
||||
self._handler_id = self.close_bttn.connect(
|
||||
'clicked',
|
||||
callback,
|
||||
self.file
|
||||
)
|
||||
75
plugins/code/ui/tabs_bar/tabs_controller.py
Normal file
75
plugins/code/ui/tabs_bar/tabs_controller.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from libs.controllers.controller_base import ControllerBase
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from core.widgets.code.source_view import SourceView
|
||||
|
||||
from .tabs_widget import TabsWidget
|
||||
from .tab_widget import TabWidget
|
||||
|
||||
|
||||
|
||||
|
||||
class TabsController(ControllerBase):
|
||||
def __init__(self):
|
||||
super(TabsController, self).__init__()
|
||||
|
||||
self.tabs_widget: TabsWidget = TabsWidget()
|
||||
self.tabs_widget.emit = self.emit
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, Code_Event_Types.FocusedViewEvent):
|
||||
self.tabs_widget.view_changed( event.view.get_buffer() )
|
||||
elif isinstance(event, Code_Event_Types.FilePathSetEvent):
|
||||
self.update_tab_label(event)
|
||||
elif isinstance(event, Code_Event_Types.ModifiedChangedEvent):
|
||||
self.tabs_widget.modified_changed( event.buffer )
|
||||
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)
|
||||
elif isinstance(event, Code_Event_Types.PoppedFileEvent):
|
||||
...
|
||||
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
||||
self.remove_tab(event)
|
||||
|
||||
def get_tabs_widget(self):
|
||||
return self.tabs_widget
|
||||
|
||||
def update_tab_label(self, event: Code_Event_Types.FilePathSetEvent):
|
||||
for page_widget in self.tabs_widget.get_children():
|
||||
tab = self.tabs_widget.get_tab_label(page_widget)
|
||||
if not event.file == tab.file: continue
|
||||
|
||||
tab.label.set_label(event.file.fname)
|
||||
|
||||
break
|
||||
|
||||
def add_tab(self, event: Code_Event_Types.AddedNewFileEvent):
|
||||
tab = TabWidget()
|
||||
tab.file = event.file
|
||||
|
||||
tab.label.set_label(event.file.fname)
|
||||
|
||||
self.tabs_widget.append_page(Gtk.Separator(), tab)
|
||||
tab.show_all()
|
||||
|
||||
def remove_tab(self, event: Code_Event_Types.RemovedFileEvent):
|
||||
for page_widget in self.tabs_widget.get_children():
|
||||
tab = self.tabs_widget.get_tab_label(page_widget)
|
||||
if not event.file == tab.file: continue
|
||||
|
||||
tab.clear_signals_and_data()
|
||||
self.tabs_widget.remove_page(
|
||||
self.tabs_widget.page_num(page_widget)
|
||||
)
|
||||
|
||||
break
|
||||
179
plugins/code/ui/tabs_bar/tabs_widget.py
Normal file
179
plugins/code/ui/tabs_bar/tabs_widget.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from .tab_widget import TabWidget
|
||||
|
||||
|
||||
|
||||
class TabsWidget(Gtk.Notebook):
|
||||
def __init__(self):
|
||||
super(TabsWidget, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show()
|
||||
|
||||
|
||||
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)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def _page_added(self, notebook, page_widget, page_num):
|
||||
tab = self.get_tab_label(page_widget)
|
||||
tab.set_close_signal(self._close_tab)
|
||||
|
||||
self._bind_tab_menu(tab, page_widget)
|
||||
|
||||
page_widget.show()
|
||||
self.set_tab_detachable(page_widget, True)
|
||||
self.set_tab_reorderable(page_widget, True)
|
||||
|
||||
def _close_tab(self, button, file):
|
||||
event = Event_Factory.create_event(
|
||||
"remove_file",
|
||||
buffer = file.buffer
|
||||
)
|
||||
|
||||
self.emit(event)
|
||||
|
||||
def _switch_page(self, notebook, page_widget, page_num):
|
||||
tab = self.get_tab_label(page_widget)
|
||||
event = Event_Factory.create_event(
|
||||
"set_active_file",
|
||||
buffer = tab.file.buffer
|
||||
)
|
||||
|
||||
self.emit(event)
|
||||
|
||||
def _bind_tab_menu(self, tab, page_widget):
|
||||
def do_context_menu(tab, eve, page_widget):
|
||||
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3: # r-click
|
||||
menu = self.create_menu(page_widget)
|
||||
menu.popup_at_pointer(eve)
|
||||
|
||||
tab._eve_handler_id = \
|
||||
tab.event_box.connect(
|
||||
"button-release-event",
|
||||
do_context_menu,
|
||||
page_widget
|
||||
)
|
||||
|
||||
def create_menu(self, page_widget) -> Gtk.Menu:
|
||||
context_menu = Gtk.Menu()
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
context_menu.show_all()
|
||||
|
||||
return context_menu
|
||||
|
||||
def view_changed(self, buffer):
|
||||
for page_widget in self.get_children():
|
||||
tab = self.get_tab_label(page_widget)
|
||||
if not buffer == tab.file.buffer: continue
|
||||
|
||||
self.handler_block(self.switch_page_id)
|
||||
|
||||
self.set_current_page(
|
||||
self.page_num(page_widget)
|
||||
)
|
||||
|
||||
self.handler_unblock(self.switch_page_id)
|
||||
|
||||
break
|
||||
|
||||
def modified_changed(self, buffer):
|
||||
for page_widget in self.get_children():
|
||||
tab = self.get_tab_label(page_widget)
|
||||
if not buffer == tab.file.buffer: continue
|
||||
|
||||
ctx = tab.label.get_style_context()
|
||||
ctx.remove_class("file-deleted")
|
||||
if buffer.get_modified():
|
||||
ctx.add_class("file-changed")
|
||||
else:
|
||||
ctx.remove_class("file-changed")
|
||||
|
||||
break
|
||||
|
||||
def externally_deleted(self, buffer):
|
||||
for page_widget in self.get_children():
|
||||
tab = self.get_tab_label(page_widget)
|
||||
if not buffer == tab.file.buffer: continue
|
||||
ctx = tab.label.get_style_context()
|
||||
ctx.add_class("file-deleted")
|
||||
break
|
||||
|
||||
|
||||
def close_item(self, menu_item, page_widget):
|
||||
tab = self.get_tab_label(page_widget)
|
||||
tab.close_bttn.clicked()
|
||||
|
||||
def close_left_items(self, menu_item, page_widget):
|
||||
children = self.get_children()
|
||||
i = children.index(page_widget)
|
||||
|
||||
if i == 0: return
|
||||
|
||||
for widget in children[ : i]:
|
||||
tab = self.get_tab_label(widget)
|
||||
tab.close_bttn.clicked()
|
||||
|
||||
def close_right_items(self, menu_item, page_widget):
|
||||
children = self.get_children()
|
||||
i = children.index(page_widget) + 1
|
||||
|
||||
if i == len(children): return
|
||||
|
||||
for widget in children[i : ]:
|
||||
tab = self.get_tab_label(widget)
|
||||
tab.close_bttn.clicked()
|
||||
|
||||
def close_other_items(self, menu_item, page_widget):
|
||||
self.close_left_items(menu_item, page_widget)
|
||||
self.close_right_items(menu_item, page_widget)
|
||||
|
||||
def close_all_items(self, menu_item, page_widget):
|
||||
children = self.get_children()
|
||||
|
||||
for widget in children[ : ]:
|
||||
tab = self.get_tab_label(widget)
|
||||
tab.close_bttn.clicked()
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"manifest": {
|
||||
"name": "Example Plugin",
|
||||
"author": "John Doe",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {
|
||||
"ui_target": "plugin_control_list",
|
||||
"pass_events": "true",
|
||||
"bind_keys": ["Example Plugin||send_message:<Control>f"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
# Python imports
|
||||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from plugins.plugin_base import PluginBase
|
||||
|
||||
|
||||
|
||||
|
||||
# NOTE: Threads WILL NOT die with parent's destruction.
|
||||
def threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
|
||||
return wrapper
|
||||
|
||||
# NOTE: Threads WILL die with parent's destruction.
|
||||
def daemon_threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
|
||||
# where self.name should not be needed for message comms
|
||||
|
||||
|
||||
def generate_reference_ui_element(self):
|
||||
button = Gtk.Button(label=self.name)
|
||||
button.connect("button-release-event", self.send_message)
|
||||
return button
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
def send_message(self, widget=None, eve=None):
|
||||
message = "Hello, World!"
|
||||
event_system.emit("display_message", ("warning", message, None))
|
||||
3
plugins/ui/template/__init__.py
Normal file
3
plugins/ui/template/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/ui/template/__main__.py
Normal file
3
plugins/ui/template/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
9
plugins/ui/template/manifest.json
Normal file
9
plugins/ui/template/manifest.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "Example Plugin",
|
||||
"author": "John Doe",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {
|
||||
"bind_keys": ["Example Plugin||send_message:<Control>f"]
|
||||
}
|
||||
}
|
||||
40
plugins/ui/template/plugin.py
Normal file
40
plugins/ui/template/plugin.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from libs.dto.base_event import BaseEvent
|
||||
|
||||
from plugins.plugin_types import PluginUI
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginUI):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: BaseEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
ui_element = self.request_ui_element("header-container")
|
||||
ui_element.add( self.generate_plugin_element() )
|
||||
|
||||
def run(self):
|
||||
...
|
||||
|
||||
def generate_plugin_element(self):
|
||||
button = Gtk.Button(label = "Hello, World!")
|
||||
|
||||
button.connect("button-release-event", self.send_message)
|
||||
button.show()
|
||||
|
||||
return button
|
||||
|
||||
def send_message(self, widget = None, eve = None):
|
||||
logger.info("Hello, World!")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"reportDuplicateImport": true,
|
||||
"executionEnvironments": [
|
||||
{
|
||||
"root": "./src/versions/solarfm-0.0.1/solarfm"
|
||||
"root": "./src/"
|
||||
}
|
||||
],
|
||||
"venvPath": ".",
|
||||
|
||||
@@ -8,11 +8,11 @@ import sys
|
||||
|
||||
# Application imports
|
||||
# from libs.db import DB
|
||||
from libs.event_system import EventSystem
|
||||
from libs.endpoint_registry import EndpointRegistry
|
||||
from libs.keybindings import Keybindings
|
||||
from libs.logger import Logger
|
||||
from libs.event_system import EventSystem
|
||||
from libs.keybindings import Keybindings
|
||||
from libs.settings.manager import SettingsManager
|
||||
from libs.widget_registery import WidgetRegisteryController
|
||||
|
||||
|
||||
|
||||
@@ -34,12 +34,8 @@ def daemon_threaded_wrapper(fn):
|
||||
|
||||
def call_chain_wrapper(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
print()
|
||||
print()
|
||||
for line in traceback.format_stack():
|
||||
print( line.strip() )
|
||||
print()
|
||||
print()
|
||||
|
||||
return fn(*args, **kwargs)
|
||||
return wrapper
|
||||
@@ -47,21 +43,20 @@ def call_chain_wrapper(fn):
|
||||
|
||||
# NOTE: Just reminding myself we can add to builtins two different ways...
|
||||
# __builtins__.update({"event_system": Builtins()})
|
||||
builtins.APP_NAME = "<change_me>"
|
||||
builtins.APP_NAME = "<change_me>".replace("<","").replace(">","")
|
||||
|
||||
builtins.keybindings = Keybindings()
|
||||
builtins.event_system = EventSystem()
|
||||
builtins.endpoint_registry = EndpointRegistry()
|
||||
builtins.settings_manager = SettingsManager()
|
||||
builtins.widget_registery = WidgetRegisteryController()
|
||||
# builtins.db = DB()
|
||||
|
||||
settings_manager.load_settings()
|
||||
|
||||
builtins.settings = settings_manager.settings
|
||||
builtins.logger = Logger(
|
||||
settings_manager.get_home_config_path(), \
|
||||
_ch_log_lvl = settings.debugging.ch_log_lvl, \
|
||||
_fh_log_lvl = settings.debugging.fh_log_lvl
|
||||
settings_manager.path_manager.get_home_config_path(), \
|
||||
_ch_log_lvl = settings_manager.settings.debugging.ch_log_lvl, \
|
||||
_fh_log_lvl = settings_manager.settings.debugging.fh_log_lvl
|
||||
).get_logger()
|
||||
|
||||
builtins.threaded = threaded_wrapper
|
||||
|
||||
34
src/app.py
34
src/app.py
@@ -2,6 +2,7 @@
|
||||
from contextlib import suppress
|
||||
import signal
|
||||
import os
|
||||
import json
|
||||
|
||||
# Lib imports
|
||||
|
||||
@@ -23,13 +24,14 @@ class Application:
|
||||
def __init__(self):
|
||||
super(Application, self).__init__()
|
||||
|
||||
if not settings_manager.is_trace_debug():
|
||||
self.load_ipc()
|
||||
|
||||
self.setup_debug_hook()
|
||||
|
||||
|
||||
def run(self):
|
||||
if not settings_manager.is_trace_debug():
|
||||
if not self.load_ipc():
|
||||
return
|
||||
|
||||
win = Window()
|
||||
win.start()
|
||||
|
||||
@@ -39,13 +41,24 @@ class Application:
|
||||
ipc_server = IPCServer()
|
||||
|
||||
self.ipc_realization_check(ipc_server)
|
||||
if not ipc_server.is_ipc_alive:
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isfile(arg):
|
||||
message = f"FILE|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
if ipc_server.is_ipc_alive:
|
||||
return True
|
||||
|
||||
raise AppLaunchException(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||
logger.warning(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||
files: list = []
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isfile(arg):
|
||||
files.append(f"file://{arg}")
|
||||
|
||||
if os.path.isdir(arg):
|
||||
message = f"DIR|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
if files:
|
||||
message = f"FILES|{json.dumps(files)}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
return False
|
||||
|
||||
def ipc_realization_check(self, ipc_server):
|
||||
try:
|
||||
@@ -53,9 +66,6 @@ class Application:
|
||||
except Exception:
|
||||
ipc_server.send_test_ipc_message()
|
||||
|
||||
with suppress(Exception):
|
||||
ipc_server.create_ipc_listener()
|
||||
|
||||
def setup_debug_hook(self):
|
||||
# Typically: ValueError: signal only works in main thread
|
||||
with suppress(ValueError):
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class BuilderWrapper(Gtk.Builder):
|
||||
"""docstring for BuilderWrapper."""
|
||||
|
||||
def __init__(self):
|
||||
super(BuilderWrapper, self).__init__()
|
||||
|
||||
self.objects = {}
|
||||
|
||||
def get_object(self, id: str, use_gtk: bool = True) -> any:
|
||||
if not use_gtk:
|
||||
return self.objects[id]
|
||||
|
||||
return super(BuilderWrapper, self).get_object(id)
|
||||
|
||||
def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None:
|
||||
if not use_gtk:
|
||||
self.objects[id] = object
|
||||
else:
|
||||
super(BuilderWrapper, self).expose_object(id, object)
|
||||
|
||||
def dereference_object(self, id: str) -> None:
|
||||
del self.objects[id]
|
||||
@@ -16,8 +16,6 @@ class BaseContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(BaseContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -27,9 +25,12 @@ class BaseContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("base-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self._update_transparency()
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
@@ -38,12 +39,14 @@ class BaseContainer(Gtk.Box):
|
||||
event_system.subscribe("remove-transparency", self._remove_transparency)
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add(HeaderContainer())
|
||||
self.add(BodyContainer())
|
||||
self.add(FooterContainer())
|
||||
widget_registery.expose_object("base-container", self)
|
||||
|
||||
self.add( HeaderContainer() )
|
||||
self.add( BodyContainer() )
|
||||
self.add( FooterContainer() )
|
||||
|
||||
def _update_transparency(self):
|
||||
self.ctx.add_class(f"mw_transparency_{settings.theming.transparency}")
|
||||
self.ctx.add_class(f"mw_transparency_{settings_manager.settings.theming.transparency}")
|
||||
|
||||
def _remove_transparency(self):
|
||||
self.ctx.remove_class(f"mw_transparency_{settings.theming.transparency}")
|
||||
self.ctx.remove_class(f"mw_transparency_{settings_manager.settings.theming.transparency}")
|
||||
@@ -16,8 +16,6 @@ class BodyContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(BodyContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -27,8 +25,10 @@ class BodyContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("body-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.set_homogeneous(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
@@ -37,8 +37,9 @@ class BodyContainer(Gtk.Box):
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add(LeftContainer())
|
||||
self.add(CenterContainer())
|
||||
self.add(RightContainer())
|
||||
widget_registery.expose_object("body-container", self)
|
||||
|
||||
self.add( LeftContainer() )
|
||||
self.add( CenterContainer() )
|
||||
self.add( RightContainer() )
|
||||
@@ -14,7 +14,6 @@ class CenterContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(CenterContainer, self).__init__()
|
||||
|
||||
self._builder = settings_manager.get_builder()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
@@ -25,14 +24,13 @@ class CenterContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("center-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("center-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
@@ -40,8 +38,13 @@ class CenterContainer(Gtk.Box):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
glade_box = self._builder.get_object("glade_box")
|
||||
button = Gtk.Button(label = "Click Me!")
|
||||
widget_registery.expose_object("center-container", self)
|
||||
|
||||
glade_box = widget_registery.get_object("glade_box")
|
||||
button = Gtk.Button(label = "Click Me!")
|
||||
webkit_ui = WebkitUI()
|
||||
|
||||
webkit_ui.load_context_base_path()
|
||||
|
||||
button.connect("clicked", self._hello_world)
|
||||
|
||||
@@ -50,7 +53,7 @@ class CenterContainer(Gtk.Box):
|
||||
|
||||
self.add(button)
|
||||
self.add(glade_box)
|
||||
self.add( WebkitUI() )
|
||||
self.add(webkit_ui)
|
||||
|
||||
def _hello_world(self, widget = None, eve = None):
|
||||
logger.debug("Hello, World!")
|
||||
3
src/core/containers/code/__init__.py
Normal file
3
src/core/containers/code/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Containers Package
|
||||
"""
|
||||
54
src/core/containers/code/code_container.py
Normal file
54
src/core/containers/code/code_container.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
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
|
||||
|
||||
|
||||
|
||||
class CodeContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(CodeContainer, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
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
|
||||
71
src/core/containers/code/editors_container.py
Normal file
71
src/core/containers/code/editors_container.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class EditorsContainer(Gtk.Paned):
|
||||
def __init__(self, code_base: any):
|
||||
super(EditorsContainer, self).__init__()
|
||||
|
||||
self.code_base = code_base
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("paned-editors-container")
|
||||
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
self.set_wide_handle(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
self.map_id = self.connect("map", self._init_map)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.scrolled_win1, \
|
||||
self.scrolled_win2 = self._create_views()
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
@@ -6,6 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
|
||||
|
||||
|
||||
@@ -13,8 +14,6 @@ class FooterContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(FooterContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -24,18 +23,19 @@ class FooterContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("footer-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.set_hexpand(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
widget_registery.expose_object("footer-container", self)
|
||||
|
||||
self.add( Separator("separator-footer", 0) )
|
||||
|
||||
@@ -6,6 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from ..widgets.controls.open_files_button import OpenFilesButton
|
||||
from ..widgets.controls.transparency_scale import TransparencyScale
|
||||
|
||||
@@ -15,8 +16,6 @@ class HeaderContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(HeaderContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -26,23 +25,25 @@ class HeaderContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("header-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.set_hexpand(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("tggl-top-main-menubar", self.tggl_top_main_menubar)
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
widget_registery.expose_object("header-container", self)
|
||||
|
||||
button = Gtk.Button(label = "Interactive Debug")
|
||||
button.connect("clicked", self._interactive_debug)
|
||||
|
||||
self.add( Separator("separator-header", 0) )
|
||||
self.add( OpenFilesButton() )
|
||||
self.add( TransparencyScale() )
|
||||
self.add(button)
|
||||
|
||||
@@ -6,6 +6,8 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ..widgets.separator_widget import Separator
|
||||
from .code.code_container import CodeContainer
|
||||
|
||||
|
||||
|
||||
@@ -22,13 +24,12 @@ class LeftContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("left-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("left-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
@@ -36,4 +37,7 @@ class LeftContainer(Gtk.Box):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
widget_registery.expose_object("left-container", self)
|
||||
|
||||
self.add( Separator("separator-left", 1) )
|
||||
self.add( CodeContainer() )
|
||||
|
||||
@@ -6,6 +6,7 @@ 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
|
||||
|
||||
|
||||
@@ -23,13 +24,12 @@ class RightContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("right-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("right-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
@@ -37,5 +37,9 @@ class RightContainer(Gtk.Box):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
widget_registery.expose_object("right-container", self)
|
||||
|
||||
vte_widget = VteWidget()
|
||||
self.add( vte_widget )
|
||||
self.add( vte_widget )
|
||||
|
||||
self.add( Separator("separator-right", 1) )
|
||||
|
||||
@@ -6,33 +6,48 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from plugins import plugins_controller
|
||||
|
||||
from libs.mixins.ipc_signals_mixin import IPCSignalsMixin
|
||||
from libs.mixins.keyboard_signals_mixin import KeyboardSignalsMixin
|
||||
|
||||
from ..containers.base_container import BaseContainer
|
||||
|
||||
from .base_controller_data import BaseControllerData
|
||||
from .base_controller_mixin import BaseControllerMixin
|
||||
from .bridge_controller import BridgeController
|
||||
|
||||
|
||||
|
||||
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerMixin):
|
||||
""" docstring for BaseController. """
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._setup_controller_data()
|
||||
|
||||
self._load_plugins(is_pre = True)
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_controllers()
|
||||
self._load_plugins_and_files()
|
||||
self._load_plugins(is_pre = False)
|
||||
self._load_files()
|
||||
|
||||
logger.info(f"Made it past {self.__class__} loading...")
|
||||
settings_manager.set_end_load_time()
|
||||
settings_manager.log_load_time()
|
||||
|
||||
|
||||
def _setup_controller_data(self):
|
||||
self.window = settings_manager.get_main_window()
|
||||
self.base_container = BaseContainer()
|
||||
self.plugins_controller = plugins_controller
|
||||
|
||||
widget_registery.expose_object("main_window", self.window)
|
||||
settings_manager.register_signals_to_builder([self, self.base_container])
|
||||
|
||||
self._collect_files_dirs()
|
||||
|
||||
def _setup_styling(self):
|
||||
...
|
||||
|
||||
@@ -44,29 +59,29 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("shutting-down", lambda: print("Shutting down..."))
|
||||
event_system.subscribe("handle-file-from-ipc", self.handle_file_from_ipc)
|
||||
event_system.subscribe("handle-files-from-ipc", self.handle_files_from_ipc)
|
||||
event_system.subscribe("handle-dir-from-ipc", self.handle_dir_from_ipc)
|
||||
event_system.subscribe("tggl-top-main-menubar", self._tggl_top_main_menubar)
|
||||
|
||||
def _load_controllers(self):
|
||||
BridgeController()
|
||||
|
||||
def _load_plugins_and_files(self):
|
||||
def _load_plugins(self, is_pre: bool):
|
||||
args, unknownargs = settings_manager.get_starting_args()
|
||||
if args.no_plugins == "false":
|
||||
self.plugins_controller.pre_launch_plugins()
|
||||
self.plugins_controller.post_launch_plugins()
|
||||
if args.no_plugins == "true": return
|
||||
|
||||
if is_pre:
|
||||
self.plugins_controller.pre_launch_plugins()
|
||||
return
|
||||
|
||||
if not is_pre:
|
||||
self.plugins_controller.post_launch_plugins()
|
||||
return
|
||||
|
||||
def _load_files(self):
|
||||
for file in settings_manager.get_starting_files():
|
||||
event_system.emit("post-file-to-ipc", file)
|
||||
|
||||
def _tggl_top_main_menubar(self):
|
||||
logger.debug("_tggl_top_main_menubar > stub...")
|
||||
|
||||
def _load_glade_file(self):
|
||||
self.builder.add_from_file( settings_manager.get_glade_file() )
|
||||
self.builder.expose_object("main_window", self.window)
|
||||
|
||||
settings_manager.set_builder(self.builder)
|
||||
self.base_container = BaseContainer()
|
||||
|
||||
settings_manager.register_signals_to_builder([self, self.base_container])
|
||||
@@ -6,28 +6,11 @@ from shutil import which
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from plugins.plugins_controller import PluginsController
|
||||
from ..builder_wrapper import BuilderWrapper
|
||||
|
||||
|
||||
|
||||
class BaseControllerData:
|
||||
''' BaseControllerData contains most of the state of the app at ay given time. It also has some support methods. '''
|
||||
|
||||
def _setup_controller_data(self) -> None:
|
||||
self.window = settings_manager.get_main_window()
|
||||
self.builder = BuilderWrapper()
|
||||
self.plugins_controller = PluginsController()
|
||||
|
||||
self.base_container = None
|
||||
self.was_midified_key = False
|
||||
self.ctrl_down = False
|
||||
self.shift_down = False
|
||||
self.alt_down = False
|
||||
|
||||
self._collect_files_dirs()
|
||||
self._load_glade_file()
|
||||
|
||||
class BaseControllerMixin:
|
||||
''' BaseControllerMixin contains most of the state of the app at ay given time. It also has some support methods. '''
|
||||
|
||||
def _collect_files_dirs(self):
|
||||
args, \
|
||||
@@ -46,7 +29,7 @@ class BaseControllerData:
|
||||
|
||||
logger.info(f"Not a File: {arg}")
|
||||
|
||||
if len(files) == 0: return
|
||||
if not files: return
|
||||
|
||||
settings_manager.set_is_starting_with_file(True)
|
||||
settings_manager.set_starting_files(files)
|
||||
3
src/core/widgets/code/__init__.py
Normal file
3
src/core/widgets/code/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Code Package
|
||||
"""
|
||||
63
src/core/widgets/code/code_base.py
Normal file
63
src/core/widgets/code/code_base.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from plugins import plugins_controller
|
||||
|
||||
from libs.controllers.controller_manager import ControllerManager
|
||||
|
||||
from .controllers.files_controller import FilesController
|
||||
from .controllers.commands_controller import CommandsController
|
||||
from .controllers.completion_controller import CompletionController
|
||||
from .controllers.views.source_views_controller import SourceViewsController
|
||||
|
||||
|
||||
|
||||
class CodeBase:
|
||||
def __init__(self):
|
||||
super(CodeBase, self).__init__()
|
||||
|
||||
self.controller_manager: ControllerManager = ControllerManager()
|
||||
|
||||
self._subscribe_to_events()
|
||||
self._load_controllers()
|
||||
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("handle-file", self._load_ipc_file)
|
||||
event_system.subscribe("handle-files", self._load_ipc_files)
|
||||
|
||||
def _load_controllers(self):
|
||||
files_controller = FilesController()
|
||||
commands_controller = CommandsController()
|
||||
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)
|
||||
self.controller_manager.register_controller("source_views", source_views_controller)
|
||||
self.controller_manager.register_controller("plugins", plugins_controller)
|
||||
self.controller_manager.register_controller("widgets", widget_registery)
|
||||
|
||||
def create_source_view(self):
|
||||
source_view = self.controller_manager["source_views"].create_source_view()
|
||||
self.controller_manager["completion"].register_completer(
|
||||
source_view.get_completion()
|
||||
)
|
||||
|
||||
return source_view
|
||||
|
||||
def first_map_load(self):
|
||||
self.controller_manager["source_views"].first_map_load()
|
||||
|
||||
def _load_ipc_file(self, fpath: str):
|
||||
active_view = self.controller_manager["source_views"].signal_mapper.active_view
|
||||
uris = [ f"file://{fpath}" ]
|
||||
active_view._on_uri_data_received(uris)
|
||||
|
||||
def _load_ipc_files(self, uris: list):
|
||||
active_view = self.controller_manager["source_views"].signal_mapper.active_view
|
||||
active_view._on_uri_data_received(uris)
|
||||
5
src/core/widgets/code/command_system/__init__.py
Normal file
5
src/core/widgets/code/command_system/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""
|
||||
Code Command System Package
|
||||
"""
|
||||
|
||||
from .command_system import CommandSystem
|
||||
26
src/core/widgets/code/command_system/command_helpers.py
Normal file
26
src/core/widgets/code/command_system/command_helpers.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def set_language_and_style(view, file):
|
||||
language = view.language_manager.guess_language(file.fname, None)
|
||||
file.buffer.set_language(language)
|
||||
file.buffer.set_style_scheme(view.syntax_theme)
|
||||
|
||||
return language
|
||||
|
||||
def update_info_bar_if_focused(command_system, view: GtkSource):
|
||||
has_focus = command_system.exec("has_focus")
|
||||
if has_focus:
|
||||
command_system.exec("update_info_bar")
|
||||
|
||||
def get_file_and_buffer(view: GtkSource):
|
||||
file = view.command.get_file(view)
|
||||
buffer = file.buffer
|
||||
|
||||
return file, buffer
|
||||
105
src/core/widgets/code/command_system/command_system.py
Normal file
105
src/core/widgets/code/command_system/command_system.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from ..source_view import SourceView
|
||||
|
||||
from . import commands
|
||||
|
||||
|
||||
|
||||
class CommandSystem:
|
||||
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 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 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)
|
||||
16
src/core/widgets/code/command_system/commands/__init__.py
Normal file
16
src/core/widgets/code/command_system/commands/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Code Commands Package
|
||||
"""
|
||||
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
||||
__all__ = []
|
||||
|
||||
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||
module = importlib.import_module(f"{__name__}.{module_name}")
|
||||
# globals()[module_name] = module # Add module to package namespace
|
||||
__all__.append(module_name)
|
||||
|
||||
del pkgutil
|
||||
del importlib
|
||||
25
src/core/widgets/code/command_system/commands/buffer_redo.py
Normal file
25
src/core/widgets/code/command_system/commands/buffer_redo.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Buffer Redo")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
undo_manager = buffer.get_undo_manager()
|
||||
|
||||
if undo_manager.can_redo():
|
||||
buffer.redo()
|
||||
25
src/core/widgets/code/command_system/commands/buffer_undo.py
Normal file
25
src/core/widgets/code/command_system/commands/buffer_undo.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Buffer Undo")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
undo_manager = buffer.get_undo_manager()
|
||||
|
||||
if undo_manager.can_undo():
|
||||
buffer.undo()
|
||||
22
src/core/widgets/code/command_system/commands/close_file.py
Normal file
22
src/core/widgets/code/command_system/commands/close_file.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from ..command_helpers import update_info_bar_if_focused
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Close File")
|
||||
view.command.remove_file(view)
|
||||
update_info_bar_if_focused(view.command, view)
|
||||
@@ -0,0 +1,38 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Cut to Temp Buffer")
|
||||
|
||||
view.clear_temp_cut_buffer_delayed()
|
||||
|
||||
buffer = view.get_buffer()
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
start_itr = itr.copy()
|
||||
end_itr = itr.copy()
|
||||
start_line = itr.get_line() + 1
|
||||
start_char = itr.get_line_offset()
|
||||
|
||||
start_itr.backward_visible_line()
|
||||
start_itr.forward_line()
|
||||
end_itr.forward_line()
|
||||
|
||||
line_str = buffer.get_slice(start_itr, end_itr, True)
|
||||
view._cut_buffer += f"{line_str}"
|
||||
buffer.delete(start_itr, end_itr)
|
||||
|
||||
view.set_temp_cut_buffer_delayed()
|
||||
@@ -0,0 +1,33 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ..command_helpers import update_info_bar_if_focused
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
uri: str,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: DnD Load File To Buffer")
|
||||
file = view.command.new_file(view)
|
||||
|
||||
gfile = Gio.File.new_for_uri(uri)
|
||||
view.command.exec_with_args(
|
||||
"load_file",
|
||||
view, gfile, file
|
||||
)
|
||||
|
||||
view.set_buffer(file.buffer)
|
||||
|
||||
update_info_bar_if_focused(view.command, view)
|
||||
@@ -0,0 +1,28 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
uris: list = [],
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: DnD Load Files")
|
||||
for uri in uris:
|
||||
try:
|
||||
gfile = Gio.File.new_for_uri(uri)
|
||||
except Exception as e:
|
||||
gfile = Gio.File.new_for_path(uri)
|
||||
|
||||
view.command.exec_with_args("load_file", view, gfile)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Duplicate Line")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
|
||||
if not buffer.get_has_selection():
|
||||
had_selection = False
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
start_itr = itr.copy()
|
||||
end_itr = itr.copy()
|
||||
start_line = itr.get_line() + 1
|
||||
start_char = itr.get_line_offset()
|
||||
else:
|
||||
had_selection = True
|
||||
start_itr, end_itr = buffer.get_selection_bounds()
|
||||
sline = start_itr.get_line()
|
||||
eline = end_itr.get_line()
|
||||
start_line = eline + 1
|
||||
start_char = start_itr.get_line_offset()
|
||||
end_char = end_itr.get_line_offset()
|
||||
range_line_size = eline - sline
|
||||
|
||||
start_itr.backward_visible_line()
|
||||
start_itr.forward_line()
|
||||
end_itr.forward_line()
|
||||
end_itr.backward_char()
|
||||
|
||||
line_str = buffer.get_slice(start_itr, end_itr, True)
|
||||
end_itr.forward_char()
|
||||
buffer.insert(end_itr, f"{line_str}\n", -1)
|
||||
|
||||
if not had_selection:
|
||||
new_itr = buffer.get_iter_at_line_offset(start_line, start_char)
|
||||
buffer.place_cursor(new_itr)
|
||||
else:
|
||||
new_itr = buffer.get_iter_at_line_offset(start_line, start_char)
|
||||
new_end_itr = buffer.get_iter_at_line_offset((start_line + range_line_size), end_char)
|
||||
buffer.select_range(new_itr, new_end_itr)
|
||||
@@ -0,0 +1,22 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Focus Left Sibling")
|
||||
if not view.sibling_left: return
|
||||
view.sibling_left.get_parent().show()
|
||||
view.sibling_left.grab_focus()
|
||||
@@ -0,0 +1,22 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
logger.debug("Command: Focus Right Sibling")
|
||||
if not view.sibling_right: return
|
||||
view.sibling_right.get_parent().show()
|
||||
view.sibling_right.grab_focus()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user