term library added

This commit is contained in:
Thakee Nathees 2022-05-27 18:20:46 +05:30
parent 052f1e263e
commit da6105d46c
9 changed files with 1754 additions and 22 deletions

View File

@ -485,12 +485,6 @@ struct Compiler {
// such assignments. // such assignments.
bool can_define; bool can_define;
// This value will set to true for parsing a temproary expression
// (ie. if <expr> ...) and the value of the expression will be popped out of
// the stack onece we're done, if it's a defenition, that value should be
// duplicated on the stack to prevent it.
bool expr_temp;
// This value will be true after parsing a call expression, for every other // This value will be true after parsing a call expression, for every other
// Expressions it'll be false. This is **ONLY** to be used when compiling a // Expressions it'll be false. This is **ONLY** to be used when compiling a
// return statement to check if the last parsed expression is a call to // return statement to check if the last parsed expression is a call to
@ -1896,13 +1890,10 @@ static void exprInterpolation(Compiler* compiler) {
static void exprFunction(Compiler* compiler) { static void exprFunction(Compiler* compiler) {
bool can_define = compiler->can_define; bool can_define = compiler->can_define;
bool expr_temp = compiler->expr_temp;
compiler->can_define = true; compiler->can_define = true;
compiler->expr_temp = false;
compileFunction(compiler, FUNC_LITERAL); compileFunction(compiler, FUNC_LITERAL);
compiler->can_define = can_define; compiler->can_define = can_define;
compiler->expr_temp = expr_temp;
} }
static void exprName(Compiler* compiler) { static void exprName(Compiler* compiler) {
@ -1994,10 +1985,6 @@ static void exprName(Compiler* compiler) {
ASSERT(compiler->parser.has_errors || ASSERT(compiler->parser.has_errors ||
(compiler->func->stack_size - 1) == index, OOPS); (compiler->func->stack_size - 1) == index, OOPS);
if (compiler->expr_temp) {
emitOpcode(compiler, OP_DUP);
}
} else { } else {
// The assigned value or the result of the operator will be at the top of // The assigned value or the result of the operator will be at the top of
// the stack by now. Store it. // the stack by now. Store it.
@ -3087,10 +3074,10 @@ static void compileIfStatement(Compiler* compiler, bool elif) {
skipNewLines(compiler); skipNewLines(compiler);
bool expr_temp = compiler->expr_temp; bool can_define = compiler->can_define;
compiler->expr_temp = true; compiler->can_define = false;
compileExpression(compiler); //< Condition. compileExpression(compiler); //< Condition.
compiler->expr_temp = expr_temp; compiler->can_define = can_define;
emitOpcode(compiler, OP_JUMP_IF_NOT); emitOpcode(compiler, OP_JUMP_IF_NOT);
int ifpatch = emitShort(compiler, 0xffff); //< Will be patched. int ifpatch = emitShort(compiler, 0xffff); //< Will be patched.
@ -3140,10 +3127,10 @@ static void compileWhileStatement(Compiler* compiler) {
loop.depth = compiler->scope_depth; loop.depth = compiler->scope_depth;
compiler->loop = &loop; compiler->loop = &loop;
bool expr_temp = compiler->expr_temp; bool can_define = compiler->can_define;
compiler->expr_temp = true; compiler->can_define = false;
compileExpression(compiler); //< Condition. compileExpression(compiler); //< Condition.
compiler->expr_temp = expr_temp; compiler->can_define = can_define;
emitOpcode(compiler, OP_JUMP_IF_NOT); emitOpcode(compiler, OP_JUMP_IF_NOT);
int whilepatch = emitShort(compiler, 0xffff); //< Will be patched. int whilepatch = emitShort(compiler, 0xffff); //< Will be patched.
@ -3176,10 +3163,10 @@ static void compileForStatement(Compiler* compiler) {
// Compile and store sequence. // Compile and store sequence.
compilerAddVariable(compiler, "@Sequence", 9, iter_line); // Sequence compilerAddVariable(compiler, "@Sequence", 9, iter_line); // Sequence
bool expr_temp = compiler->expr_temp; bool can_define = compiler->can_define;
compiler->expr_temp = true; compiler->can_define = false;
compileExpression(compiler); compileExpression(compiler);
compiler->expr_temp = expr_temp; compiler->can_define = can_define;
// Add iterator to locals. It's an increasing integer indicating that the // Add iterator to locals. It's an increasing integer indicating that the
// current loop is nth starting from 0. // current loop is nth starting from 0.

259
src/libs/ext_term.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef PK_AMALGAMATED
#include "libs.h"
#endif
#define TERM_IMPLEMENT
#include "thirdparty/term/term.h" //<< AMALG_INLINE >>
#undef TERM_IMPLEMENT
// A reference to the event class, to check is instance of.
static PkHandle* _cls_term_event = NULL;
static void _setSlotVector(PKVM* vm, int slot, int tmp, double x, double y) {
if (!pkImportModule(vm, "types", slot)) return;
if (!pkGetAttribute(vm, slot, "Vector", slot)) return;
if (!pkNewInstance(vm, slot, slot, 0, 0)) return;
pkSetSlotNumber(vm, tmp, x);
if (!pkSetAttribute(vm, slot, "x", tmp)) return;
pkSetSlotNumber(vm, tmp, y);
if (!pkSetAttribute(vm, slot, "y", tmp)) return;
}
void* _termEventNew(PKVM* vm) {
term_Event* event = pkRealloc(vm, NULL, sizeof(term_Event));
event->type = TERM_ET_UNKNOWN;
return event;
}
void _termEventDelete(PKVM* vm, void* event) {
pkRealloc(vm, event, 0);
}
void _termEventGetter(PKVM* vm) {
const char* name;
if (!pkValidateSlotString(vm, 1, &name, NULL)) return;
term_Event* event = pkGetSelf(vm);
if (strcmp(name, "type") == 0) {
pkSetSlotNumber(vm, 0, (double)event->type);
} else if (strcmp(name, "keycode") == 0) {
pkSetSlotNumber(vm, 0, (double)event->key.code);
} else if (strcmp(name, "ascii") == 0) {
pkSetSlotNumber(vm, 0, (double)event->key.ascii);
} else if (strcmp(name, "modifiers") == 0) {
if (event->type == TERM_ET_KEY_DOWN) {
pkSetSlotNumber(vm, 0, (double)event->key.modifiers);
} else {
pkSetSlotNumber(vm, 0, (double)event->mouse.modifiers);
}
} else if (strcmp(name, "button") == 0) {
pkSetSlotNumber(vm, 0, (double)event->mouse.button);
} else if (strcmp(name, "pos") == 0) {
pkReserveSlots(vm, 2);
_setSlotVector(vm, 0, 1, event->mouse.pos.x, event->mouse.pos.y);
} else if (strcmp(name, "scroll") == 0) {
pkSetSlotBool(vm, 0, event->mouse.scroll);
}
}
void _registerEnums(PKVM* vm, PkHandle* term) {
pkReserveSlots(vm, 1);
pkSetSlotHandle(vm, 0, term);
pkSetSlotNumber(vm, 1, TERM_KEY_UNKNOWN); pkSetAttribute(vm, 0, "KEY_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_0); pkSetAttribute(vm, 0, "KEY_0", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_1); pkSetAttribute(vm, 0, "KEY_1", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_2); pkSetAttribute(vm, 0, "KEY_2", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_3); pkSetAttribute(vm, 0, "KEY_3", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_4); pkSetAttribute(vm, 0, "KEY_4", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_5); pkSetAttribute(vm, 0, "KEY_5", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_6); pkSetAttribute(vm, 0, "KEY_6", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_7); pkSetAttribute(vm, 0, "KEY_7", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_8); pkSetAttribute(vm, 0, "KEY_8", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_9); pkSetAttribute(vm, 0, "KEY_9", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_A); pkSetAttribute(vm, 0, "KEY_A", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_B); pkSetAttribute(vm, 0, "KEY_B", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_C); pkSetAttribute(vm, 0, "KEY_C", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_D); pkSetAttribute(vm, 0, "KEY_D", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_E); pkSetAttribute(vm, 0, "KEY_E", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F); pkSetAttribute(vm, 0, "KEY_F", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_G); pkSetAttribute(vm, 0, "KEY_G", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_H); pkSetAttribute(vm, 0, "KEY_H", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_I); pkSetAttribute(vm, 0, "KEY_I", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_J); pkSetAttribute(vm, 0, "KEY_J", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_K); pkSetAttribute(vm, 0, "KEY_K", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_L); pkSetAttribute(vm, 0, "KEY_L", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_M); pkSetAttribute(vm, 0, "KEY_M", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_N); pkSetAttribute(vm, 0, "KEY_N", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_O); pkSetAttribute(vm, 0, "KEY_O", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_P); pkSetAttribute(vm, 0, "KEY_P", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Q); pkSetAttribute(vm, 0, "KEY_Q", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_R); pkSetAttribute(vm, 0, "KEY_R", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_S); pkSetAttribute(vm, 0, "KEY_S", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_T); pkSetAttribute(vm, 0, "KEY_T", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_U); pkSetAttribute(vm, 0, "KEY_U", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_V); pkSetAttribute(vm, 0, "KEY_V", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_W); pkSetAttribute(vm, 0, "KEY_W", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_X); pkSetAttribute(vm, 0, "KEY_X", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Y); pkSetAttribute(vm, 0, "KEY_Y", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_Z); pkSetAttribute(vm, 0, "KEY_Z", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_ESC); pkSetAttribute(vm, 0, "KEY_ESC", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_ENTER); pkSetAttribute(vm, 0, "KEY_ENTER", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_SPACE); pkSetAttribute(vm, 0, "KEY_SPACE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_HOME); pkSetAttribute(vm, 0, "KEY_HOME", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_END); pkSetAttribute(vm, 0, "KEY_END", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_PAGEUP); pkSetAttribute(vm, 0, "KEY_PAGEUP", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_PAGEDOWN); pkSetAttribute(vm, 0, "KEY_PAGEDOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_LEFT); pkSetAttribute(vm, 0, "KEY_LEFT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_UP); pkSetAttribute(vm, 0, "KEY_UP", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_RIGHT); pkSetAttribute(vm, 0, "KEY_RIGHT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_DOWN); pkSetAttribute(vm, 0, "KEY_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_INSERT); pkSetAttribute(vm, 0, "KEY_INSERT", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_DELETE); pkSetAttribute(vm, 0, "KEY_DELETE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_BACKSPACE); pkSetAttribute(vm, 0, "KEY_BACKSPACE", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_TAB); pkSetAttribute(vm, 0, "KEY_TAB", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F1); pkSetAttribute(vm, 0, "KEY_F1", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F2); pkSetAttribute(vm, 0, "KEY_F2", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F3); pkSetAttribute(vm, 0, "KEY_F3", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F4); pkSetAttribute(vm, 0, "KEY_F4", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F5); pkSetAttribute(vm, 0, "KEY_F5", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F6); pkSetAttribute(vm, 0, "KEY_F6", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F7); pkSetAttribute(vm, 0, "KEY_F7", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F8); pkSetAttribute(vm, 0, "KEY_F8", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F9); pkSetAttribute(vm, 0, "KEY_F9", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F10); pkSetAttribute(vm, 0, "KEY_F10", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F11); pkSetAttribute(vm, 0, "KEY_F11", 1);
pkSetSlotNumber(vm, 1, TERM_KEY_F12); pkSetAttribute(vm, 0, "KEY_F12", 1);
pkSetSlotNumber(vm, 1, TERM_MB_UNKNOWN); pkSetAttribute(vm, 0, "BUTTON_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_MB_LEFT); pkSetAttribute(vm, 0, "BUTTON_LEFT", 1);
pkSetSlotNumber(vm, 1, TERM_MB_MIDDLE); pkSetAttribute(vm, 0, "BUTTON_MIDDLE", 1);
pkSetSlotNumber(vm, 1, TERM_MB_RIGHT); pkSetAttribute(vm, 0, "BUTTON_RIGHT", 1);
pkSetSlotNumber(vm, 1, TERM_MD_NONE); pkSetAttribute(vm, 0, "MD_NONE", 1);
pkSetSlotNumber(vm, 1, TERM_MD_CTRL); pkSetAttribute(vm, 0, "MD_CTRL", 1);
pkSetSlotNumber(vm, 1, TERM_MD_ALT); pkSetAttribute(vm, 0, "MD_ALT", 1);
pkSetSlotNumber(vm, 1, TERM_MD_SHIFT); pkSetAttribute(vm, 0, "MD_SHIFT", 1);
pkSetSlotNumber(vm, 1, TERM_ET_UNKNOWN); pkSetAttribute(vm, 0, "EVENT_UNKNOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_KEY_DOWN); pkSetAttribute(vm, 0, "EVENT_KEY_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_RESIZE); pkSetAttribute(vm, 0, "EVENT_RESIZE", 1);
pkSetSlotNumber(vm, 1, TERM_ET_DOUBLE_CLICK); pkSetAttribute(vm, 0, "EVENT_DOUBLE_CLICK", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_DOWN); pkSetAttribute(vm, 0, "EVENT_MOUSE_DOWN", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_UP); pkSetAttribute(vm, 0, "EVENT_MOUSE_UP", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_MOVE); pkSetAttribute(vm, 0, "EVENT_MOUSE_MOVE", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_DRAG); pkSetAttribute(vm, 0, "EVENT_MOUSE_DRAG", 1);
pkSetSlotNumber(vm, 1, TERM_ET_MOUSE_SCROLL); pkSetAttribute(vm, 0, "EVENT_MOUSE_SCROLL", 1);
}
void _termInit(PKVM* vm) {
bool capture_events;
if (!pkValidateSlotBool(vm, 1, &capture_events)) return;
term_init(capture_events);
}
void _termCleanup(PKVM* vm) {
term_cleanup();
}
void _termIsatty(PKVM* vm) {
pkSetSlotBool(vm, 0, term_isatty());
}
void _termNewScreenBuffer(PKVM* vm) {
term_new_screen_buffer();
}
void _termRestoreScreenBuffer(PKVM* vm) {
term_restore_screen_buffer();
}
void _termGetSize(PKVM* vm) {
pkReserveSlots(vm, 2);
term_Vec size = term_getsize();
_setSlotVector(vm, 0, 1, size.x, size.y);
}
void _termGetPosition(PKVM* vm) {
pkReserveSlots(vm, 2);
term_Vec pos = term_getposition();
_setSlotVector(vm, 0, 1, pos.x, pos.y);
}
void _termSetPosition(PKVM* vm) {
double x, y;
int argc = pkGetArgc(vm);
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
if (argc == 1) {
pkReserveSlots(vm, 3);
if (!pkGetAttribute(vm, 1, "x", 2)) return;
if (!pkValidateSlotNumber(vm, 2, &x)) return;
if (!pkGetAttribute(vm, 1, "y", 2)) return;
if (!pkValidateSlotNumber(vm, 2, &y)) return;
} else {
if (!pkValidateSlotNumber(vm, 1, &x)) return;
if (!pkValidateSlotNumber(vm, 2, &y)) return;
}
term_Vec pos = term_vec((int)x, (int)y);
term_setposition(pos);
}
void _termReadEvent(PKVM* vm) {
pkReserveSlots(vm, 3);
pkSetSlotHandle(vm, 2, _cls_term_event);
if (!pkValidateSlotInstanceOf(vm, 1, 2)) return;
term_Event* event = pkGetSlotNativeInstance(vm, 1);
pkSetSlotBool(vm, 0, term_read_event(event));
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleTerm(PKVM* vm) {
PkHandle* term = pkNewModule(vm, "term");
_registerEnums(vm, term);
pkModuleAddFunction(vm, term, "init", _termInit, 1);
pkModuleAddFunction(vm, term, "cleanup", _termCleanup, 0);
pkModuleAddFunction(vm, term, "isatty", _termIsatty, 0);
pkModuleAddFunction(vm, term, "new_screen_buffer", _termNewScreenBuffer, 0);
pkModuleAddFunction(vm, term, "restore_screen_buffer", _termRestoreScreenBuffer, 0);
pkModuleAddFunction(vm, term, "getsize", _termGetSize, 0);
pkModuleAddFunction(vm, term, "getposition", _termGetPosition, 0);
pkModuleAddFunction(vm, term, "setposition", _termSetPosition, -1);
pkModuleAddFunction(vm, term, "read_event", _termReadEvent, 1);
_cls_term_event = pkNewClass(vm, "Event", NULL, term, _termEventNew, _termEventDelete);
pkClassAddMethod(vm, _cls_term_event, "@getter", _termEventGetter, 1);
pkRegisterModule(vm, term);
pkReleaseHandle(vm, term);
}
void cleanupModuleTerm(PKVM* vm) {
if (_cls_term_event) pkReleaseHandle(vm, _cls_term_event);
}

View File

@ -17,6 +17,9 @@ void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm); void registerModulePath(PKVM* vm);
void registerModuleDummy(PKVM* vm); void registerModuleDummy(PKVM* vm);
void registerModuleTerm(PKVM* vm);
void cleanupModuleTerm(PKVM* vm);
// Registers the modules. // Registers the modules.
void registerLibs(PKVM* vm) { void registerLibs(PKVM* vm) {
registerModuleMath(vm); registerModuleMath(vm);
@ -25,8 +28,11 @@ void registerLibs(PKVM* vm) {
registerModuleIO(vm); registerModuleIO(vm);
registerModulePath(vm); registerModulePath(vm);
registerModuleDummy(vm); registerModuleDummy(vm);
registerModuleTerm(vm);
} }
// Cleanup the modules. // Cleanup the modules.
void cleanupLibs(PKVM* vm) { void cleanupLibs(PKVM* vm) {
cleanupModuleTerm(vm);
} }

21
src/libs/thirdparty/term/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Thakee Nathees
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

1012
src/libs/thirdparty/term/term.h vendored Normal file

File diff suppressed because it is too large Load Diff

124
tests/examples/snake.pk Normal file
View File

@ -0,0 +1,124 @@
import tui, term, math
from types import Vector
## This is a pocketlang implementation of:
## https://www.youtube.com/watch?v=xGmXxpIj6vs&t=279s&ab_channel=ChrisDeLeonofHomeTeamGameDev
## x, y velocity of snake.
vx = 0; vy = 0
## position (at the middle).
px = 0; py = 0
## tile size.
tx = 0; ty = 0
## apple position.
ax = 15; ay = 15
## tail, trail
trail = []
tail = 15
## score
score = 0
def init()
size = tui.get_size()
tx = size.x
ty = size.y
px = tx / 2; py = ty / 2
end
def frame()
px += vx
py += vy
if px < 0 then px = tx - 1 end
if px > tx - 1 then px = 0 end
if py < 0 then py = ty - 1 end
if py > ty - 1 then py = 0 end
tui.clear()
tui.string('press Q to quit | score = $score')
for i in trail
tui.set_position(i.x, i.y)
tui.start_bg(0, 0xff, 0)
tui.string(' ')
tui.end_bg()
if i.x == px and i.y == py
tail = 5
end
end
tui.set_position(ax, ay)
tui.start_bg(0xff, 0, 0)
tui.string(' ')
tui.end_bg()
trail.append(Vector(px, py))
while trail.length > tail
trail.pop(0)
end
if px == ax and py == ay
tail += 1
score += 1
ax = math.rand() % tx
ay = math.rand() % ty
end
tui.flush()
end
def handle(event)
if event.type == term.EVENT_KEY_DOWN
if event.keycode == term.KEY_Q
tui.stop()
end
## The "Switch Statement" alternative.
{
term.KEY_LEFT: fn
vx = -1; vy = 0
end,
term.KEY_UP: fn
vx = 0; vy = -1
end,
term.KEY_DOWN: fn
vx = 0; vy = 1
end,
term.KEY_RIGHT: fn
vx = 1; vy = 0
end,
term.KEY_T: fn
math.sin(12)
end,
}.get(event.keycode, fn end)()
end
end
def main()
config = tui.Config()
config.capture_events = true
config.hide_cursor = true
config.new_buffer = true
config.fps = 20
config.init_fn = init
config.event_fn = handle
config.frame_fn = frame
tui.run(config)
end
main()

321
tests/examples/tui/_init.pk Normal file
View File

@ -0,0 +1,321 @@
import term, io
from time import clock, sleep
from types import ByteBuffer
def write(msg)
io.write(io.stdout, msg)
end
## The configuration that should be used to create tui context
## and run.
class Config
def _init()
self.title = null
self.fps = 60
self.hide_cursor = false
self.capture_events = false
self.new_buffer = false
self.init_fn = null
self.event_fn = null
self.frame_fn = null
self.cleanup_fn = null
end
end
## Interlan context contains draw buffer and other data.
class _Context
def _init()
self.buff = ByteBuffer()
self.clear()
end
## Called to reset all the internal for reusing the context.
def clear()
self.buff.clear()
self.done = false ## If true the main loop ends.
end
end
## Internal global context.
_ctx = _Context()
## -------------------------------------------------------------------------
## FUNCTIONS
## -------------------------------------------------------------------------
## Flush all the buffered bytes in the context's buffer.
def flush()
write(_ctx.buff.string())
io.flush()
_ctx.buff.clear()
end
## Stops the main loop and return from run().
def stop()
_ctx.done = true
end
def set_title(title)
write("\x1b]0;$title\x07")
end
def hide_cursor()
write("\x1b[?25l")
end
def show_cursor()
write("\x1b[?25h")
end
## It'll write escape sequence to move the cursor but not actually move.
## for this to make effect, one should flush the buffer.
def set_position(x, y)
_ctx.buff.write("\x1b[${y + 1};${x + 1}H")
end
def get_size()
return term.getsize()
end
##
## Hex ASCII DEC-Line-Drawing
## ------------------------------
## 0x6a j ┘
## 0x6b k ┐
## 0x6c l ┌
## 0x6d m └
## 0x6e n ┼
## 0x71 q ─
## 0x74 t ├
## 0x75 u ┤
## 0x76 v ┴
## 0x77 w ┬
## 0x78 x │
##
def box_char(c)
_ctx.buff.write("\x1b(0$c\x1b(B")
end
## FIXME: Implement str * int multiplicatin to support
##
## "\x1b(0${ c * n }\x1b(B"
##
## and define box_char_len() or refactor the above to take argument n.
## Write a string to the context buffer.
def string(s)
_ctx.buff.write(str(s))
end
## Clear the screen and move cursor to (0, 0).
def clear()
_ctx.buff.write("\x1b[H\x1b[J")
end
## Clear everythin from cursor to EOL.
def clear_eol()
_ctx.buff.write("\x1b[K")
end
## Clear everythin from cursor to EOF.
def clear_eof()
_ctx.buff.write("\x1b[J")
end
## Reset all the stylings.
def reset()
_ctx.buff.write("\x1b[0m")
end
def _is_valid_color(r, g, b)
return r is Number and g is Number and b is Number
return r.isbyte() and g.isbyte() and b.isbyte()
end
## Set the forground color.
def start_color(r, g, b)
assert(_is_valid_color(r, g, b))
_ctx.buff.write("\x1b[38;2;$r;$g;${b}m")
end
## End the forground color.
def end_color()
_ctx.buff.write("\x1b[39m")
end
## Start the background color.
def start_bg(r, g, b)
assert(_is_valid_color(r, g, b))
_ctx.buff.write("\x1b[48;2;$r;$g;${b}m")
end
## End the background color.
def end_bg()
_ctx.buff.write("\x1b[49m")
end
def start_bold()
_ctx.buff.write("\x1b[1m")
end
def end_bold()
_ctx.buff.write("\x1b[22m")
end
def start_dim()
_ctx.buff.write("\x1b[2m")
end
def end_dim()
_ctx.buff.write("\x1b[22m")
end
def start_italic()
_ctx.buff.write("\x1b[3m")
end
def end_italic()
_ctx.buff.write("\x1b[23m")
end
def start_underline()
_ctx.buff.write("\x1b[4m")
end
def end_underline()
_ctx.buff.write("\x1b[24m")
end
def start_hidden()
_ctx.buff.write("\x1b[8m")
end
def end_hidden()
_ctx.buff.write("\x1b[28m")
end
def start_strikethrough()
_ctx.buff.write("\x1b[9m")
end
def end_strikethrough()
_ctx.buff.write("\x1b[29m")
end
def start_color_black()
_ctx.buff.write("\x1b[30m")
end
def end_color_black()
_ctx.buff.write("\x1b[40m")
end
def start_color_red()
_ctx.buff.write("\x1b[31m")
end
def end_color_red()
_ctx.buff.write("\x1b[41m")
end
def start_color_green()
_ctx.buff.write("\x1b[32m")
end
def end_color_green()
_ctx.buff.write("\x1b[42m")
end
def start_color_yellow()
_ctx.buff.write("\x1b[33m")
end
def end_color_yellow()
_ctx.buff.write("\x1b[43m")
end
def start_color_blue()
_ctx.buff.write("\x1b[34m")
end
def end_color_blue()
_ctx.buff.write("\x1b[44m")
end
def start_color_magenta()
_ctx.buff.write("\x1b[35m")
end
def end_color_magenta()
_ctx.buff.write("\x1b[45m")
end
def start_color_cyan()
_ctx.buff.write("\x1b[36m")
end
def end_color_cyan()
_ctx.buff.write("\x1b[46m")
end
def start_color_white()
_ctx.buff.write("\x1b[37m")
end
def end_color_white()
_ctx.buff.write("\x1b[47m")
end
def start_color_default()
_ctx.buff.write("\x1b[39m")
end
def end_color_default()
_ctx.buff.write("\x1b[49m")
end
## -------------------------------------------------------------------------
## TUI MAIN LOOP
## -------------------------------------------------------------------------
def run(config)
term.init(config.capture_events)
if config.new_buffer then term.new_screen_buffer() end
if config.hide_cursor then hide_cursor() end
if config.init_fn then config.init_fn() end
event = term.Event()
## The main loop.
while not _ctx.done
start = clock()
## Dispatch events.
while term.read_event(event)
if config.event_fn then config.event_fn(event) end
if _ctx.done then break end
end
## Run frame function
if config.frame_fn then config.frame_fn() end
## Sleep to sync FPS.
et = clock() - start ## Elapsed time.
ft = 1 / config.fps ## Frame time.
## TODO: set title to print fps if said in config.
if ft > et then sleep((ft - et) * 1000) end
end
## Cleanup.
if config.cleanup_fn then config.cleanup_fn() end
if config.hide_cursor then show_cursor() end
if config.new_buffer then term.restore_screen_buffer() end
term.cleanup()
_ctx.clear()
end

View File

@ -72,6 +72,7 @@ assert(val == 'bar')
def test_in_local() def test_in_local()
x = false
if x = fn y = false; return not y end () if x = fn y = false; return not y end ()
assert(x == true) assert(x == true)
end end

View File

@ -16,6 +16,7 @@ def read_file()
'line4 : qux\n', 'line4 : qux\n',
] ]
line = ''
while line = f.getline() while line = f.getline()
assert(line in LINES) assert(line in LINES)
end end