Very basic Notcurses support. There are bugs! (0.37.45)
This commit is contained in:
parent
4a6903e58a
commit
fd582f4d3a
30 changed files with 465 additions and 5 deletions
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(fun VERSION 0.37.44 LANGUAGES C)
|
||||
project(fun VERSION 0.37.45 LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
|
@ -474,6 +474,38 @@ if(M_LIB)
|
|||
target_link_libraries(fun_core PUBLIC ${M_LIB})
|
||||
endif()
|
||||
|
||||
# Optional Notcurses TUI support (per-opcode files under src/vm/notcurses)
|
||||
option(FUN_WITH_NOTCURSES "Enable Notcurses TUI support" OFF)
|
||||
set(NOTCURSES_INCLUDE_DIRS "")
|
||||
set(NOTCURSES_LINK_LIBS "")
|
||||
if(FUN_WITH_NOTCURSES)
|
||||
message(STATUS "FUN_WITH_NOTCURSES=ON: enabling Notcurses TUI ops")
|
||||
add_definitions(-DFUN_WITH_NOTCURSES)
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PkgConfig_FOUND)
|
||||
# Prefer full 'notcurses', fall back to 'notcurses-core'
|
||||
pkg_check_modules(NOTCURSES QUIET notcurses)
|
||||
if(NOT NOTCURSES_FOUND)
|
||||
pkg_check_modules(NOTCURSES QUIET notcurses-core)
|
||||
endif()
|
||||
endif()
|
||||
if(NOTCURSES_FOUND)
|
||||
list(APPEND NOTCURSES_INCLUDE_DIRS ${NOTCURSES_INCLUDE_DIRS} ${NOTCURSES_INCLUDE_DIRS})
|
||||
list(APPEND NOTCURSES_LINK_LIBS ${NOTCURSES_LINK_LIBS} ${NOTCURSES_LIBRARIES})
|
||||
include_directories(${NOTCURSES_INCLUDE_DIRS})
|
||||
else()
|
||||
message(FATAL_ERROR "FUN_WITH_NOTCURSES=ON but notcurses was not found via pkg-config (tried notcurses and notcurses-core). Install notcurses or configure with -DFUN_WITH_NOTCURSES=OFF")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# notcurses include and link (if enabled)
|
||||
if(NOTCURSES_INCLUDE_DIRS)
|
||||
target_include_directories(fun_core PRIVATE ${NOTCURSES_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(NOTCURSES_LINK_LIBS)
|
||||
target_link_libraries(fun_core PUBLIC ${NOTCURSES_LINK_LIBS})
|
||||
endif()
|
||||
|
||||
# Interpreter /usr/bin/fun
|
||||
option(FUN_WITH_REPL "Enable interactive REPL in the fun CLI" OFF)
|
||||
add_executable(fun
|
||||
|
|
|
|||
0
examples/ini_diag.fun
Normal file → Executable file
0
examples/ini_diag.fun
Normal file → Executable file
0
examples/math_ceil.fun
Normal file → Executable file
0
examples/math_ceil.fun
Normal file → Executable file
0
examples/math_cos.fun
Normal file → Executable file
0
examples/math_cos.fun
Normal file → Executable file
0
examples/math_exp_log.fun
Normal file → Executable file
0
examples/math_exp_log.fun
Normal file → Executable file
0
examples/math_floor.fun
Normal file → Executable file
0
examples/math_floor.fun
Normal file → Executable file
0
examples/math_fmin_fmax.fun
Normal file → Executable file
0
examples/math_fmin_fmax.fun
Normal file → Executable file
0
examples/math_gcd_lcm.fun
Normal file → Executable file
0
examples/math_gcd_lcm.fun
Normal file → Executable file
0
examples/math_isqrt.fun
Normal file → Executable file
0
examples/math_isqrt.fun
Normal file → Executable file
0
examples/math_round.fun
Normal file → Executable file
0
examples/math_round.fun
Normal file → Executable file
0
examples/math_sign.fun
Normal file → Executable file
0
examples/math_sign.fun
Normal file → Executable file
0
examples/math_sin.fun
Normal file → Executable file
0
examples/math_sin.fun
Normal file → Executable file
0
examples/math_sqrt.fun
Normal file → Executable file
0
examples/math_sqrt.fun
Normal file → Executable file
0
examples/math_tan.fun
Normal file → Executable file
0
examples/math_tan.fun
Normal file → Executable file
0
examples/math_trunc.fun
Normal file → Executable file
0
examples/math_trunc.fun
Normal file → Executable file
42
examples/notcurses_clock.fun
Executable file
42
examples/notcurses_clock.fun
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
// BROKEN!!!
|
||||
|
||||
/*
|
||||
* Notcurses clock demo: updates time every 200ms; any key to finish.
|
||||
*/
|
||||
|
||||
include <ui/notcurses.fun>
|
||||
|
||||
n = Notcurses()
|
||||
if n.init() == 0
|
||||
print("Notcurses not available. Rebuild with -DFUN_WITH_NOTCURSES=ON.")
|
||||
exit(0)
|
||||
|
||||
n.clear()
|
||||
n.draw_text(1, 0, "Clock demo (press any key)")
|
||||
|
||||
var done = 0
|
||||
while done == 0
|
||||
// current time string
|
||||
var ms = time_now_ms()
|
||||
var t = date_format("%Y-%m-%d %H:%M:%S", ms)
|
||||
n.draw_text(3, 0, "Time: " + t)
|
||||
|
||||
// poll without blocking too long
|
||||
var k = n.getch(200)
|
||||
if k != -1
|
||||
done = 1
|
||||
|
||||
n.shutdown()
|
||||
46
examples/notcurses_hello.fun
Executable file
46
examples/notcurses_hello.fun
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimal Notcurses hello example.
|
||||
*/
|
||||
|
||||
include <ui/notcurses.fun>
|
||||
|
||||
n = Notcurses()
|
||||
|
||||
if n.init() == 0
|
||||
print("Notcurses not available. Rebuild with -DFUN_WITH_NOTCURSES=ON.")
|
||||
exit(0)
|
||||
|
||||
n.clear()
|
||||
n.draw_text(2, 0, "Fun + Notcurses")
|
||||
n.draw_text(4, 0, "Press any key to exit...")
|
||||
|
||||
// blocking until key
|
||||
_ = n.getch(0)
|
||||
n.shutdown()
|
||||
|
||||
/* Possible output:
|
||||
A TUI.
|
||||
|
||||
After exit:
|
||||
3 renders, 991,14µs (223,57µs min, 330,38µs avg, 531,91µs max)
|
||||
3 rasters, 320,76µs (106,45µs min, 106,92µs avg, 107,72µs max)
|
||||
3 writes, 198,26µs (62,54µs min, 66,09µs avg, 69,94µs max)
|
||||
59B (0B min, 19B avg, 30B max) 1 input Ghpa: 0
|
||||
0 failed renders, 0 failed rasters, 0 refreshes, 0 input errors
|
||||
RGB emits:elides: def 1:38 fg 0:0 bg 0:0
|
||||
Cell emits:elides: 39:74805 (99,95%) 97,44% 0,00% 0,00%
|
||||
Bmap emits:elides: 0:0 (0,00%) 0B (0,00%) SuM: 0 (0,00%)
|
||||
*/
|
||||
42
examples/notcurses_typing.fun
Executable file
42
examples/notcurses_typing.fun
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
// BROKEN!!!
|
||||
|
||||
/*
|
||||
* Notcurses typing demo: shows last key code; ESC quits.
|
||||
*/
|
||||
|
||||
include <ui/notcurses.fun>
|
||||
|
||||
n = Notcurses()
|
||||
if n.init() == 0
|
||||
print("Notcurses not available. Rebuild with -DFUN_WITH_NOTCURSES=ON.")
|
||||
exit(0)
|
||||
|
||||
n.clear()
|
||||
n.draw_text(1, 0, "Typing demo (ESC to quit)")
|
||||
|
||||
var running = 1
|
||||
var last = -1
|
||||
while running == 1
|
||||
// poll every 100ms
|
||||
var k = n.getch(100)
|
||||
if k != -1
|
||||
last = k
|
||||
if k == 27 // ESC
|
||||
running = 0
|
||||
// draw last key code
|
||||
n.draw_text(3, 0, "Last key code: " + to_string(last))
|
||||
|
||||
n.shutdown()
|
||||
0
examples/ripemd160_example.fun
Normal file → Executable file
0
examples/ripemd160_example.fun
Normal file → Executable file
42
lib/ui/notcurses.fun
Normal file
42
lib/ui/notcurses.fun
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
// Notcurses stdlib abstraction wrapping VM NC_* builtins.
|
||||
// Provides a tiny OO-style helper around nc_init/nc_clear/nc_draw_text/nc_getch/nc_shutdown.
|
||||
// If Fun was built without Notcurses support, init() returns 0 and methods are no-ops.
|
||||
|
||||
class Notcurses()
|
||||
// Initialize Notcurses core. Returns 1 on success, 0 on failure.
|
||||
fun init(this)
|
||||
return nc_init()
|
||||
|
||||
// Clear the screen and render. Returns 0 on success, -1 on error.
|
||||
fun clear(this)
|
||||
return nc_clear()
|
||||
|
||||
// Draw text at y, x and render. Returns 0 on success, -1 on error.
|
||||
fun draw_text(this, y, x, text)
|
||||
// allow flexible types
|
||||
return nc_draw_text(to_number(y), to_number(x), to_string(text))
|
||||
|
||||
// Get a Unicode codepoint (int). timeout_ms<=0 blocks; >0 returns -1 if no key ready.
|
||||
fun getch(this, timeout_ms)
|
||||
if timeout_ms == nil
|
||||
timeout_ms = 0
|
||||
return nc_getch(to_number(timeout_ms))
|
||||
|
||||
// Shut down Notcurses, restoring the terminal.
|
||||
fun shutdown(this)
|
||||
return nc_shutdown()
|
||||
|
||||
// (banner helper removed temporarily due to parser limitations)
|
||||
|
|
@ -261,7 +261,14 @@ typedef enum {
|
|||
|
||||
// Min/Max variants (float-aware, C99 semantics)
|
||||
OP_FMIN, // pops b, a (int/float); pushes fmin(a,b) (NaN handling per C99)
|
||||
OP_FMAX // pops b, a (int/float); pushes fmax(a,b) (NaN handling per C99)
|
||||
OP_FMAX, // pops b, a (int/float); pushes fmax(a,b) (NaN handling per C99)
|
||||
|
||||
/* Notcurses TUI (optional) */
|
||||
OP_NC_INIT, // initializes Notcurses; returns 1 on success, 0 on failure
|
||||
OP_NC_SHUTDOWN, // shuts down Notcurses; returns 0
|
||||
OP_NC_CLEAR, // clears screen/plane; returns 0
|
||||
OP_NC_DRAW_TEXT, // pops text, x, y; draws; returns 0
|
||||
OP_NC_GETCH // pops timeout_ms; returns codepoint or -1 on timeout/error
|
||||
} OpCode;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
44
src/parser.c
44
src/parser.c
|
|
@ -1195,6 +1195,50 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
free(name);
|
||||
return 1;
|
||||
}
|
||||
/* Notcurses builtins (optional) */
|
||||
if (strcmp(name, "nc_init") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "nc_init expects ()"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_NC_INIT, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "nc_shutdown") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "nc_shutdown expects ()"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_NC_SHUTDOWN, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "nc_clear") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "nc_clear expects ()"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_NC_CLEAR, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "nc_draw_text") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
/* (y, x, text) -> push y, x, text, then opcode will pop text,x,y */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "nc_draw_text expects (y, x, text)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "nc_draw_text expects (y, x, text)"); free(name); return 0; }
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "nc_draw_text expects (y, x, text)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "nc_draw_text expects (y, x, text)"); free(name); return 0; }
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "nc_draw_text expects (y, x, text)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after nc_draw_text args"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_NC_DRAW_TEXT, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "nc_getch") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
/* (timeout_ms) */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "nc_getch expects (timeout_ms)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after nc_getch arg"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_NC_GETCH, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "pcsc_release") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "pcsc_release expects 1 argument (ctx)"); free(name); return 0; }
|
||||
|
|
|
|||
21
src/vm.c
21
src/vm.c
|
|
@ -7,12 +7,15 @@
|
|||
* https://opensource.org/license/apache-2-0
|
||||
*/
|
||||
|
||||
/* Ensure POSIX prototypes (nanosleep, clock_gettime, localtime_r, etc.) are available
|
||||
/* Ensure POSIX/XSI prototypes (nanosleep, wcwidth, etc.) are available
|
||||
* before any system headers are included by amalgamated .c files. */
|
||||
#ifndef _WIN32
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 700
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -45,6 +48,13 @@
|
|||
#include "value.h"
|
||||
#include "vm.h"
|
||||
|
||||
/* Shared Notcurses state (optional) */
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
# include <wchar.h> /* ensure wcwidth/wcswidth prototypes present before notcurses.h on some systems */
|
||||
# include <notcurses/notcurses.h>
|
||||
#endif
|
||||
#include "vm/notcurses/common.h"
|
||||
|
||||
// Optional by extensions commonly used code. #ifdef's are in each single file.
|
||||
#include "external/curl.c"
|
||||
#include "external/ini.c"
|
||||
|
|
@ -781,6 +791,15 @@ void vm_run(VM *vm, Bytecode *entry) {
|
|||
#include "vm/tk/bind.c"
|
||||
#endif
|
||||
|
||||
/* Notcurses TUI ops (optional) */
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
#include "vm/notcurses/init.c"
|
||||
#include "vm/notcurses/shutdown.c"
|
||||
#include "vm/notcurses/clear.c"
|
||||
#include "vm/notcurses/draw_text.c"
|
||||
#include "vm/notcurses/getch.c"
|
||||
#endif
|
||||
|
||||
/* SQLite ops */
|
||||
#ifdef FUN_WITH_SQLITE
|
||||
#include "vm/sqlite/open.c"
|
||||
|
|
|
|||
6
src/vm.h
6
src/vm.h
|
|
@ -53,7 +53,9 @@ static const char *opcode_names[] = {
|
|||
"TK_BIND",
|
||||
"SERIAL_OPEN","SERIAL_CONFIG","SERIAL_SEND","SERIAL_RECV","SERIAL_CLOSE",
|
||||
"TK_EVAL","TK_RESULT","TK_LOOP","TK_WM_TITLE","TK_LABEL","TK_BUTTON","TK_PACK",
|
||||
"TRY_PUSH","TRY_POP","THROW"
|
||||
"TRY_PUSH","TRY_POP","THROW",
|
||||
/* Notcurses TUI (optional) */
|
||||
"NC_INIT","NC_SHUTDOWN","NC_CLEAR","NC_DRAW_TEXT","NC_GETCH"
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -132,7 +134,7 @@ void vm_debug_request_finish(VM *vm);
|
|||
void vm_debug_request_continue(VM *vm);
|
||||
|
||||
static inline int opcode_is_valid(int op) {
|
||||
return op >= OP_NOP && op <= OP_THROW; // all current opcodes
|
||||
return op >= OP_NOP && op <= OP_NC_GETCH; // all current opcodes (including optional NC_*)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
27
src/vm/notcurses/clear.c
Normal file
27
src/vm/notcurses/clear.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* NC_CLEAR */
|
||||
case OP_NC_CLEAR: {
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
if (_fun_nc && _fun_nc_std) {
|
||||
ncplane_erase(_fun_nc_std);
|
||||
notcurses_render(_fun_nc);
|
||||
push_value(vm, make_int(0));
|
||||
} else {
|
||||
push_value(vm, make_int(-1));
|
||||
}
|
||||
#else
|
||||
(void)_fun_nc; (void)_fun_nc_std;
|
||||
push_value(vm, make_int(-1));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
23
src/vm/notcurses/common.h
Normal file
23
src/vm/notcurses/common.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* Common helpers/state for Notcurses TUI ops */
|
||||
#pragma once
|
||||
|
||||
#include "value.h"
|
||||
|
||||
/* Forward declarations to avoid depending on the notcurses headers unless enabled */
|
||||
struct notcurses;
|
||||
struct ncplane;
|
||||
|
||||
/* Shared static state within vm.c translation unit (header is included into vm.c at file scope) */
|
||||
static struct notcurses* _fun_nc = NULL;
|
||||
static struct ncplane* _fun_nc_std = NULL;
|
||||
39
src/vm/notcurses/draw_text.c
Normal file
39
src/vm/notcurses/draw_text.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* NC_DRAW_TEXT */
|
||||
case OP_NC_DRAW_TEXT: {
|
||||
Value textv = pop_value(vm);
|
||||
Value xv = pop_value(vm);
|
||||
Value yv = pop_value(vm);
|
||||
int x = (xv.type == VAL_INT ? (int)xv.i : (xv.type == VAL_FLOAT ? (int)xv.d : 0));
|
||||
int y = (yv.type == VAL_INT ? (int)yv.i : (yv.type == VAL_FLOAT ? (int)yv.d : 0));
|
||||
char *text = value_to_string_alloc(&textv);
|
||||
free_value(textv);
|
||||
free_value(xv);
|
||||
free_value(yv);
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
if (_fun_nc && _fun_nc_std && text) {
|
||||
ncplane_putstr_yx(_fun_nc_std, y, x, text);
|
||||
notcurses_render(_fun_nc);
|
||||
free(text);
|
||||
push_value(vm, make_int(0));
|
||||
} else {
|
||||
if (text) free(text);
|
||||
push_value(vm, make_int(-1));
|
||||
}
|
||||
#else
|
||||
(void)_fun_nc; (void)_fun_nc_std;
|
||||
if (text) free(text);
|
||||
push_value(vm, make_int(-1));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
43
src/vm/notcurses/getch.c
Normal file
43
src/vm/notcurses/getch.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* NC_GETCH */
|
||||
case OP_NC_GETCH: {
|
||||
Value to_ms_v = pop_value(vm);
|
||||
int timeout_ms = (to_ms_v.type == VAL_INT ? (int)to_ms_v.i : (to_ms_v.type == VAL_FLOAT ? (int)to_ms_v.d : 0));
|
||||
free_value(to_ms_v);
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
if (_fun_nc) {
|
||||
/* For simplicity, use blocking get for now when timeout<=0 */
|
||||
if (timeout_ms <= 0) {
|
||||
ncinput ni;
|
||||
uint32_t id = notcurses_get_blocking(_fun_nc, &ni);
|
||||
push_value(vm, make_int((int)id));
|
||||
} else {
|
||||
/* Polling approximation: render then nonblocking get once */
|
||||
ncinput ni;
|
||||
uint32_t id = notcurses_get_nblock(_fun_nc, &ni);
|
||||
if (id == 0) {
|
||||
/* no input available now: return -1 to indicate timeout */
|
||||
push_value(vm, make_int(-1));
|
||||
} else {
|
||||
push_value(vm, make_int((int)id));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
push_value(vm, make_int(-1));
|
||||
}
|
||||
#else
|
||||
(void)_fun_nc; (void)_fun_nc_std; (void)timeout_ms;
|
||||
push_value(vm, make_int(-1));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
27
src/vm/notcurses/init.c
Normal file
27
src/vm/notcurses/init.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* NC_INIT */
|
||||
case OP_NC_INIT: {
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
if (_fun_nc) { push_value(vm, make_int(1)); break; }
|
||||
struct notcurses_options opts = {0};
|
||||
_fun_nc = notcurses_core_init(&opts, NULL);
|
||||
if (!_fun_nc) { push_value(vm, make_int(0)); break; }
|
||||
_fun_nc_std = notcurses_stdplane(_fun_nc);
|
||||
push_value(vm, make_int(1));
|
||||
#else
|
||||
(void)_fun_nc; (void)_fun_nc_std;
|
||||
fprintf(stderr, "Notcurses support disabled at build time. Reconfigure with -DFUN_WITH_NOTCURSES=ON.\n");
|
||||
push_value(vm, make_int(0));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
25
src/vm/notcurses/shutdown.c
Normal file
25
src/vm/notcurses/shutdown.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-01-03
|
||||
*/
|
||||
|
||||
/* NC_SHUTDOWN */
|
||||
case OP_NC_SHUTDOWN: {
|
||||
#ifdef FUN_WITH_NOTCURSES
|
||||
if (_fun_nc) {
|
||||
notcurses_stop(_fun_nc);
|
||||
_fun_nc = NULL;
|
||||
_fun_nc_std = NULL;
|
||||
}
|
||||
#else
|
||||
(void)_fun_nc; (void)_fun_nc_std;
|
||||
#endif
|
||||
push_value(vm, make_int(0));
|
||||
break;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue