tmontes / ppytty Goto Github PK
View Code? Open in Web Editor NEWWIP: Present Python on a TTY
License: MIT License
WIP: Present Python on a TTY
License: MIT License
Objective:
yield
s from Task.run
.yield from
/ await
API wrapping functions / methods.Benefits:
Possibilities:
kernel.api
module with one function per trap.Task
corresponding to kernel traps.General idea:
More:
More thoughts (copied from later comment to be accounted in issue progress):
More thoughts (copied from later comment to be accounted in issue progress):
message-send
/ message-wait
?IMPORTANT:
hw.py
module. (see #103).
Identified in #77:
Possibility:
(<tag>, <data>)
: I/O obtained data is tagged with None
.Rough Idea:
(as a continuation of #41)
Ideas:
Status quo:
Idea:
Window.render
could take an optional alpha_bg
defaulting to 1.0
.alpha_bg
is less than that, the window background would be rendered as an interpolation of its color and the color of whatever is beneath it (the terminal background and/or other windows).Challenges:
Notes:
Ideas:
window-render
trap to be told that or the kernel to somehow remember rendered window position, detecting such changes.Hand tested scenario:
/bin/bash
and sys.executable
for a Python REPL.Tested systems:
Test procedure:
word word word word
the edit the line with cursor movement (emacs and vi keybindings). . (fixed in PR #112)
KeyboardInterrupt
should be displayed. Focus and visible should still be in the bash shell!Test results matrix:
Test | macOS | raspbian | Ubuntu |
---|---|---|---|
Python CTRL-C | ok | no effect | no effect |
Python Space/Back | space ok, back not ok [1] | ok | ok |
bash CTRL-C | ok | ok, ^C echoed |
ok, ^C echoed |
bash Space/back | ok | ok | ok |
Python line edits | no visual cursor moves | no visual cursor moves | no visual cursor moves |
bash line edits | no visual cursor moves | no visual cursor moves | no visual cursor moves |
[1] Cursor position is actually tracked and the next "visible" input is be properly positioned as well as the cursor, which is also correctly updated.
Interesting... Needs more investigation.
Identified while working on #5.
Real calls: os.read
, os.write
, os.close
, os.pipe
, signal.signal
, fcntl.*
, and maybe more.
Note:
Original idea in #5.
Sub-issue of #36.
Objective:
sleep
, read-key
and task-wait
-- should no longer block.message-send
the task a message tuple (request id, trap result).None
.With this, instead of:
def task():
yield ('sleep', 5) # Blocks for 5 seconds
...the following code should be used:
def task():
request_id = yield ('sleep', 5) # Does not block
sender, message = yield ('message-wait',) # This blocks until we get a message
assert sender is None
msg_request_id, sleep_result = message
assert msg_request_id == request_id
# discard sleep_result, not useful
Pros:
Possible message-wait
Improvement:
termios.TIOCSWINSZ
update to properly reflect the new terminal geometry.It should have two sub-packages:
kernel
lib
The last one may, in turn, have other sub-packages -- we'll see about that once we get there.
Summary:
task-wait
and message-wait
return, among other things, a reference to a task.task-spawn
.Motive:
Failing example:
def child():
yield ('sleep',)
def parent():
yield ('task-spawn', child)
completed_task, success, result = yield ('task-wait',)
# This fails because completed_task is actually the generator object obtained by calling
assert completed_task is childchild
Possible solutions:
run
/task-spawn
) to be a generator object or alike.Let's sleep on this for a while.
Random thoughts:
default
terminal, associated to stdin/stdout.terminal-create
would create and initialise a new terminal.terminal-destroy
... But implementation should be simple.direct-print
and direct-clear
traps would become methods on the terminal object.default
terminal).read-key
could also be associated to a terminal.ppytty
entry point script such that they would be automatically created and initialised, being ready to to use by driven tasks/presentations.More notes:
Possible uses:
Related to #7, somehow.
Notes:
pyte.Screen
needs to be resized.This scheduling limitation should now be easy to address, after the keyboard input revamp in #79.
Current status:
Wishlist:
Status quo:
Crazy idea:
What this would allow:
Thoughts on implementation:
Window.render
method should not be very difficult to update.window_render
trap will probably be much more complex.Sub-issue of #36.
trap | arguments | blocks? | notes |
---|---|---|---|
message-send |
task, message | no | if task is None message is sent to the parent task |
message-wait |
- | yes | returns (sender task, message) tuple |
Notes:
Status quo:
Idea:
Window.render
could take an alpha_fg
argument, defaulting to 1.0
, meaning behave as status quo.alpha_fg
, the foreground colours would be "interpolated" to the background.Challenges:
Possible compromises:
Notes on having state as a module:
Wishlist:
state
is not that great...Original idea in #5.
Notes from there:
Original idea in #5.
...or the exception object, if the top task raises one.
It currently goes completely wild!
One possibility:
dump-state
trap.Notes:
(that's it, nothing else to say)
...leave that to main, as a default.
Thoughts:
Notes on concurrent reads:
Steps to reproduce:
Example:
+-----------------------------------+
| text editor process with focus |
| |
| +-----------------------+
| move the | top window |
| text editor | |
| here - - - -|- - -> [] |
| | |
+------------------| |
| |
+-----------------------+
Options:
__init__
to have a new cursor
argument, defaulting to False
.cursor_visible
with a visible
argument, defaulting to True
.Idea:
Driving idea:
Extra craziness:
...no instance is actually necessary.
Existing traps:
Trap | Blocks? | Notes |
---|---|---|
direct-clear |
No | Direct terminal output. |
direct-print |
No | Direct terminal output. |
window-create |
No | Create and return a Window. |
window-render |
No | Update terminal output. |
window-destroy |
No | Destroy Window and update terminal output. |
sleep |
Yes | Return after N seconds. |
read-key |
Yes | Return byte corresponding to terminal input. |
put-key |
No | Pushback byte to other read-key waiting tasks. |
task-spawn |
No | Create a child Task. |
task-destroy |
No | Destroy child Task and all of its children. |
task-wait |
Yes | Wait for any child Task completion. |
dump-state |
No | Logs kernel state. |
Future library design seems to indicate the need for one or more kernel traps to support inter-task communication. This will lead to, at least, one more trap that blocks the calling task (assuming a simple message-send
/ message-receive
like trap pair).
This type of design, while somewhat intuitive, leads to an unnecessary limitation. Waiting/blocking on multiple things:
All Tasks will have an INBOX, where they receive messages.
There will be two new kernel traps to support inter-task communication:
message-send
: sends a message (any object) to another Task, does not block.message-wait
: returns the 1st message in the INBOX, or blocks until there is one.
(<sender>, <value>)
tuple where <sender>
will be the sender Task or None
if the message is originated from the kernel.Inter-task communication:
message-send
takes two arguments: the destination Task and the message.
None
as the destination Task (or some TBD constant).About waiting for multiple things simultaneously:
sleep
, read-key
and task-wait
will no longer block: they will return some kind of "request id" the caller must track.message-wait
to confirm their completion: the kernel will send a message to the task once any of the pending requests is completed. Such message will itself be a (<request-id>, <result>)
so that the waiting task knows what completed.Simpler, blocking variations of the traps can be implemented at a library level.
Will certainly need adjustments, but I like the idea of "async traps" and a single "blocking trap" a lot.
Broken down this issue into:
Given the initially chaotic exploration, many (variable, function, class) names are either not very good or completely misleading now. Let's improve that:
_PlayerStop
exception, it no longer makes sense.state.running
should be state.runnable
.Not sure if it should be handled by the kernel of the lib... (maybe the kernel as it may simplify handling automatic output terminal resizes).
Ideas:
x
and y
.int
values correspond to zero-based, absolute terminal coordinates.int
values correspond to "from-right/bottom" absolute terminal coordinates, where -1
corresponds to the last "column/row".float
values correspond to zero-based, relative terminal coordinates where 1.0
is the first "column/row" after the visible ones.float
values correspond to "from-right/bottom" relative terminal coordinates, where -1.0
is the first "column/row" before the visible ones.w
and h
.int
values correspond to absolute terminal "rows/columns".float
values correspond to sizes relative to the terminal geometry with 1.0
represents the full width/height of the terminal.May be of use:
dx
, dy
, dw
and dh
to somehow manage margins.Examples:
w = Window(x=0, y=0, w=1.0, h=1.0)
.w = Window(x=0, y=0, w=1.0, h=1.0, dx=1, dy=1, dw=-2, dh=-2)
w1, w2 = Window(x=0, y=0, w=0.5, h=1.0), Window(x=0.5, y=0, w=0.5, h=1.0)
(may need dx
/dw
adjustments to ensure there is no overlap?)That's the general idea.
Fact:
task.throw(trap_result)
to throw exceptions into running tasks.trap_result
is set to an exception class via common.trap_will_throw
.Why:
help(generator.throw)
says first argument is exception type, optional second is exception args.Given this:
def f1():
yield 1
Both of these approaches similarly:
r1 = f1()
r1.throw(RuntimeError, 'argument')
r2 = f1()
r2.throw(RuntimeError('argument'))
Given the non 100% clear docs, not even here I went checking CPython's source code where I found:
481 if (PyExceptionClass_Check(typ))
482 PyErr_NormalizeException(&typ, &val, &tb);
483
484 else if (PyExceptionInstance_Check(typ)) {
485 /* Raising an instance. The value should be a dummy. */
486 if (val && val != Py_None) {
487 PyErr_SetString(PyExc_TypeError,
488 "instance exception may not have a separate value");
489 goto failed_throw;
490 }
...this confirms that exception instances can indeed be raised -- the docs need fixing (I should file a bug)
With this, calls to common.trap_will_throw
can be given an exception instance with useful arguments such as, for example, the trap name for TrapDoesNotExist
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.