imxc 0.5.4 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/parser.d.ts CHANGED
@@ -10,6 +10,7 @@ export interface ParseError {
10
10
  line: number;
11
11
  col: number;
12
12
  message: string;
13
+ severity?: 'error' | 'warning';
13
14
  }
14
15
  export declare function parseFile(filePath: string, source: string): ParsedFile;
15
16
  export declare function extractImports(sourceFile: ts.SourceFile): Map<string, string>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,228 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { registerTemplate, buildImxDts, TSCONFIG, GITIGNORE, cmakeTemplate } from './index.js';
4
+ const APPSTATE_INTERFACE = `interface AppState {
5
+ loading: boolean;
6
+ result: string;
7
+ onFetchData: () => void;
8
+ }`;
9
+ const APPSTATE_H = `#pragma once
10
+ #include <string>
11
+ #include <functional>
12
+
13
+ struct AppState {
14
+ bool loading = false;
15
+ std::string result = "";
16
+ std::function<void()> onFetchData;
17
+ };
18
+ `;
19
+ const ASYNC_H = `#pragma once
20
+ #include <thread>
21
+ #include <functional>
22
+ #include <imx/runtime.h>
23
+
24
+ namespace imx {
25
+
26
+ // Runs \`work\` on a background thread, then calls \`on_done\` with the result.
27
+ // Calls request_frame() so the UI wakes up to display the result.
28
+ // Replace with a thread pool if you need to limit concurrency.
29
+ template<typename T>
30
+ void run_async(Runtime& runtime, std::function<T()> work, std::function<void(T)> on_done) {
31
+ std::thread([&runtime, work = std::move(work), on_done = std::move(on_done)]() {
32
+ T result = work();
33
+ on_done(std::move(result));
34
+ runtime.request_frame();
35
+ }).detach();
36
+ }
37
+
38
+ } // namespace imx
39
+ `;
40
+ const MAIN_CPP = `#include <imx/runtime.h>
41
+ #include <imx/renderer.h>
42
+
43
+ #include <imgui.h>
44
+ #include <imgui_impl_glfw.h>
45
+ #include <imgui_impl_opengl3.h>
46
+ #include <GLFW/glfw3.h>
47
+
48
+ #include <thread>
49
+ #include <chrono>
50
+ #include "async.h"
51
+ #include "AppState.h"
52
+
53
+ struct App {
54
+ GLFWwindow* window = nullptr;
55
+ ImGuiIO* io = nullptr;
56
+ imx::Runtime runtime;
57
+ AppState state;
58
+ };
59
+
60
+ static void render_frame(App& app) {
61
+ glfwMakeContextCurrent(app.window);
62
+ if (glfwGetWindowAttrib(app.window, GLFW_ICONIFIED) != 0) return;
63
+
64
+ int fb_w = 0, fb_h = 0;
65
+ glfwGetFramebufferSize(app.window, &fb_w, &fb_h);
66
+ if (fb_w <= 0 || fb_h <= 0) return;
67
+
68
+ ImGui_ImplOpenGL3_NewFrame();
69
+ ImGui_ImplGlfw_NewFrame();
70
+ ImGui::NewFrame();
71
+
72
+ imx::render_root(app.runtime, app.state);
73
+
74
+ ImGui::Render();
75
+ glViewport(0, 0, fb_w, fb_h);
76
+ glClearColor(0.12F, 0.12F, 0.15F, 1.0F);
77
+ glClear(GL_COLOR_BUFFER_BIT);
78
+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
79
+
80
+ if ((app.io->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != 0) {
81
+ ImGui::UpdatePlatformWindows();
82
+ ImGui::RenderPlatformWindowsDefault();
83
+ }
84
+
85
+ glfwMakeContextCurrent(app.window);
86
+ glfwSwapBuffers(app.window);
87
+ }
88
+
89
+ static void window_size_callback(GLFWwindow* window, int, int) {
90
+ auto* app = static_cast<App*>(glfwGetWindowUserPointer(window));
91
+ if (app) render_frame(*app);
92
+ }
93
+
94
+ int main() {
95
+ if (glfwInit() == 0) return 1;
96
+
97
+ const char* glsl_version = "#version 150";
98
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
99
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
100
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
101
+ #ifdef __APPLE__
102
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
103
+ #endif
104
+
105
+ GLFWwindow* window = glfwCreateWindow(800, 600, "APP_NAME", nullptr, nullptr);
106
+ if (!window) { glfwTerminate(); return 1; }
107
+ glfwMakeContextCurrent(window);
108
+ glfwSwapInterval(1);
109
+
110
+ IMGUI_CHECKVERSION();
111
+ ImGui::CreateContext();
112
+ ImGuiIO& io = ImGui::GetIO();
113
+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
114
+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
115
+
116
+ ImGui::StyleColorsDark();
117
+ ImGuiStyle& style = ImGui::GetStyle();
118
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
119
+ style.WindowRounding = 0.0F;
120
+ style.Colors[ImGuiCol_WindowBg].w = 1.0F;
121
+ }
122
+
123
+ ImGui_ImplGlfw_InitForOpenGL(window, true);
124
+ ImGui_ImplOpenGL3_Init(glsl_version);
125
+
126
+ App app;
127
+ app.window = window;
128
+ app.io = &io;
129
+ glfwSetWindowUserPointer(window, &app);
130
+ glfwSetWindowSizeCallback(window, window_size_callback);
131
+
132
+ app.state.onFetchData = [&]() {
133
+ app.state.loading = true;
134
+ app.state.result = "";
135
+ imx::run_async<std::string>(
136
+ app.runtime,
137
+ []() {
138
+ // Simulate work — replace with real computation
139
+ std::this_thread::sleep_for(std::chrono::seconds(2));
140
+ return std::string("Data loaded successfully!");
141
+ },
142
+ [&](std::string res) {
143
+ app.state.result = std::move(res);
144
+ app.state.loading = false;
145
+ }
146
+ );
147
+ };
148
+
149
+ while (glfwWindowShouldClose(window) == 0) {
150
+ if (app.runtime.needs_frame()) {
151
+ glfwPollEvents();
152
+ } else {
153
+ glfwWaitEventsTimeout(0.1);
154
+ }
155
+ render_frame(app);
156
+ app.runtime.frame_rendered(ImGui::IsAnyItemActive());
157
+ }
158
+
159
+ ImGui_ImplOpenGL3_Shutdown();
160
+ ImGui_ImplGlfw_Shutdown();
161
+ ImGui::DestroyContext();
162
+ glfwDestroyWindow(window);
163
+ glfwTerminate();
164
+ return 0;
165
+ }
166
+
167
+ #ifdef _WIN32
168
+ #include <windows.h>
169
+ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { return main(); }
170
+ #endif
171
+ `;
172
+ const APP_TSX = `export default function App(props: AppState) {
173
+ return (
174
+ <DockSpace>
175
+ <Window title="Async Demo">
176
+ <Column gap={8}>
177
+ <Text>Background Task Example</Text>
178
+ <Separator />
179
+ <Button
180
+ title="Fetch Data"
181
+ onPress={props.onFetchData}
182
+ disabled={props.loading}
183
+ />
184
+ {props.loading && <Text color={[1, 0.8, 0, 1]}>Loading...</Text>}
185
+ {props.result !== "" && <Text color={[0, 1, 0, 1]}>Result: {props.result}</Text>}
186
+ </Column>
187
+ </Window>
188
+ </DockSpace>
189
+ );
190
+ }
191
+ `;
192
+ function generate(projectDir, projectName) {
193
+ const srcDir = path.join(projectDir, 'src');
194
+ if (fs.existsSync(path.join(srcDir, 'App.tsx'))) {
195
+ console.error(`Error: ${srcDir}/App.tsx already exists. Aborting.`);
196
+ process.exit(1);
197
+ }
198
+ fs.mkdirSync(srcDir, { recursive: true });
199
+ const publicDir = path.join(projectDir, 'public');
200
+ fs.mkdirSync(publicDir, { recursive: true });
201
+ // Write files
202
+ fs.writeFileSync(path.join(srcDir, 'main.cpp'), MAIN_CPP.replace('APP_NAME', projectName));
203
+ fs.writeFileSync(path.join(srcDir, 'AppState.h'), APPSTATE_H);
204
+ fs.writeFileSync(path.join(srcDir, 'async.h'), ASYNC_H);
205
+ fs.writeFileSync(path.join(srcDir, 'App.tsx'), APP_TSX);
206
+ fs.writeFileSync(path.join(srcDir, 'imx.d.ts'), buildImxDts(APPSTATE_INTERFACE));
207
+ fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), TSCONFIG);
208
+ fs.writeFileSync(path.join(projectDir, 'CMakeLists.txt'), cmakeTemplate(projectName, 'https://github.com/bgocumlu/imx.git'));
209
+ fs.writeFileSync(path.join(projectDir, '.gitignore'), GITIGNORE);
210
+ console.log(`imxc: initialized project "${projectName}" with template "async"`);
211
+ console.log('');
212
+ console.log(' Created:');
213
+ console.log(` src/main.cpp — app shell with background task setup`);
214
+ console.log(` src/AppState.h — C++ state struct with loading/result fields`);
215
+ console.log(` src/async.h — run_async<T> helper (std::thread + request_frame)`);
216
+ console.log(` src/App.tsx — your root component`);
217
+ console.log(` src/imx.d.ts — type definitions for IDE support`);
218
+ console.log(` tsconfig.json — TypeScript config`);
219
+ console.log(` CMakeLists.txt — build config with FetchContent`);
220
+ console.log(` .gitignore — ignores build/, node_modules/, *.ini`);
221
+ console.log(` public/ — static assets (copied to exe directory)`);
222
+ console.log('');
223
+ console.log(' Next steps:');
224
+ console.log(` cd ${projectName}`);
225
+ console.log(` cmake -B build`);
226
+ console.log(` cmake --build build`);
227
+ }
228
+ registerTemplate({ name: 'async', description: 'Background tasks with std::thread', generate });
@@ -0,0 +1,15 @@
1
+ export interface FeatureModule {
2
+ name: string;
3
+ description: string;
4
+ requires?: string[];
5
+ includes: string[];
6
+ appStateCppFields: string;
7
+ appStateCppHeaders: string[];
8
+ appStateTsFields: string;
9
+ callbacks: string;
10
+ tsxWindow: string;
11
+ extraFiles: Record<string, string>;
12
+ dataFields?: string[];
13
+ }
14
+ export declare const FEATURES: FeatureModule[];
15
+ export declare function generateCombined(featureNames: string[], projectDir: string, projectName: string): void;