diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e33a63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.dev/ +__pycache__/ +*.swp diff --git a/sqle/__init__.py b/sqle/__init__.py new file mode 100644 index 0000000..9c49fad --- /dev/null +++ b/sqle/__init__.py @@ -0,0 +1,3 @@ + +# TODO + diff --git a/sqle/__main__.py b/sqle/__main__.py new file mode 100644 index 0000000..f552d54 --- /dev/null +++ b/sqle/__main__.py @@ -0,0 +1,10 @@ +from imgui_bundle import imgui, imgui_ctx, immapp + +import sqle.win + +term = sqle.win.Terminal() + +immapp.run( + window_title = "SQLE", + gui_function = lambda: term.gui(), +) diff --git a/sqle/utl/__init__.py b/sqle/utl/__init__.py new file mode 100644 index 0000000..2d3dcd1 --- /dev/null +++ b/sqle/utl/__init__.py @@ -0,0 +1 @@ +from .future import Future, Promise diff --git a/sqle/utl/future.py b/sqle/utl/future.py new file mode 100644 index 0000000..04f989b --- /dev/null +++ b/sqle/utl/future.py @@ -0,0 +1,26 @@ +from typing import Generic, TypeVar +from threading import Event + +T = TypeVar("T") + +class Future(Generic[T]): + _event: Event = Event() + _data : T|None = None + + def get(self) -> T|None: + return self._data if self.filled() else None + + def filled(self) -> bool: + return self._event.is_set() + +class Promise(Future[T]): + def fill(self, data: T): + self._data = data + self._event.set() + return self + +def is_filled(fut: Future[T]|None): + return fut.filled() if fut is not None else False + +def is_filling(fut: Future[T]|None): + return (not fut.filled()) if fut is not None else False diff --git a/sqle/win/__init__.py b/sqle/win/__init__.py new file mode 100644 index 0000000..a3b7b08 --- /dev/null +++ b/sqle/win/__init__.py @@ -0,0 +1 @@ +from .terminal import Terminal diff --git a/sqle/win/terminal.py b/sqle/win/terminal.py new file mode 100644 index 0000000..26bd1f0 --- /dev/null +++ b/sqle/win/terminal.py @@ -0,0 +1,44 @@ +from imgui_bundle import imgui, imgui_ctx +from abc import ABCMeta, abstractmethod + +from sqle.utl.future import Future, Promise, is_filling, is_filled + + +class Terminal: + def __init__(self): + self._sql = "" + self._io = _IO() + + self._req_sql = None + self._req_fut = None + + def gui(self) -> None: + with imgui_ctx.begin("my first window"): + modified, self._sql = imgui.input_text( + "##sql", + self._sql, + ) + + if imgui.is_item_deactivated_after_edit(): + accept_enter = (self._req_sql != self._sql) or (not is_filling(self._req_fut)) + if accept_enter: + # TODO: abort prev future + self._req_fut = self._io.try_exec(self._sql) + + if is_filled(self._req_fut): + msg = self._req_fut.get() + imgui.text(msg if msg is not None else "OK") + + # TODO: display table + +# an interface the Terminal window wants for handling SQL +class IO(metaclass = ABCMeta): + @abstractmethod + def try_exec(self, sql: str) -> Promise[str|None]: # TODO: return also SQL result + pass + +# an impl of IO for testing +class _IO(IO): + def try_exec(self, sql): + print("exec: "+sql) + return Promise().fill(None)