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
+86 -2
View File
@@ -2,7 +2,7 @@
# Supports DeepSeek API and OpenAI-compatible APIs (Xiaomi MiMo, etc.)
# API keys are read from environment variables — never hardcoded.
import std/[httpclient, json, os, strutils, uri]
import std/[httpclient, json, os, strutils, uri, tables, times]
type
AiProvider* = enum
@@ -64,6 +64,35 @@ proc detectConfig*(): AiConfig =
proc hasAiConfig*(): bool =
detectConfig().apiKey.len > 0
type
ErrorCacheEntry = object
suggestion: string
timestamp: float64
var errorCache = initTable[string, ErrorCacheEntry]()
var errorCacheMaxSize = 50
proc errorCacheKey(errorMsg, fileName: string): string =
result = fileName & "::" & errorMsg
if result.len > 200:
result = result[0..199]
proc cacheError*(errorMsg, fileName: string, suggestion: string) =
if errorCache.len >= errorCacheMaxSize:
errorCache.clear()
errorCache[errorCacheKey(errorMsg, fileName)] = ErrorCacheEntry(
suggestion: suggestion,
timestamp: epochTime()
)
proc getCachedError*(errorMsg, fileName: string): string =
let key = errorCacheKey(errorMsg, fileName)
if key in errorCache:
let entry = errorCache[key]
if epochTime() - entry.timestamp < 3600.0:
return entry.suggestion
return ""
proc buildErrorPrompt*(errorMsg, sourceCode, fileName: string): string =
## Build a prompt for the AI to analyze a compiler error
result = """You are an expert Clojure/Nim compiler assistant. The user got a compilation error.
@@ -98,6 +127,43 @@ Requirements:
- Return ONLY the Clojure code, no explanations
"""
proc buildOptimizationPrompt*(code: string): string =
## Build a prompt for AI optimization suggestions
result = """You are an expert Clojure performance engineer. Analyze this Clojure code and suggest optimizations:
```clojure
""" & code & """
```
Consider:
- SIMD/vectorization opportunities
- loop/recur vs recursion
- Persistent data structure usage
- Transients for batch operations
- Parallelization opportunities (pmap, reducers)
Keep response under 200 words. Return ONLY Clojure code suggestions, no explanations.
"""
proc buildDebugPrompt*(code: string, evalResult: string): string =
## Build a prompt for AI debugging analysis
result = """You are an expert Clojure debugger. Analyze this Clojure expression and its result:
**Expression:**
```clojure
""" & code & """
```
**Result:**
```
""" & evalResult & """
```
Explain what happened step by step. If there's a bug or unexpected behavior, explain why.
Keep response under 200 words.
Respond in the same language as the user's source code comments (Bulgarian or English).
"""
proc callAiApi*(config: AiConfig, prompt: string): AiResponse =
## Call the AI API and return the response
if config.apiKey.len == 0:
@@ -139,9 +205,15 @@ proc callAiApi*(config: AiConfig, prompt: string): AiResponse =
proc explainError*(errorMsg, sourceCode, fileName: string): AiResponse =
## High-level helper: explain a compiler error using AI
let cached = getCachedError(errorMsg, fileName)
if cached.len > 0:
return AiResponse(ok: true, suggestion: cached)
let config = detectConfig()
let prompt = buildErrorPrompt(errorMsg, sourceCode, fileName)
return callAiApi(config, prompt)
let res = callAiApi(config, prompt)
if res.ok:
cacheError(errorMsg, fileName, res.suggestion)
return res
proc generateCode*(description: string): AiResponse =
## High-level helper: generate Clojure code from description
@@ -149,6 +221,18 @@ proc generateCode*(description: string): AiResponse =
let prompt = buildGenerationPrompt(description)
return callAiApi(config, prompt)
proc optimizeCode*(code: string): AiResponse =
## High-level helper: suggest optimizations for Clojure code
let config = detectConfig()
let prompt = buildOptimizationPrompt(code)
return callAiApi(config, prompt)
proc debugCode*(code: string, evalResult: string): AiResponse =
## High-level helper: debug a Clojure expression and its result
let config = detectConfig()
let prompt = buildDebugPrompt(code, evalResult)
return callAiApi(config, prompt)
proc formatSuggestion*(response: AiResponse): string =
## Format AI response for terminal display
if not response.ok: