2026-03-01 21:34:43 +08:00
|
|
|
|
using CMLeonOS;
|
|
|
|
|
|
using CMLeonOS.Gui.UILib;
|
|
|
|
|
|
using Cosmos.System.Graphics;
|
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using UniLua;
|
|
|
|
|
|
|
|
|
|
|
|
namespace CMLeonOS.Gui.Apps.CodeStudio
|
|
|
|
|
|
{
|
|
|
|
|
|
internal class Ide
|
|
|
|
|
|
{
|
|
|
|
|
|
internal Ide(Process process, WindowManager wm)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.process = process;
|
|
|
|
|
|
this.wm = wm;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.CodeStudio.Run.bmp")]
|
|
|
|
|
|
private static byte[] _runBytes;
|
|
|
|
|
|
private static Bitmap runBitmap = new Bitmap(_runBytes);
|
|
|
|
|
|
|
|
|
|
|
|
Process process;
|
|
|
|
|
|
|
|
|
|
|
|
WindowManager wm;
|
|
|
|
|
|
|
|
|
|
|
|
AppWindow mainWindow;
|
|
|
|
|
|
|
|
|
|
|
|
Button runButton;
|
|
|
|
|
|
|
2026-03-02 21:42:44 +08:00
|
|
|
|
CodeEditor editor;
|
2026-03-01 21:34:43 +08:00
|
|
|
|
|
|
|
|
|
|
TextBox problems;
|
|
|
|
|
|
|
|
|
|
|
|
TextBox output;
|
|
|
|
|
|
|
2026-03-02 21:42:44 +08:00
|
|
|
|
FileBrowser fileBrowser;
|
|
|
|
|
|
|
2026-03-01 21:34:43 +08:00
|
|
|
|
private const int headersHeight = 24;
|
|
|
|
|
|
private const int problemsHeight = 128;
|
|
|
|
|
|
private const int outputHeight = 128;
|
|
|
|
|
|
|
|
|
|
|
|
private string? path = null;
|
|
|
|
|
|
|
|
|
|
|
|
private bool modified = false;
|
|
|
|
|
|
|
|
|
|
|
|
private void TextChanged()
|
|
|
|
|
|
{
|
|
|
|
|
|
modified = true;
|
|
|
|
|
|
|
|
|
|
|
|
UpdateTitle();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static class Theme
|
|
|
|
|
|
{
|
|
|
|
|
|
internal static Color Background = Color.FromArgb(68, 76, 84);
|
|
|
|
|
|
internal static Color CodeBackground = Color.FromArgb(41, 46, 51);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateTitle()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (path == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow.Title = "Untitled - Lua CodeStudio";
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (modified)
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow.Title = $"{Path.GetFileName(path)}* - Lua CodeStudio";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow.Title = $"{Path.GetFileName(path)} - Lua CodeStudio";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal void Open(string newPath, bool readFile = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newPath == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (readFile && !File.Exists(newPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox messageBox = new MessageBox(process, "Lua CodeStudio", $"No such file '{Path.GetFileName(newPath)}'.");
|
|
|
|
|
|
messageBox.Show();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
path = newPath;
|
|
|
|
|
|
|
|
|
|
|
|
if (readFile)
|
|
|
|
|
|
{
|
|
|
|
|
|
editor.Text = File.ReadAllText(path);
|
|
|
|
|
|
|
2026-03-02 21:42:44 +08:00
|
|
|
|
string extension = Path.GetExtension(path).ToLower();
|
|
|
|
|
|
editor.SetSyntaxHighlighting(extension == ".lua", extension);
|
|
|
|
|
|
|
2026-03-01 21:34:43 +08:00
|
|
|
|
editor.MarkAllLines();
|
|
|
|
|
|
editor.Render();
|
|
|
|
|
|
|
|
|
|
|
|
modified = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateTitle();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OpenFilePrompt()
|
|
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
fileBrowser = new FileBrowser(process, wm, (string selectedPath) =>
|
2026-03-01 21:34:43 +08:00
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
if (selectedPath != null)
|
2026-03-01 21:34:43 +08:00
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
Open(selectedPath);
|
2026-03-01 21:34:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-03-02 21:42:44 +08:00
|
|
|
|
fileBrowser.Show();
|
2026-03-01 21:34:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SaveAsPrompt()
|
|
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
fileBrowser = new FileBrowser(process, wm, (string selectedPath) =>
|
2026-03-01 21:34:43 +08:00
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
if (selectedPath != null)
|
2026-03-01 21:34:43 +08:00
|
|
|
|
{
|
2026-03-02 21:42:44 +08:00
|
|
|
|
path = selectedPath;
|
2026-03-01 21:34:43 +08:00
|
|
|
|
Save();
|
|
|
|
|
|
}
|
2026-03-02 21:42:44 +08:00
|
|
|
|
}, selectDirectoryOnly: true);
|
|
|
|
|
|
fileBrowser.Show();
|
2026-03-01 21:34:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Save()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (path == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
SaveAsPrompt();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
File.WriteAllText(path, editor.Text);
|
|
|
|
|
|
|
|
|
|
|
|
modified = false;
|
|
|
|
|
|
UpdateTitle();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RunClicked(int x, int y)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
output.Text = "";
|
|
|
|
|
|
|
|
|
|
|
|
ILuaState lua = LuaAPI.NewState();
|
|
|
|
|
|
lua.L_OpenLibs();
|
|
|
|
|
|
|
|
|
|
|
|
lua.PushCSharpFunction(L =>
|
|
|
|
|
|
{
|
|
|
|
|
|
int n = L.GetTop();
|
|
|
|
|
|
string result = "";
|
|
|
|
|
|
for (int i = 1; i <= n; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (i > 1) result += "\t";
|
|
|
|
|
|
LuaType type = L.Type(i);
|
|
|
|
|
|
if (type == LuaType.LUA_TSTRING)
|
|
|
|
|
|
{
|
|
|
|
|
|
result += L.ToString(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (type == LuaType.LUA_TBOOLEAN)
|
|
|
|
|
|
{
|
|
|
|
|
|
result += L.ToBoolean(i) ? "true" : "false";
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (type == LuaType.LUA_TNUMBER)
|
|
|
|
|
|
{
|
|
|
|
|
|
result += L.ToNumber(i).ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (type == LuaType.LUA_TNIL)
|
|
|
|
|
|
{
|
|
|
|
|
|
result += "nil";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
output.Text += result + "\n";
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
});
|
|
|
|
|
|
lua.SetGlobal("print");
|
|
|
|
|
|
|
|
|
|
|
|
UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadResult == UniLua.ThreadStatus.LUA_OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
UniLua.ThreadStatus callResult = lua.PCall(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (callResult == UniLua.ThreadStatus.LUA_OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.LimeGreen;
|
|
|
|
|
|
problems.Text = "Execution successful";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string errorMsg = lua.ToString(-1);
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = $"Script execution error: {errorMsg}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string errorMsg = lua.ToString(-1);
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = $"Script load error: {errorMsg}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = e.Message;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Evaluate()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ILuaState lua = LuaAPI.NewState();
|
|
|
|
|
|
lua.L_OpenLibs();
|
|
|
|
|
|
UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadResult == UniLua.ThreadStatus.LUA_OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.LimeGreen;
|
|
|
|
|
|
problems.Text = "No syntax errors";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string errorMsg = lua.ToString(-1);
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(errorMsg))
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = "Script load error: Unknown error";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = $"Script load error: {errorMsg}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
problems.Foreground = Color.Pink;
|
|
|
|
|
|
problems.Text = e.Message;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow = new AppWindow(process, 96, 96, 800, 600);
|
|
|
|
|
|
mainWindow.Clear(Theme.Background);
|
|
|
|
|
|
mainWindow.Closing = process.TryStop;
|
|
|
|
|
|
UpdateTitle();
|
|
|
|
|
|
wm.AddWindow(mainWindow);
|
|
|
|
|
|
|
|
|
|
|
|
runButton = new Button(mainWindow, 0, 0, 60, headersHeight);
|
|
|
|
|
|
runButton.Background = Theme.Background;
|
|
|
|
|
|
runButton.Border = Theme.Background;
|
|
|
|
|
|
runButton.Foreground = Color.White;
|
|
|
|
|
|
runButton.Text = "Run";
|
|
|
|
|
|
runButton.Image = runBitmap;
|
|
|
|
|
|
runButton.ImageLocation = Button.ButtonImageLocation.Left;
|
|
|
|
|
|
runButton.OnClick = RunClicked;
|
|
|
|
|
|
wm.AddWindow(runButton);
|
|
|
|
|
|
|
2026-03-02 21:42:44 +08:00
|
|
|
|
editor = new CodeEditor(mainWindow, 0, headersHeight, mainWindow.Width, mainWindow.Height - headersHeight - problemsHeight - outputHeight - (headersHeight * 3))
|
2026-03-01 21:34:43 +08:00
|
|
|
|
{
|
|
|
|
|
|
Background = Theme.CodeBackground,
|
|
|
|
|
|
Foreground = Color.White,
|
|
|
|
|
|
Text = "print(\"Hello World!\")",
|
|
|
|
|
|
Changed = TextChanged,
|
|
|
|
|
|
MultiLine = true
|
|
|
|
|
|
};
|
2026-03-02 21:42:44 +08:00
|
|
|
|
editor.SetSyntaxHighlighting(true, ".lua");
|
2026-03-01 21:34:43 +08:00
|
|
|
|
wm.AddWindow(editor);
|
|
|
|
|
|
|
|
|
|
|
|
problems = new TextBox(mainWindow, 0, headersHeight + editor.Height + headersHeight, mainWindow.Width, problemsHeight + (headersHeight * 2))
|
|
|
|
|
|
{
|
|
|
|
|
|
Background = Theme.CodeBackground,
|
|
|
|
|
|
Foreground = Color.Gray,
|
|
|
|
|
|
Text = "Click Evaluate to check your program for syntax errors.",
|
|
|
|
|
|
ReadOnly = true,
|
|
|
|
|
|
MultiLine = true
|
|
|
|
|
|
};
|
|
|
|
|
|
wm.AddWindow(problems);
|
|
|
|
|
|
|
|
|
|
|
|
mainWindow.DrawString("Problems", Color.White, 0, headersHeight + editor.Height);
|
|
|
|
|
|
|
|
|
|
|
|
output = new TextBox(mainWindow, 0, headersHeight + editor.Height + problemsHeight + (headersHeight * 2), mainWindow.Width, outputHeight + (headersHeight * 2))
|
|
|
|
|
|
{
|
|
|
|
|
|
Background = Theme.CodeBackground,
|
|
|
|
|
|
Foreground = Color.White,
|
|
|
|
|
|
Text = "Output will appear here...",
|
|
|
|
|
|
ReadOnly = true,
|
|
|
|
|
|
MultiLine = true
|
|
|
|
|
|
};
|
|
|
|
|
|
wm.AddWindow(output);
|
|
|
|
|
|
|
|
|
|
|
|
mainWindow.DrawString("Output", Color.White, 0, headersHeight + editor.Height + problemsHeight + headersHeight);
|
|
|
|
|
|
|
|
|
|
|
|
var shortcutBar = new ShortcutBar(mainWindow, runButton.Width, 0, mainWindow.Width - runButton.Width, headersHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
Background = Theme.Background,
|
|
|
|
|
|
Foreground = Color.White
|
|
|
|
|
|
};
|
|
|
|
|
|
shortcutBar.Cells.Add(new ShortcutBarCell("Open", OpenFilePrompt));
|
|
|
|
|
|
shortcutBar.Cells.Add(new ShortcutBarCell("Save", Save));
|
|
|
|
|
|
shortcutBar.Cells.Add(new ShortcutBarCell("Save As", SaveAsPrompt));
|
|
|
|
|
|
shortcutBar.Cells.Add(new ShortcutBarCell("Evaluate", Evaluate));
|
|
|
|
|
|
shortcutBar.Render();
|
|
|
|
|
|
wm.AddWindow(shortcutBar);
|
|
|
|
|
|
|
|
|
|
|
|
wm.Update(mainWindow);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|