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.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:
Original idea in #5.
Notes on having state as a module:
Wishlist:
state
is not that great...Original idea in #5.
It currently goes completely wild!
Steps to reproduce:
Example:
+-----------------------------------+
| text editor process with focus |
| |
| +-----------------------+
| move the | top window |
| text editor | |
| here - - - -|- - -> [] |
| | |
+------------------| |
| |
+-----------------------+
This scheduling limitation should now be easy to address, after the keyboard input revamp in #79.
Options:
__init__
to have a new cursor
argument, defaulting to False
.cursor_visible
with a visible
argument, defaulting to True
....no instance is actually necessary.
(that's it, nothing else to say)
Original idea in #5.
Notes from there:
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:
Rough Idea:
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.
Related to #7, somehow.
Notes:
pyte.Screen
needs to be resized.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:
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:
termios.TIOCSWINSZ
update to properly reflect the new terminal geometry.Current status:
Wishlist:
One possibility:
dump-state
trap.Notes:
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
.
...or the exception object, if the top task raises one.
Idea:
Driving idea:
Extra craziness:
Possible uses:
Thoughts:
Notes on concurrent reads:
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.Ideas:
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:
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:
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
.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:
Notes:
Ideas:
window-render
trap to be told that or the kernel to somehow remember rendered window position, detecting such changes.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.
(as a continuation of #41)
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).
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.
Identified in #77:
Possibility:
(<tag>, <data>)
: I/O obtained data is tagged with None
....leave that to main, as a default.
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.