Folder support, Custom theme support, Boiler Plate Code support

This commit is contained in:
Alexander R.
2026-07-29 00:51:54 +00:00
parent 0559f7549a
commit 4aa62722c6
108 changed files with 3020 additions and 152 deletions
+61
View File
@@ -0,0 +1,61 @@
"""Convert themes from convert-themes/registry.json into src/tui/themes/*.json"""
import json
import re
from pathlib import Path
REGISTRY_PATH = Path("convert-themes/registry.json")
OUTPUT_DIR = Path("src/tui/themes")
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
if not REGISTRY_PATH.exists():
print(f"Error: {REGISTRY_PATH} not found.")
exit(1)
with open(REGISTRY_PATH, "r", encoding="utf-8") as f:
data = json.load(f)
themes_list = data.get("themes", [])
converted_count = 0
for item in themes_list:
name = item.get("name")
if not name:
continue
dark = item.get("dark") or item.get("light") or {}
if not dark:
continue
theme_id = re.sub(r'[^a-z0-9\-]', '', name.lower().replace(' ', '-'))
if not theme_id:
continue
background = dark.get("mSurfaceVariant") or dark.get("mSurface") or "#1e1e1e"
surface = dark.get("mSurface") or "#252526"
primary = dark.get("mPrimary") or "#3b82f6"
primary_text = dark.get("mOnPrimary") or "#ffffff"
secondary = dark.get("mSecondary") or "#64748b"
accent = dark.get("mTertiary") or dark.get("mHover") or primary
folder_header = accent
folder_text = dark.get("mOnTertiary") or dark.get("mOnHover") or "#ffffff"
theme_dict = {
"id": theme_id,
"name": name,
"background": background,
"surface": surface,
"primary": primary,
"primary_text": primary_text,
"secondary": secondary,
"accent": accent,
"folder_header": folder_header,
"folder_text": folder_text
}
out_file = OUTPUT_DIR / f"{theme_id}.json"
with open(out_file, "w", encoding="utf-8") as f_out:
json.dump(theme_dict, f_out, indent=2)
converted_count += 1
print(f"Successfully converted {converted_count} themes to {OUTPUT_DIR}/!")
+27
View File
@@ -0,0 +1,27 @@
import asyncio
from src.tui.app import TactiTermTUI
async def test_command_palette_integration():
app = TactiTermTUI()
async with app.run_test() as pilot:
print("Available themes count registered with Textual App:", len(app.available_themes))
sample_themes = list(app.available_themes.keys())[:15]
print("Sample registered themes in App:", sample_themes)
# Test system commands
commands = list(app.get_system_commands(app.screen))
cmd_titles = [c.title for c in commands]
print("System commands in Command Palette:", cmd_titles)
assert "Keys" in cmd_titles, "Keys option missing from Command Palette"
assert "Themes" in cmd_titles, "Themes option missing from Command Palette"
# Test applying a theme from registered themes
app.apply_theme("dracula")
await pilot.pause(0.1)
print("Main box classes after applying Dracula:", app.query_one("#main-container").classes)
assert app.query_one("#main-container").has_class("theme-dracula")
print("Command Palette Theme Integration test PASSED!")
if __name__ == "__main__":
asyncio.run(test_command_palette_integration())
+45
View File
@@ -0,0 +1,45 @@
"""Integration test for multi-file code execution, linting, and prompt context formatting."""
import unittest
from src.core.executor import CodeExecutor
from src.core.linter import CodeLinter
from src.core.prompts import format_multifile_context, compress_file_content
class TestMultiFile(unittest.TestCase):
def setUp(self):
self.executor = CodeExecutor()
self.linter = CodeLinter()
def test_cpp_multifile_execution(self):
files = {
"main.cpp": '#include "main.h"\n#include <iostream>\nint main() { printMessage(); return 0; }\n',
"main.h": '#ifndef MAIN_H\n#define MAIN_H\n#include <iostream>\ninline void printMessage() { std::cout << "C++ Multi-File Success!"; }\n#endif\n'
}
res = self.executor.run("cpp", code="", stdin="", files=files)
self.assertEqual(res.get("exit_code"), 0)
self.assertIn("C++ Multi-File Success!", res.get("stdout"))
def test_python_multifile_execution(self):
files = {
"main.py": 'import helper\nprint(helper.get_msg())\n',
"helper.py": 'def get_msg(): return "Python Multi-File Success!"\n'
}
res = self.executor.run("python", code="", stdin="", files=files)
self.assertEqual(res.get("exit_code"), 0)
self.assertIn("Python Multi-File Success!", res.get("stdout"))
def test_multifile_context_formatting(self):
files = {
"main.cpp": '#include "main.h"\nint main() { return 0; }',
"main.h": '#define MSG "Hello"'
}
ctx = format_multifile_context(files, active_file="main.cpp")
self.assertIn("=== File: main.cpp (Active) ===", ctx)
self.assertIn("=== File: main.h ===", ctx)
def test_compression(self):
large_code = "def foo():\n pass\n" * 100
compressed = compress_file_content("test.py", large_code)
self.assertIn("def foo()", compressed)
if __name__ == "__main__":
unittest.main()
+17
View File
@@ -0,0 +1,17 @@
from textual.theme import Theme
from src.tui.theme_manager import theme_manager
print("Loaded theme manager count:", len(theme_manager.themes))
t_sample = list(theme_manager.themes.values())[0]
print("Sample theme data:", t_sample)
t_obj = Theme(
name=t_sample["id"],
primary=t_sample["primary"],
secondary=t_sample.get("secondary"),
accent=t_sample.get("accent"),
background=t_sample["background"],
surface=t_sample["surface"],
dark=True
)
print("Created Textual Theme object successfully:", t_obj.name)
+20
View File
@@ -0,0 +1,20 @@
import asyncio
from src.tui.app import TactiTermTUI
from textual.widgets import OptionList
async def test_theme_popup():
app = TactiTermTUI()
async with app.run_test() as pilot:
print("Call action_cycle_theme()...")
app.action_cycle_theme()
await pilot.pause(0.2)
main_box = app.query_one("#main-container")
print("Is show-theme-menu in classes:", main_box.has_class("show-theme-menu"))
theme_list = app.query_one("#theme_list_popup", OptionList)
print("Theme list option count:", theme_list.option_count)
print("Focused widget ID:", getattr(app.focused, "id", None))
if __name__ == "__main__":
asyncio.run(test_theme_popup())