mirror of
https://github.com/hexedtech/codemp-sublime.git
synced 2024-11-23 07:14:48 +01:00
feat: move the library to be bundled together with the repo directly.
This approach will allow us to install directly through package control by just specifying the repo! Former-commit-id: 3df245186298042dfd4d8e0bf65844a283a571dd
This commit is contained in:
parent
759fe03ac8
commit
6c54a15560
18 changed files with 263 additions and 170 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -22,7 +22,6 @@ build/
|
||||||
develop-eggs/
|
develop-eggs/
|
||||||
dist/
|
dist/
|
||||||
eggs/
|
eggs/
|
||||||
lib/
|
|
||||||
lib64/
|
lib64/
|
||||||
parts/
|
parts/
|
||||||
sdist/
|
sdist/
|
||||||
|
|
0
.no-sublime-package
Normal file
0
.no-sublime-package
Normal file
|
@ -32,7 +32,7 @@
|
||||||
"caption": "Codemp: Connect",
|
"caption": "Codemp: Connect",
|
||||||
"command": "codemp_connect",
|
"command": "codemp_connect",
|
||||||
"args": {
|
"args": {
|
||||||
// "server_host": "http://[::1]:50051"
|
"server_host": "http://codemp.dev:50053",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
f0cef32c2765ba5d1bcaca6e11544caacf717006
|
|
|
@ -1 +0,0 @@
|
||||||
8ee9409baac472917d5a57fff2f6e584d90588a7
|
|
105
lib/codemp-0.0.5.dist-info/METADATA
Normal file
105
lib/codemp-0.0.5.dist-info/METADATA
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
Metadata-Version: 2.3
|
||||||
|
Name: codemp
|
||||||
|
Version: 0.0.5
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Summary: code multiplexer
|
||||||
|
Keywords: codemp,cooperative,rust,python
|
||||||
|
Home-Page: https://codemp.dev
|
||||||
|
Author: alemi <me@alemi.dev>, zaaarf <me@zaaarf.foo>, frelodev <frelodev@gmail.com>, cschen <cschen@codemp.dev>
|
||||||
|
Author-email: cschen <cschen@codemp.dev>, alemi <me@alemi.dev>, zaaarf <me@zaaarf.foo>, frelodev <frelodev@gmail.com>
|
||||||
|
Maintainer-email: cschen <cschen@codemp.dev>
|
||||||
|
License: GPL-3.0-only
|
||||||
|
Requires-Python: >=3.8
|
||||||
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
||||||
|
Project-URL: repository, https://github.com/hexedtech/codemp.git
|
||||||
|
|
||||||
|
[![codemp](https://codemp.dev/static/banner.png)](https://codemp.dev)
|
||||||
|
|
||||||
|
[![Actions Status](https://github.com/hexedtech/codemp/actions/workflows/ci.yml/badge.svg)](https://github.com/hexedtech/codemp/actions)
|
||||||
|
[![docs.rs](https://img.shields.io/docsrs/codemp)](https://docs.rs/codemp/0.7.0-beta.2/codemp/)
|
||||||
|
[![Crates.io Version](https://img.shields.io/crates/v/codemp)](https://crates.io/crates/codemp)
|
||||||
|
[![NPM Version](https://img.shields.io/npm/v/codemp)](https://npmjs.org/package/codemp)
|
||||||
|
[![PyPI - Version](https://img.shields.io/pypi/v/codemp)](https://pypi.org/project/codemp)
|
||||||
|
[![Crates.io License](https://img.shields.io/crates/l/codemp)](https://github.com/hexedtech/codemp/blob/dev/LICENSE)
|
||||||
|
[![Gitter](https://img.shields.io/gitter/room/hexedtech/codemp)](https://gitter.im/hexedtech/codemp)
|
||||||
|
|
||||||
|
> `codemp` is a **collaborative** text editing solution to work remotely.
|
||||||
|
|
||||||
|
It seamlessly integrates in your editor providing remote cursors and instant text synchronization,
|
||||||
|
as well as a remote virtual workspace for you and your team.
|
||||||
|
|
||||||
|
> `codemp` is build with state-of-the-art CRDT technology, guaranteeing eventual consistency.
|
||||||
|
|
||||||
|
This means everyone in a workspace will always be working on the exact same file _eventually_:
|
||||||
|
even under unreliable networks or constrained resources, the underlying CRDT will always reach a
|
||||||
|
convergent state across all users. Even with this baseline, `codemp`'s protocol is optimized for speed
|
||||||
|
and low network footprint, meaning even slow connections can provide stable real-time editing.
|
||||||
|
|
||||||
|
The full documentation is available on [docs.rs](https://docs.rs/codemp/0.7.0-beta.2/codemp/).
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
`codemp` is primarily used as a plugin in your editor of choice.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The editor plugins are in active development. Expect frequent changes.
|
||||||
|
|
||||||
|
`codemp` is available as a plugin for a growing number of text editors. Currently we support:
|
||||||
|
- [NeoVim](https://github.com/hexedtech/codemp-nvim)
|
||||||
|
- [VSCode](https://github.com/hexedtech/codemp-vscode)
|
||||||
|
- [Sublime Text](https://github.com/hexedtech/codemp-sublime)
|
||||||
|
<!-- - [IntelliJ Platform](https://github.com/hexedtech/codemp-intellij) -->
|
||||||
|
|
||||||
|
## Registration
|
||||||
|
The `codemp` protocol is [openly available](https://github.com/hexedtech/codemp-proto/) and servers may be freely developed with it.
|
||||||
|
|
||||||
|
A reference instance is provided by hexed.technology at [codemp.dev](https://codemp.dev). You may create an account for it [here](https://codemp.dev/register).
|
||||||
|
During the initial closed beta, registrations will require an invite code. Get in contact if interested.
|
||||||
|
|
||||||
|
An open beta is going to follow with free access to a single workspace per user.
|
||||||
|
After such period, [codemp.dev](https://codemp.dev) will switch to a subscription-based model.
|
||||||
|
|
||||||
|
# Development
|
||||||
|
This is the main client library for `codemp`. It provides a batteries-included fully-featured `Client`, managed by the library itself, and exposes a number of functions to interact with it. The host program can obtain a `Client` handle by connecting, and from that reference can retrieve every other necessary component.
|
||||||
|
|
||||||
|
`codemp` is primarily a rlib and can be used as such, but is also available in other languages via FFI.
|
||||||
|
|
||||||
|
Adding a dependency on `codemp` is **easy**:
|
||||||
|
|
||||||
|
### From Rust
|
||||||
|
Just `cargo add codemp` and check the docs for some examples.
|
||||||
|
|
||||||
|
### From supported languages
|
||||||
|
We provide first-class bindings for:
|
||||||
|
- [JavaScript](./dist/js/README.md): available from `npm` as [`codemp`](https://npmjs.org/package/codemp)
|
||||||
|
- [Python](./dist/lua/README.md): available from `PyPI` as [`codemp`](https://pypi.org/project/codemp)
|
||||||
|
- [Lua](./dist/lua/README.md): run `cargo build --features=lua`
|
||||||
|
- [Java](./dist/java/README.md): run `gradle build` in `dist/java/` (requires Gradle)
|
||||||
|
|
||||||
|
As a design philosophy, our binding APIs attempt to perfectly mimic their Rust counterparts, so the main documentation can still be referenced as source of truth.
|
||||||
|
Refer to specific language documentation for specifics, differences and quirks.
|
||||||
|
|
||||||
|
### From other languages
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The common C bindings are not available yet!
|
||||||
|
|
||||||
|
Any other language with C FFI capabilities will be able to use `codemp` via its bare C bindings.
|
||||||
|
This may be more complex and may require wrapping the native calls underneath.
|
||||||
|
|
||||||
|
# Get in Touch
|
||||||
|
We love to hear back from users! Be it to give feedback, propose new features or highlight bugs, don't hesitate to reach out!
|
||||||
|
|
||||||
|
## Contacts
|
||||||
|
We have a public [Gitter](https://gitter.im) room available on [gitter.im/hexedtech/codemp](https://gitter.im/hexedtech/codemp).
|
||||||
|
It's possible to freely browse the room history, but to send new messages it will be necessary to sign in with your GitHub account.
|
||||||
|
|
||||||
|
If you have a [Matrix](https://matrix.org) account, you can join the gitter room directly at [#hexedtech_codemp:gitter.im](https://matrix.to/#/#hexedtech_codemp:gitter.im)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
If you find bugs or would like to see new features implemented, be sure to open an issue on this repository.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> The CLA necessary for code contributions is not yet available!
|
||||||
|
|
||||||
|
In case you wish to contribute code, that's great! We love external contributions, but we require you to sign our CLA first (available soon).
|
||||||
|
|
7
lib/codemp-0.0.5.dist-info/RECORD
Normal file
7
lib/codemp-0.0.5.dist-info/RECORD
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
codemp-0.0.5.dist-info/METADATA,sha256=9Gy6K7EREfjx1ozQv3OQPBhPEqsDphl2uOUzYXO5HXY,5819
|
||||||
|
codemp-0.0.5.dist-info/WHEEL,sha256=Z7z_TcN-SqAJ4k-DAgSbQsbDhIg--F0f-wRIhoPNirs,102
|
||||||
|
codemp/__init__.py,sha256=mu2xQJfcdjBHPYAGe4y3B-O1zKM0O6jqyutzs-XfgsE,107
|
||||||
|
codemp/__init__.pyi,sha256=u_Yx1O12UzHwKtz97pfkT0mYbECDzzPEi8ewSb6yb9g,4155
|
||||||
|
codemp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||||
|
codemp/codemp.abi3.so,sha256=OrEWjqxkDYxY0wN9O7T3Osg8JMvRu3Fj6-vVQFqPgv4,4193664
|
||||||
|
codemp-0.0.5.dist-info/RECORD,,
|
4
lib/codemp-0.0.5.dist-info/WHEEL
Normal file
4
lib/codemp-0.0.5.dist-info/WHEEL
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: maturin (1.7.0)
|
||||||
|
Root-Is-Purelib: false
|
||||||
|
Tag: cp38-abi3-macosx_11_0_arm64
|
5
lib/codemp/__init__.py
Normal file
5
lib/codemp/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from .codemp import *
|
||||||
|
|
||||||
|
__doc__ = codemp.__doc__
|
||||||
|
if hasattr(codemp, "__all__"):
|
||||||
|
__all__ = codemp.__all__
|
124
lib/codemp/__init__.pyi
Normal file
124
lib/codemp/__init__.pyi
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
from typing import Tuple, Optional, Callable
|
||||||
|
|
||||||
|
class Driver:
|
||||||
|
"""
|
||||||
|
this is akin to a big red button with a white "STOP" on top of it.
|
||||||
|
it is used to stop the runtime.
|
||||||
|
"""
|
||||||
|
def stop(self) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
def init() -> Driver: ...
|
||||||
|
def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ...
|
||||||
|
def connect(host: str, username: str, password: str) -> Promise[Client]: ...
|
||||||
|
|
||||||
|
class Promise[T]:
|
||||||
|
"""
|
||||||
|
This is a class akin to a future, which wraps a join handle from a spawned
|
||||||
|
task on the rust side. you may call .pyawait() on this promise to block
|
||||||
|
until we have a result, or return immediately if we already have one.
|
||||||
|
This only goes one way rust -> python.
|
||||||
|
|
||||||
|
It can either be used directly or you can wrap it inside a future python side.
|
||||||
|
"""
|
||||||
|
def wait(self) -> T: ...
|
||||||
|
def is_done(self) -> bool: ...
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
"""
|
||||||
|
Handle to the actual client that manages the session. It manages the connection
|
||||||
|
to a server and joining/creating new workspaces
|
||||||
|
"""
|
||||||
|
def join_workspace(self, workspace: str) -> Promise[Workspace]: ...
|
||||||
|
def create_workspace(self, workspace: str) -> Promise[None]: ...
|
||||||
|
def delete_workspace(self, workspace: str) -> Promise[None]: ...
|
||||||
|
def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ...
|
||||||
|
def list_workspaces(self, owned: bool, invited: bool) -> Promise[list[str]]: ...
|
||||||
|
def leave_workspace(self, workspace: str) -> bool: ...
|
||||||
|
def get_workspace(self, id: str) -> Workspace: ...
|
||||||
|
def active_workspaces(self) -> list[str]: ...
|
||||||
|
def user_id(self) -> str: ...
|
||||||
|
def user_name(self) -> str: ...
|
||||||
|
def refresh(self) -> Promise[None]: ...
|
||||||
|
|
||||||
|
class Workspace:
|
||||||
|
"""
|
||||||
|
Handle to a workspace inside codemp. It manages buffers.
|
||||||
|
A cursor is tied to the single workspace.
|
||||||
|
"""
|
||||||
|
def create(self, path: str) -> Promise[None]: ...
|
||||||
|
def attach(self, path: str) -> Promise[BufferController]: ...
|
||||||
|
def detach(self, path: str) -> bool: ...
|
||||||
|
def fetch_buffers(self) -> Promise[None]: ...
|
||||||
|
def fetch_users(self) -> Promise[None]: ...
|
||||||
|
def list_buffer_users(self, path: str) -> Promise[list[str]]: ...
|
||||||
|
def delete(self, path: str) -> Promise[None]: ...
|
||||||
|
def id(self) -> str: ...
|
||||||
|
def cursor(self) -> CursorController: ...
|
||||||
|
def buffer_by_name(self, path: str) -> Optional[BufferController]: ...
|
||||||
|
def buffer_list(self) -> list[str]: ...
|
||||||
|
def filetree(self, filter: Optional[str]) -> list[str]: ...
|
||||||
|
|
||||||
|
class TextChange:
|
||||||
|
"""
|
||||||
|
Editor agnostic representation of a text change, it translate between internal
|
||||||
|
codemp text operations and editor operations
|
||||||
|
"""
|
||||||
|
start: int
|
||||||
|
end: int
|
||||||
|
content: str
|
||||||
|
|
||||||
|
def is_delete(self) -> bool: ...
|
||||||
|
def is_insert(self) -> bool: ...
|
||||||
|
def is_empty(self) -> bool: ...
|
||||||
|
def apply(self, txt: str) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
|
class BufferController:
|
||||||
|
"""
|
||||||
|
Handle to the controller for a specific buffer, which manages the back and forth
|
||||||
|
of operations to and from other peers.
|
||||||
|
"""
|
||||||
|
def path(self) -> str: ...
|
||||||
|
def content(self) -> Promise[str]: ...
|
||||||
|
def send(self,
|
||||||
|
start: int,
|
||||||
|
end: int,
|
||||||
|
txt: str) -> Promise[None]: ...
|
||||||
|
def try_recv(self) -> Promise[Optional[TextChange]]: ...
|
||||||
|
def recv(self) -> Promise[TextChange]: ...
|
||||||
|
def poll(self) -> Promise[None]: ...
|
||||||
|
def callback(self,
|
||||||
|
cb: Callable[[BufferController], None]) -> None: ...
|
||||||
|
def clear_callback(self) -> None: ...
|
||||||
|
def stop(self) -> bool: ...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Cursor:
|
||||||
|
"""
|
||||||
|
An Editor agnostic cursor position representation
|
||||||
|
"""
|
||||||
|
start: Tuple[int, int]
|
||||||
|
end: Tuple[int, int]
|
||||||
|
buffer: str
|
||||||
|
user: Optional[str] # can be an empty string
|
||||||
|
|
||||||
|
|
||||||
|
class CursorController:
|
||||||
|
"""
|
||||||
|
Handle to the controller for a workspace, which manages the back and forth of
|
||||||
|
cursor movements to and from other peers
|
||||||
|
"""
|
||||||
|
def send(self,
|
||||||
|
path: str,
|
||||||
|
start: Tuple[int, int],
|
||||||
|
end: Tuple[int, int]) -> Promise[None]: ...
|
||||||
|
def try_recv(self) -> Promise[Optional[Cursor]]: ...
|
||||||
|
def recv(self) -> Promise[Cursor]: ...
|
||||||
|
def poll(self) -> Promise[None]: ...
|
||||||
|
def callback(self,
|
||||||
|
cb: Callable[[CursorController], None]) -> None: ...
|
||||||
|
def clear_callback(self) -> None: ...
|
||||||
|
def stop(self) -> bool: ...
|
||||||
|
|
1
lib/codemp/codemp.abi3.so.REMOVED.git-id
Normal file
1
lib/codemp/codemp.abi3.so.REMOVED.git-id
Normal file
|
@ -0,0 +1 @@
|
||||||
|
7145849af30523094153d307d57c79bb7a90680f
|
0
lib/codemp/py.typed
Normal file
0
lib/codemp/py.typed
Normal file
|
@ -5,10 +5,10 @@ import logging
|
||||||
import random
|
import random
|
||||||
from typing import Tuple, Union
|
from typing import Tuple, Union
|
||||||
|
|
||||||
from Codemp.src.client import client
|
from .src.client import client
|
||||||
from Codemp.src.utils import safe_listener_detach
|
from .src.utils import safe_listener_detach
|
||||||
from Codemp.src.utils import safe_listener_attach
|
from .src.utils import safe_listener_attach
|
||||||
from Codemp.src import globals as g
|
from .src import globals as g
|
||||||
|
|
||||||
LOG_LEVEL = logging.DEBUG
|
LOG_LEVEL = logging.DEBUG
|
||||||
handler = logging.StreamHandler()
|
handler = logging.StreamHandler()
|
||||||
|
|
|
@ -4,9 +4,9 @@ import sublime
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import codemp
|
from . import globals as g
|
||||||
from Codemp.src import globals as g
|
from .utils import populate_view, safe_listener_attach, safe_listener_detach
|
||||||
from Codemp.src.utils import populate_view, safe_listener_attach, safe_listener_detach
|
from ..lib import codemp
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,10 @@ from typing import Optional
|
||||||
import sublime
|
import sublime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import codemp
|
from ..lib import codemp
|
||||||
from Codemp.src import globals as g
|
from .workspace import VirtualWorkspace
|
||||||
from Codemp.src.workspace import VirtualWorkspace
|
from .buffers import VirtualBuffer
|
||||||
from Codemp.src.buffers import VirtualBuffer
|
from .utils import bidict
|
||||||
from Codemp.src.utils import bidict
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
from typing import Optional, Callable, Any
|
|
||||||
|
|
||||||
import sublime
|
|
||||||
import logging
|
|
||||||
import asyncio
|
|
||||||
import threading
|
|
||||||
import concurrent.futures
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class sublimeWorkerThreadExecutor(concurrent.futures.Executor):
|
|
||||||
def __init__(self):
|
|
||||||
self._futures_pending = 0
|
|
||||||
self._shutting_down = False
|
|
||||||
|
|
||||||
# reentrant lock: we either increment from the main thread (submit calls)
|
|
||||||
# or we decrement from the worker thread (futures)
|
|
||||||
self._condvar = threading.Condition()
|
|
||||||
|
|
||||||
def submit(
|
|
||||||
self, fn: Callable[..., Any], *args: Any, **kwargs: Any
|
|
||||||
) -> concurrent.futures.Future:
|
|
||||||
if self._shutting_down:
|
|
||||||
raise RuntimeError("Executor is shutting down")
|
|
||||||
|
|
||||||
with self._condvar:
|
|
||||||
self._futures_pending += 1
|
|
||||||
|
|
||||||
logger.debug("Spawning a future in the main thread")
|
|
||||||
future = concurrent.futures.Future()
|
|
||||||
|
|
||||||
def coro() -> None:
|
|
||||||
logger.debug("Running a future from the worker thread")
|
|
||||||
try:
|
|
||||||
future.set_result(fn(*args, **kwargs))
|
|
||||||
except BaseException as e:
|
|
||||||
future.set_exception(e)
|
|
||||||
with self._condvar:
|
|
||||||
self._futures_pending -= 1
|
|
||||||
|
|
||||||
sublime.set_timeout_async(coro)
|
|
||||||
return future
|
|
||||||
|
|
||||||
def shutdown(self, wait: bool = True) -> None:
|
|
||||||
self._shutting_down = True
|
|
||||||
if not wait:
|
|
||||||
return
|
|
||||||
|
|
||||||
with self._condvar:
|
|
||||||
self._condvar.wait_for(lambda: self._futures_pending == 0)
|
|
||||||
|
|
||||||
|
|
||||||
class Runtime:
|
|
||||||
def __init__(self):
|
|
||||||
self.tasks = []
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
self.loop.set_default_executor(sublimeWorkerThreadExecutor())
|
|
||||||
self.loop.set_debug(True)
|
|
||||||
self.thread = threading.Thread(
|
|
||||||
target=self.loop.run_forever, name="codemp-asyncio-loop"
|
|
||||||
)
|
|
||||||
logger.debug("spinning up even loop in its own thread.")
|
|
||||||
self.thread.start()
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
logger.debug("closing down the event loop.")
|
|
||||||
for task in asyncio.all_tasks(self.loop):
|
|
||||||
task.cancel()
|
|
||||||
|
|
||||||
self.stop_loop()
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Unexpected crash while shutting down event loop: {e}")
|
|
||||||
|
|
||||||
self.thread.join()
|
|
||||||
|
|
||||||
def stop_loop(self):
|
|
||||||
logger.debug("stopping event loop.")
|
|
||||||
self.loop.call_soon_threadsafe(lambda: asyncio.get_running_loop().stop())
|
|
||||||
|
|
||||||
def run_blocking(self, fut, *args, **kwargs):
|
|
||||||
return self.loop.run_in_executor(None, fut, *args, **kwargs)
|
|
||||||
|
|
||||||
def dispatch(self, coro, name=None):
|
|
||||||
"""
|
|
||||||
Dispatch a task on the event loop and returns the task itself.
|
|
||||||
Similar to `run_coroutine_threadsafe` but returns the
|
|
||||||
actual task running and not the result of the coroutine.
|
|
||||||
|
|
||||||
`run_coroutine_threadsafe` returns a concurrent.futures.Future
|
|
||||||
which has a blocking .result so not really suited for long running
|
|
||||||
coroutines
|
|
||||||
"""
|
|
||||||
logger.debug("dispatching coroutine...")
|
|
||||||
|
|
||||||
def make_task(fut):
|
|
||||||
logger.debug("creating task on the loop.")
|
|
||||||
try:
|
|
||||||
fut.set_result(self.loop.create_task(coro))
|
|
||||||
except Exception as e:
|
|
||||||
fut.set_exception(e)
|
|
||||||
|
|
||||||
# create the future to populate with the task
|
|
||||||
# we use the concurrent.futures.Future since it is thread safe
|
|
||||||
# and the .result() call is blocking.
|
|
||||||
fut = concurrent.futures.Future()
|
|
||||||
self.loop.call_soon_threadsafe(make_task, fut)
|
|
||||||
task = fut.result(None) # wait for the task to be created
|
|
||||||
task.set_name(name)
|
|
||||||
self.tasks.append(task) # save the reference
|
|
||||||
return task
|
|
||||||
|
|
||||||
def block_on(self, coro, timeout=None):
|
|
||||||
fut = asyncio.run_coroutine_threadsafe(coro, self.loop)
|
|
||||||
try:
|
|
||||||
return fut.result(timeout)
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
logger.debug("future got cancelled.")
|
|
||||||
raise
|
|
||||||
except TimeoutError:
|
|
||||||
logger.debug("future took too long to finish.")
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def get_task(self, name) -> Optional[asyncio.Task]:
|
|
||||||
return next((t for t in self.tasks if t.get_name() == name), None)
|
|
||||||
|
|
||||||
def stop_task(self, name):
|
|
||||||
task = self.get_task(name)
|
|
||||||
if task is not None:
|
|
||||||
self.dispatch(self.wait_for_cancel(task))
|
|
||||||
|
|
||||||
async def wait_for_cancel(self, task):
|
|
||||||
task.cancel() # cancelling a task, merely requests a cancellation.
|
|
||||||
try:
|
|
||||||
await task
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# store a global in the module so it acts as a singleton
|
|
||||||
# (modules are loaded only once)
|
|
||||||
# rt = Runtime()
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sublime
|
import sublime
|
||||||
import sublime_plugin
|
import sublime_plugin
|
||||||
from typing import Dict, Generic, TypeVar
|
from typing import Dict, Generic, TypeVar
|
||||||
from Codemp.src import globals as g
|
from . import globals as g
|
||||||
|
|
||||||
# bidirectional dictionary so that we can have bidirectional
|
# bidirectional dictionary so that we can have bidirectional
|
||||||
# lookup!
|
# lookup!
|
||||||
|
|
|
@ -6,12 +6,10 @@ import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import codemp
|
from ..lib import codemp
|
||||||
from Codemp.src import globals as g
|
from . import globals as g
|
||||||
from Codemp.src.buffers import VirtualBuffer
|
from .buffers import VirtualBuffer
|
||||||
from Codemp.src.utils import draw_cursor_region, safe_listener_attach, sublime_plugin
|
from .utils import draw_cursor_region, sublime_plugin
|
||||||
from Codemp.src.utils import bidict
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue