feat: add fullscreen TUI and project updates

- New TUI screens: Main Menu, Compile, Run, REPL, AI Generator, AI Settings, Help
- AI configuration persisted in ~/.config/cljnim/config.json
- Added illwill dependency for terminal UI
- Updated experiments, examples, docs, and core modules
This commit is contained in:
2026-05-09 01:53:23 +03:00
parent 2bc64eca22
commit ba0b300917
42 changed files with 3042 additions and 153 deletions
+47
View File
@@ -0,0 +1,47 @@
# Clojure/Nim → Native Shared Library
Compile Clojure code to a C shared library (`.so` / `.dll` / `.dylib`).
## Why?
- **Embed Clojure in Python/Rust/Go/C** via FFI
- **Tiny binaries** — no JVM overhead
- **True C ABI** — call Clojure functions from any language
## Quick Start
```bash
./build.sh
```
This generates:
- `build/libmath.so` — shared library
- `build/math.h` — C header
- `build/math.nim` — intermediate Nim source
## Test from C
```bash
cd test_client
make
./test_client
```
Expected output:
```
square(5) = 25
add(10, 20) = 30
cube(3) = 27
factorial(5) = 120
```
## How it works
1. `cljnim compile-lib` — generates Nim with exported `proc name*(...)`
2. `nim c --app:lib --header` — compiles Nim to `.so` + `.h`
3. C client links against the `.so` and calls functions
## Limitations
- Functions use `CljVal` (Nim ref object) — client must call Nim runtime helpers
- `NimMain()` must be called before using the library
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CLJNIM="${SCRIPT_DIR}/../../cljnim"
LIB_PATH="${SCRIPT_DIR}/../../lib"
mkdir -p "${SCRIPT_DIR}/build"
echo "=== Step 1: Clojure → Nim ==="
"$CLJNIM" compile-lib \
"${SCRIPT_DIR}/examples/math.clj" \
"${SCRIPT_DIR}/build/math.nim"
echo "=== Step 2: Nim → Shared Library ==="
cd "$SCRIPT_DIR" && nim c --app:lib \
--path:"$LIB_PATH" \
-d:release \
-o:"build/libmath.so" \
"native_wrappers.nim"
echo "=== Step 3: Generated files ==="
ls -la "${SCRIPT_DIR}/build/"
echo ""
echo "Library: ${SCRIPT_DIR}/build/libmath.so"
echo ""
echo "To test: cd ${SCRIPT_DIR}/test_client && make && LD_LIBRARY_PATH=../build ./test_client"
+16
View File
@@ -0,0 +1,16 @@
# Generated by Clojure/Nim
import cljnim_runtime
proc square*(x: CljVal): CljVal =
cljMul(@[x, x])
proc cube*(x: CljVal): CljVal =
cljMul(@[x, x, x])
proc add*(a: CljVal, b: CljVal): CljVal =
cljAdd(@[a, b])
proc greet*(name: CljVal): CljVal =
cljStrConcat(@[cljString("Hello, "), name, cljString("!")])
proc factorial*(n: CljVal): CljVal =
if cljIsTruthy(cljNumEq(@[n, cljInt(0)])):
result = cljInt(1)
else:
result = cljMul(@[n, factorial(cljSub(@[n, cljInt(1)]))])
+18
View File
@@ -0,0 +1,18 @@
(ns math)
(defn square [x]
(* x x))
(defn cube [x]
(* x x x))
(defn add [a b]
(+ a b))
(defn greet [name]
(str "Hello, " name "!"))
(defn factorial [n]
(if (= n 0)
1
(* n (factorial (- n 1)))))
@@ -0,0 +1,23 @@
# C-friendly wrappers around Clojure-generated code
# Exports plain C types (int, char*) instead of CljVal
import cljnim_runtime
# Import the generated Clojure functions
include build/math
proc c_square*(x: cint): cint {.exportc, dynlib.} =
let r = square(cljInt(x.int64))
return r.intVal.cint
proc c_factorial*(n: cint): cint {.exportc, dynlib.} =
let r = factorial(cljInt(n.int64))
return r.intVal.cint
proc c_add*(a, b: cint): cint {.exportc, dynlib.} =
let r = add(cljInt(a.int64), cljInt(b.int64))
return r.intVal.cint
proc c_greet*(name: cstring): cstring {.exportc, dynlib.} =
let r = greet(cljString($name))
return r.strVal.cstring
@@ -0,0 +1,11 @@
CC = gcc
CFLAGS = -I../build -L../build
LDFLAGS = -lmath -Wl,-rpath,'$$ORIGIN/../build'
all: test_client
test_client: main.c
$(CC) $(CFLAGS) main.c $(LDFLAGS) -o test_client
clean:
rm -f test_client
+24
View File
@@ -0,0 +1,24 @@
#include <stdio.h>
// Declarations from the shared library
extern int c_square(int x);
extern int c_factorial(int n);
extern int c_add(int a, int b);
extern const char* c_greet(const char* name);
// Nim runtime init
extern void NimMain(void);
int main(void) {
NimMain();
printf("=== Clojure/Nim Native Library Test ===\n\n");
printf("c_square(7) = %d\n", c_square(7));
printf("c_add(10, 20) = %d\n", c_add(10, 20));
printf("c_factorial(5) = %d\n", c_factorial(5));
printf("c_greet(\"World\") = %s\n", c_greet("World"));
printf("\nAll tests passed! Clojure in a .so file.\n");
return 0;
}