cluaupp 0.1.2 → 0.1.5

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +10 -13
  3. package/docs/README.md +13 -10
  4. package/docs/architecture.md +30 -73
  5. package/docs/cli.md +5 -6
  6. package/docs/comparison.md +3 -3
  7. package/docs/config.md +6 -6
  8. package/docs/cpp-advanced.md +10 -6
  9. package/docs/cpp-organization.md +4 -2
  10. package/docs/cpp-safety.md +11 -7
  11. package/docs/cpp-types.md +1 -1
  12. package/docs/examples/_category_.json +5 -0
  13. package/docs/examples/combat.md +239 -0
  14. package/docs/examples/data-boot.md +98 -0
  15. package/docs/examples/hud.md +96 -0
  16. package/docs/examples/index.md +43 -0
  17. package/docs/examples/leaderstats.md +140 -0
  18. package/docs/examples/shop.md +122 -0
  19. package/docs/examples/sword.md +108 -0
  20. package/docs/getting-started.md +14 -7
  21. package/docs/intellisense.md +31 -0
  22. package/docs/intro.md +3 -3
  23. package/docs/libraries/_category_.json +5 -0
  24. package/docs/libraries/dataservice.md +104 -0
  25. package/docs/libraries/index.md +22 -0
  26. package/docs/libraries/janitor.md +65 -0
  27. package/docs/libraries/more.md +79 -0
  28. package/docs/libraries/net.md +35 -0
  29. package/docs/libraries/promise.md +27 -0
  30. package/docs/oop/_category_.json +5 -0
  31. package/docs/oop/file-tags.md +48 -0
  32. package/docs/oop/index.md +22 -0
  33. package/docs/oop/modules.md +88 -0
  34. package/docs/oop/services.md +76 -0
  35. package/docs/print-cout.md +91 -0
  36. package/docs/syntax.md +63 -8
  37. package/editors/vscode/extension.js +146 -0
  38. package/editors/vscode/package.json +25 -0
  39. package/include/cluaupp/libs/janitor.hpp +7 -3
  40. package/include/cluaupp/roblox.hpp +19 -0
  41. package/package.json +66 -65
  42. package/runtime/Janitor/init.luau +4 -34
  43. package/src/architecture.js +174 -66
  44. package/src/cli.js +88 -21
  45. package/src/client/init.client.cpp +5 -0
  46. package/src/compile.js +77 -7
  47. package/src/editor-install.js +218 -0
  48. package/src/emit.js +321 -9
  49. package/src/headers.js +234 -0
  50. package/src/intellisense.js +1368 -0
  51. package/src/layout.js +129 -0
  52. package/src/lex.js +17 -9
  53. package/src/libs.js +165 -18
  54. package/src/lsp.js +227 -0
  55. package/src/parse.js +187 -6
  56. package/src/preprocess.js +118 -3
  57. package/src/server/leaderstats.server.cpp +28 -0
  58. package/src/shared/config.cpp +5 -0
  59. package/src/shared/config.h +3 -0
  60. package/src/understand.js +66 -6
  61. package/templates/game/.clangd +11 -0
  62. package/templates/game/.vscode/c_cpp_properties.json +6 -2
  63. package/templates/game/.vscode/extensions.json +6 -0
  64. package/templates/game/.vscode/settings.json +16 -2
  65. package/templates/game/cluaupp.config.json +2 -2
  66. package/templates/game/compile_flags.txt +2 -0
  67. package/templates/game/src/client/init.client.cpp +1 -0
  68. package/templates/game/src/server/leaderstats.server.cpp +1 -0
  69. package/docs/libraries.md +0 -80
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: File tags
3
+ sidebar_position: 2
4
+ ---
5
+
6
+ # File tags
7
+
8
+ The **filename** decides the Roblox instance. This is the same key idea as roblox-ts (`*.server.ts` → Script).
9
+
10
+ | Source | Instance | RunContext |
11
+ | --- | --- | --- |
12
+ | `LeaderstatsServer.server.cpp` | **Script** | **Server** |
13
+ | `DataBoot.client.cpp` | **LocalScript** | Client |
14
+ | `Tools.plugin.cpp` | **Script** | Plugin |
15
+ | `Boot.legacy.cpp` | Script | **Legacy** |
16
+ | `Boot.legacy.server.cpp` | Script | **Legacy** |
17
+ | `Boot.legacy.client.cpp` | LocalScript | Legacy |
18
+ | `Damage.cpp` (no tag) | **ModuleScript** | — |
19
+ | `LeaderstatsServer.h` | **ModuleScript** (types) | — |
20
+ | `LeaderstatsServer.cpp` (sibling of `.h`) | **ModuleScript** (`*Impl`) | — |
21
+
22
+ ## One file in, one file out
23
+
24
+ Rojo infers the instance from the filename key: `*.server.luau` is a Script, `*.client.luau` is a LocalScript, untagged `.luau` is a ModuleScript.
25
+
26
+ ```
27
+ src/server/boot/DataBoot.server.cpp → out/server/boot/DataBoot.server.luau
28
+ src/client/boot/DataBoot.client.cpp → out/client/boot/DataBoot.client.luau
29
+ src/shared/damage.cpp → out/shared/Damage.luau
30
+ src/server/services/leaderstats/LeaderstatsServer.h → LeaderstatsServer.luau (export type)
31
+ src/server/services/leaderstats/LeaderstatsServer.cpp → LeaderstatsServerImpl.luau
32
+ ```
33
+
34
+ `.legacy.server.cpp` still emits a Legacy Script (`boot.server.luau`). `.client.cpp` stays a LocalScript. Do not invent `init.meta.json` on the default 1:1 path.
35
+
36
+ ## Where files live
37
+
38
+ ```
39
+ src/server/.../*.server.cpp → out/server (ServerScriptService.Cluaupp)
40
+ src/client/.../*.client.cpp → out/client (StarterPlayerScripts.Cluaupp)
41
+ src/shared/.../*.cpp → out/shared (ReplicatedStorage.Cluaupp)
42
+ ```
43
+
44
+ Name the **system**, not `init.server.cpp`. `LeaderstatsServer.server.cpp` and `DataBoot.server.cpp` are two files.
45
+
46
+ ## Opt-in planner
47
+
48
+ `"architecture": true` in `cluaupp.config.json` restores PascalCase service folders (`Main`, Controller, Types). Default is off.
@@ -0,0 +1,22 @@
1
+ ---
2
+ title: OOP structure
3
+ sidebar_position: 1
4
+ ---
5
+
6
+ # OOP structure
7
+
8
+ The **live site** (not just these markdown files) is GitHub Pages:
9
+
10
+ - [Learn → OOP structure](https://kartzrbx.github.io/Cluaupp/learn/index.html)
11
+ - [Guide → OOP](https://kartzrbx.github.io/Cluaupp/guide/oop.html)
12
+ - [Examples](https://kartzrbx.github.io/Cluaupp/guide/examples.html)
13
+
14
+ Cluaupp does **not** compile custom C++ `class` types yet. “OOP” here is how you **lay out systems** so Studio gets Script / LocalScript / ModuleScript from the filename tag — the same idea as roblox-ts. Flamework-style Start/Stop folders are opt-in (`"architecture": true`).
15
+
16
+ | Page | What you learn |
17
+ | --- | --- |
18
+ | [File tags](file-tags.md) | `.server` / `.client` / `.plugin` / `.legacy` / untagged |
19
+ | [Services](services.md) | One `.server.cpp` → one `.server.luau` |
20
+ | [Modules](modules.md) | Untagged files, structs, named functions as methods |
21
+
22
+ Planner details: [Architecture](../architecture.md). Folder layout: [Organization](../cpp-organization.md). Full services: [Examples](../examples/index.md).
@@ -0,0 +1,88 @@
1
+ ---
2
+ title: Modules and structs
3
+ sidebar_position: 4
4
+ ---
5
+
6
+ # Modules and structs
7
+
8
+ Use this when you want a **reusable object** without a tagged Script.
9
+
10
+ ## Untagged `.cpp` = ModuleScript
11
+
12
+ ```
13
+ src/shared/util/Coins.cpp
14
+ ```
15
+
16
+ ```cpp
17
+ #include <cluaupp/roblox.hpp>
18
+
19
+ int DoubleCoins(int coins) {
20
+ return coins;
21
+ }
22
+ ```
23
+
24
+ ```
25
+ out/shared/util/Coins.luau -- ModuleScript, exported functions
26
+ ```
27
+
28
+ Quoted `#include "TemplateData.hpp"` is not inlined when the header has a sibling `.cpp` or is a shared module: `cluaupp build` emits `require(ReplicatedStorage.Cluaupp.constants.TemplateData)` / `require(ServerScriptService.Cluaupp.configurations.PlayerDataVersion)` (Rojo roots from `default.project.json`), never `script.Parent.Parent.shared`.
29
+
30
+ `.h` / `.hpp` are **type modules**. A service header becomes `export type Name = { init: (self: Name) -> (), … }` and a typed table. The sibling `.cpp` is the construction (`NameImpl.luau`); the header `require`s that impl and binds the functions. Data-only structs still emit a constructor so `TemplateData()` works. Untagged `.cpp` without a header is a ModuleScript other Luau can `require`. Prefer headers for the public type, tagged `.server.cpp` / `.client.cpp` for scripts, and the sibling `.cpp` for method bodies.
31
+
32
+ ## Structs = data, not classes
33
+
34
+ The subset allows structs for IntelliSense and designated initializers (tables):
35
+
36
+ ```cpp
37
+ struct TemplateData {
38
+ struct Currencies {
39
+ int Money = 0;
40
+ int Level = 1;
41
+ } Currencies;
42
+ };
43
+
44
+ TemplateData playerData = TemplateData {};
45
+ ```
46
+
47
+ That is your “class fields”. Methods are **named functions** next to them (`EnsureStat`, `ApplyCurrencies`). Cluaupp does not emit `function TemplateData:GetMoney()`.
48
+
49
+ ## Methods as functions
50
+
51
+ ```cpp
52
+ void EnsureStat(Folder* folder, string name, int value) {
53
+ auto* stat = folder->FindFirstChild(name);
54
+ if (stat == nullptr) {
55
+ cout::print << "EnsureStat: " << name << " not found" << endl;
56
+ return;
57
+ }
58
+ }
59
+ ```
60
+
61
+ Pass the instance in (`folder`, `player`). That is composition: the Folder is the object, the function is the method.
62
+
63
+ ## Janitor as the destructor
64
+
65
+ There is no C++ destructor. Pair “construct” with a Janitor:
66
+
67
+ ```cpp
68
+ auto* janitor = new Janitor();
69
+ janitor->LinkToInstance(player);
70
+ janitor->Add(player->AncestryChanged.Connect(OnAncestry));
71
+ ```
72
+
73
+ When the player leaves, `LinkToInstance` runs `Cleanup`. That is RAII for Roblox.
74
+
75
+ ## Start / Stop
76
+
77
+ On generated services, `Main.Start` / `Main.Stop` are the constructor / destructor of the **system**. Put connections in Start (or in `init()` / `PlayersManager`). Do not leak `Connect` without a Janitor.
78
+
79
+ ## What not to write
80
+
81
+ ```cpp
82
+ class Shop {
83
+ int price;
84
+ void Buy(Player* player);
85
+ };
86
+ ```
87
+
88
+ Custom classes are **not supported**. Split into a struct (fields) + functions (methods) + a `.server.cpp` or untagged module (lifetime).
@@ -0,0 +1,76 @@
1
+ ---
2
+ title: Services
3
+ sidebar_position: 3
4
+ ---
5
+
6
+ # Services
7
+
8
+ Write **one tagged file per system**. Cluaupp emits **one** Luau instance: `LeaderstatsServer.server.luau` from `LeaderstatsServer.server.cpp`. It does not invent Main / Controller / Types unless `"architecture": true`.
9
+
10
+ ## Example: leaderstats
11
+
12
+ ```cpp
13
+ #include <cluaupp/roblox.hpp>
14
+ #include <cluaupp/libs/janitor.hpp>
15
+ #include <cluaupp/libs/dataservice.hpp>
16
+
17
+ void EnsureStat(Folder* folder, string name, int value) {
18
+ return;
19
+ }
20
+
21
+ void ApplyCurrencies(Player* player, Data* data) {
22
+ return;
23
+ }
24
+
25
+ void OnCurrenciesChanged() {
26
+ return;
27
+ }
28
+
29
+ void SetupPlayerManager(Player* player) {
30
+ Data* data = DataService::Server.WaitFor(player);
31
+ if (data == nullptr) {
32
+ return;
33
+ }
34
+ ApplyCurrencies(player, data);
35
+ data->GetChangedSignal(DataService::Server.Paths.Currencies).Connect(OnCurrenciesChanged);
36
+ }
37
+
38
+ void init() {
39
+ auto* players = GetService<Players>();
40
+ players->PlayerAdded.Connect(SetupPlayerManager);
41
+ }
42
+ ```
43
+
44
+ Typical output:
45
+
46
+ ```
47
+ out/server/services/leaderstats/LeaderstatsServer.server.luau
48
+ ```
49
+
50
+ Your functions stay in that file. `init()` runs at the end. There is no fake `Main` that only forwards to a Controller.
51
+
52
+ ## Lifecycle
53
+
54
+ You own `init` and Janitor cleanup in the same file. You do not write `class LeaderstatsServer` — name the **file** `LeaderstatsServer.server.cpp` and keep **functions** as the public API.
55
+
56
+ `"architecture": true` is the old ForeverHD split (`Main.Start` / `Main.Stop`, Managers, Types). Leave it off unless you want that.
57
+
58
+ ## Boot vs gameplay
59
+
60
+ Keep DataService `Init` in `DataBoot.server.cpp` / `DataBoot.client.cpp`. Keep leaderstats / combat in their own `.server.cpp`. Services `WaitFor` after boot has run.
61
+
62
+ ## Opt-in roles (`"architecture": true`)
63
+
64
+ | Your C++ | Generated role |
65
+ | --- | --- |
66
+ | `PlayerAdded`, `GetPlayers` | `PlayersManager` |
67
+ | `Folder` + `IntValue` | `CacheController` |
68
+ | `DataService`, `GetChangedSignal` | `DataController` |
69
+ | `TakeDamage`, `Humanoid` | `CombatController` |
70
+ | `Net::Event` | `NetController` |
71
+ | `UserInputService` | `InputController` |
72
+ | wiring | `Main.Start` / `Main.Stop` |
73
+
74
+ A tiny `print` in `init.client.cpp` stays a single LocalScript.
75
+
76
+ Copy-paste: [Examples](../examples/index.md).
@@ -0,0 +1,91 @@
1
+ ---
2
+ title: print and cout
3
+ sidebar_position: 8
4
+ ---
5
+
6
+ # print and cout
7
+
8
+ Cluaupp has no `<iostream>`. Logging is Roblox `print` / `warn` / `error`. You can still write C++-style `cout` / `cerr` / `endl` — the compiler flattens them.
9
+
10
+ ## Globals
11
+
12
+ ```cpp
13
+ print("ok");
14
+ warn("careful");
15
+ error("fail");
16
+ ```
17
+
18
+ ```luau
19
+ print("ok")
20
+ warn("careful")
21
+ error("fail")
22
+ ```
23
+
24
+ `print` in C++ takes a string (and chained `cout` pieces). Do not expect full C++ `std::cout` overloads.
25
+
26
+ ## Stream: `cout << … << endl`
27
+
28
+ Each `<<` is another argument. `endl` ends the statement (no extra `"\n"`).
29
+
30
+ ```cpp
31
+ cout << "EnsureStat: " << name << " not found" << endl;
32
+ ```
33
+
34
+ ```luau
35
+ print("EnsureStat: ", name, " not found")
36
+ ```
37
+
38
+ `cerr` is the same chain, emitted as `warn`:
39
+
40
+ ```cpp
41
+ cerr << "failed to load " << player->Name << endl;
42
+ ```
43
+
44
+ ```luau
45
+ warn("failed to load ", player.Name)
46
+ ```
47
+
48
+ ## Levels: `cout::print` / `warn` / `error` / `ping`
49
+
50
+ Use `::` to pick the Roblox function. The stream still concatenates with `<<`.
51
+
52
+ ```cpp
53
+ cout::print << "EnsureStat test: " << name << " not found" << endl;
54
+ cout::warn << "missing folder for " << player->Name << endl;
55
+ cout::error << "profile failed" << endl;
56
+ cout::ping << "here" << endl;
57
+ ```
58
+
59
+ ```luau
60
+ print("EnsureStat test: ", name, " not found")
61
+ warn("missing folder for ", player.Name)
62
+ error("profile failed")
63
+ print("here")
64
+ ```
65
+
66
+ | C++ | Luau |
67
+ | --- | --- |
68
+ | `cout << … << endl` | `print(…)` |
69
+ | `cout::print << … << endl` | `print(…)` |
70
+ | `cout::warn << … << endl` | `warn(…)` |
71
+ | `cout::error << … << endl` | `error(…)` |
72
+ | `cout::ping << … << endl` | `print(…)` |
73
+ | `cerr << … << endl` | `warn(…)` |
74
+
75
+ `cout::ping` is a debug alias of `print` (no extra Studio highlight).
76
+
77
+ ## Call form (no `<<`)
78
+
79
+ ```cpp
80
+ cout::print("ok");
81
+ cout::warn("careful");
82
+ cout::error("fail");
83
+ cout::ping("here");
84
+ cout::endl();
85
+ ```
86
+
87
+ `cout::endl()` is a no-op in Luau (flush is already the statement). Prefer `<< endl` on a stream.
88
+
89
+ ## IntelliSense
90
+
91
+ `struct cout` / `cerr` and `endl` live in `<cluaupp/roblox.hpp>`. Include that header so clangd knows `cout::print` and `operator<<`.
package/docs/syntax.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  Cluaupp is not a full C++ compiler. It is a **subset** aimed at Roblox scripts, in the same spirit as roblox-ts (restricted TypeScript → Luau).
4
4
 
5
- Generated Luau follows the current language: [`--!strict`](https://luau.org/getting-started), `local`, and `const`.
5
+ Generated Luau follows the current language: [`local`](https://luau.org/getting-started), `const`, and `const function`. Injected `require` / `GetService` lines are `const`. `--!strict` is emitted only when the file has `#pragma strict` (or `"strict": true` in config).
6
6
 
7
7
  ## Files
8
8
 
9
9
  - Extensions: `.cpp`, `.h`, `.hpp` (also `.cc`, `.hh`)
10
- - Quoted `#include "file.h"` is inlined (C preprocessor)
10
+ - Quoted `#include "file.h"` becomes a Rojo `require` (or is inlined for a header that belongs to the same `.cpp`)
11
11
  - `#include <cluaupp/roblox.hpp>` and `<cluaupp/libs/*.hpp>` are IntelliSense only; library headers also inject `require(CluauppLibs.*)`
12
- - Other `#` lines (`#pragma once`) are ignored
13
- - Function prototypes (`void foo();`) are skipped; only functions with a body are emitted
12
+ - `#pragma once` is ignored
13
+ - `#pragma strict` / `#pragma nstrict` control `--!strict` for that compilation unit
14
+ - Function prototypes in a `.h` / `.hpp` become `export type` fields (`init: (self: Name) -> ()`). Only `.cpp` files emit function bodies.
14
15
 
15
16
  ## Functions
16
17
 
@@ -25,11 +26,11 @@ int doubleCoins(int coins) {
25
26
  ```
26
27
 
27
28
  ```luau
28
- local function CreateLeaderstats(player: Player)
29
+ const function CreateLeaderstats(player: Player)
29
30
  return
30
31
  end
31
32
 
32
- local function doubleCoins(coins: number): number
33
+ const function doubleCoins(coins: number): number
33
34
  return coins
34
35
  end
35
36
  ```
@@ -73,6 +74,22 @@ while (true) {
73
74
  for (auto* player : players->GetPlayers()) {
74
75
  CreateLeaderstats(player);
75
76
  }
77
+
78
+ switch (action) {
79
+ case "buy":
80
+ case "purchase":
81
+ Grant(player);
82
+ break;
83
+ case "sell":
84
+ if (amount <= 0) {
85
+ break;
86
+ }
87
+ Take(player);
88
+ break;
89
+ default:
90
+ warn("unknown");
91
+ break;
92
+ }
76
93
  ```
77
94
 
78
95
  ```luau
@@ -89,9 +106,22 @@ end
89
106
  for _, player in players:GetPlayers() do
90
107
  CreateLeaderstats(player)
91
108
  end
109
+
110
+ repeat
111
+ if action == "buy" or action == "purchase" then
112
+ Grant(player)
113
+ elseif action == "sell" then
114
+ if amount <= 0 then
115
+ break
116
+ end
117
+ Take(player)
118
+ else
119
+ warn("unknown")
120
+ end
121
+ until true
92
122
  ```
93
123
 
94
- The only `for` accepted today is **range-for**: `for (auto* x : list)`. C-style `for (int i = 0; i < n; i++)` is not supported yet.
124
+ `switch` evaluates the discriminant **once**, then becomes `if` / `elseif` / `else` inside `repeat … until true` so `break` still exits the switch (even from inside an `if`). Stacked `case` labels share a body (`case "buy": case "purchase":`). There is no C-style fall-through into the next case’s statements. C-style `for (int i = 0; i < n; i++)` is not supported yet.
95
125
 
96
126
  ## Expressions
97
127
 
@@ -143,8 +173,33 @@ local players: Players = game:GetService("Players")
143
173
 
144
174
  The first argument of `new Class(parent)` becomes `.Parent`. With no argument: `Instance.new("Class")` only.
145
175
 
176
+ ## print / cout
177
+
178
+ `print`, `warn`, and `error` work as in Luau. `cout << … << endl` is the C++ spelling — each `<<` is another argument, `endl` ends the line. `cout::warn` / `cout::error` / `cout::ping` pick the Roblox function.
179
+
180
+ ```cpp
181
+ cout << "EnsureStat: " << name << " not found" << endl;
182
+ cout::print << "EnsureStat: " << name << " not found" << endl;
183
+ cerr << "failed";
184
+ cout::print("ok");
185
+ cout::warn("careful");
186
+ cout::error("fail");
187
+ cout::ping("here");
188
+ ```
189
+
190
+ ```luau
191
+ print("EnsureStat: ", name, " not found")
192
+ warn("failed")
193
+ print("ok")
194
+ warn("careful")
195
+ error("fail")
196
+ print("here")
197
+ ```
198
+
199
+ Full table and IntelliSense notes: [print and cout](print-cout.md).
200
+
146
201
  ## Not supported yet
147
202
 
148
- Custom C++ classes, generic templates besides `GetService<T>`, pointer arithmetic, `switch`, `std::`, overloading, macros (except skipping `#` lines).
203
+ Custom C++ classes, generic templates besides `GetService<T>`, pointer arithmetic, `std::`, overloading, macros (except `#pragma strict` / `#pragma nstrict` / `#pragma once`).
149
204
 
150
205
  If you need one of those patterns, open an issue with the C++ and the expected Luau.
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const vscode = require("vscode");
6
+
7
+ function loadEngine(context) {
8
+ const folders = vscode.workspace.workspaceFolders || [];
9
+ const workspaceFolder = folders[0] ? folders[0].uri.fsPath : null;
10
+ const rootFile = path.join(context.extensionPath, "cluaupp.root");
11
+ const roots = [];
12
+ if (fs.existsSync(rootFile)) {
13
+ roots.push(fs.readFileSync(rootFile, "utf8").trim());
14
+ }
15
+ if (workspaceFolder) {
16
+ roots.push(path.join(workspaceFolder, "..", "Cluaupp"));
17
+ roots.push(path.join(workspaceFolder, "node_modules", "cluaupp"));
18
+ }
19
+ roots.push(path.join(context.extensionPath, "..", ".."));
20
+ for (const root of roots) {
21
+ const engine = path.join(root, "src", "intellisense.js");
22
+ if (fs.existsSync(engine)) {
23
+ return { engine: require(engine), root, workspaceFolder };
24
+ }
25
+ }
26
+ throw new Error("Cluaupp IntelliSense engine not found. Run `cluaupp intellisense` in the game folder.");
27
+ }
28
+
29
+ function kindOf(kind) {
30
+ const map = {
31
+ method: vscode.CompletionItemKind.Method,
32
+ function: vscode.CompletionItemKind.Function,
33
+ constructor: vscode.CompletionItemKind.Constructor,
34
+ property: vscode.CompletionItemKind.Property,
35
+ variable: vscode.CompletionItemKind.Variable,
36
+ class: vscode.CompletionItemKind.Class,
37
+ enum: vscode.CompletionItemKind.Enum,
38
+ keyword: vscode.CompletionItemKind.Keyword,
39
+ event: vscode.CompletionItemKind.Event,
40
+ file: vscode.CompletionItemKind.File,
41
+ };
42
+ return map[kind] || vscode.CompletionItemKind.Text;
43
+ }
44
+
45
+ function activate(context) {
46
+ let loaded;
47
+ try {
48
+ loaded = loadEngine(context);
49
+ } catch (err) {
50
+ vscode.window.showWarningMessage(String(err.message || err));
51
+ return;
52
+ }
53
+
54
+ const selector = { language: "cpp", scheme: "file" };
55
+ const diagnostics = vscode.languages.createDiagnosticCollection("cluaupp");
56
+ context.subscriptions.push(diagnostics);
57
+
58
+ const optionsFor = (document) => ({
59
+ projectRoot: loaded.workspaceFolder || path.dirname(document.uri.fsPath),
60
+ file: document.uri.fsPath,
61
+ filePath: document.uri.fsPath,
62
+ includeDirs: [
63
+ path.dirname(document.uri.fsPath),
64
+ path.join(loaded.workspaceFolder || "", "src"),
65
+ path.join(loaded.workspaceFolder || "", "include"),
66
+ ],
67
+ });
68
+
69
+ const refreshDiagnostics = (document) => {
70
+ if (!document || document.languageId !== "cpp") {
71
+ return;
72
+ }
73
+ const items = loaded.engine.diagnosticsFor(document.getText(), document.uri.fsPath, optionsFor(document));
74
+ diagnostics.set(
75
+ document.uri,
76
+ items.map((item) => {
77
+ const line = Math.max(0, (item.line || 1) - 1);
78
+ const col = Math.max(0, (item.col || 1) - 1);
79
+ const range = new vscode.Range(line, col, line, col + 1);
80
+ return new vscode.Diagnostic(range, item.message, vscode.DiagnosticSeverity.Error);
81
+ }),
82
+ );
83
+ };
84
+
85
+ context.subscriptions.push(
86
+ vscode.languages.registerCompletionItemProvider(
87
+ selector,
88
+ {
89
+ provideCompletionItems(document, position) {
90
+ const offset = document.offsetAt(position);
91
+ const items = loaded.engine.completeAt(document.getText(), offset, optionsFor(document));
92
+ return items.map((item) => {
93
+ const completion = new vscode.CompletionItem(item.name, kindOf(item.kind));
94
+ completion.detail = item.detail || item.type || "";
95
+ completion.sortText = `${item.kind === "keyword" ? "2" : "0"}_${item.name}`;
96
+ completion.insertText = item.name;
97
+ return completion;
98
+ });
99
+ },
100
+ },
101
+ ".",
102
+ ":",
103
+ ">",
104
+ "<",
105
+ '"',
106
+ "/",
107
+ ),
108
+ vscode.languages.registerHoverProvider(selector, {
109
+ provideHover(document, position) {
110
+ const hover = loaded.engine.hoverAt(document.getText(), document.offsetAt(position), optionsFor(document));
111
+ if (!hover) {
112
+ return null;
113
+ }
114
+ return new vscode.Hover(new vscode.MarkdownString(`**${hover.name}**\n\n\`${hover.detail || hover.type || ""}\``));
115
+ },
116
+ }),
117
+ vscode.languages.registerDefinitionProvider(selector, {
118
+ provideDefinition(document, position) {
119
+ const def = loaded.engine.definitionAt(document.getText(), document.offsetAt(position), optionsFor(document));
120
+ if (!def || !def.file) {
121
+ return null;
122
+ }
123
+ return new vscode.Location(vscode.Uri.file(def.file), new vscode.Position(Math.max(0, (def.line || 1) - 1), 0));
124
+ },
125
+ }),
126
+ vscode.workspace.onDidChangeTextDocument((event) => refreshDiagnostics(event.document)),
127
+ vscode.workspace.onDidOpenTextDocument(refreshDiagnostics),
128
+ vscode.commands.registerCommand("cluaupp.restartIntelliSense", () => {
129
+ try {
130
+ delete require.cache[require.resolve(path.join(loaded.root, "src", "intellisense.js"))];
131
+ loaded = loadEngine(context);
132
+ vscode.window.showInformationMessage("Cluaupp IntelliSense reloaded.");
133
+ } catch (err) {
134
+ vscode.window.showErrorMessage(String(err.message || err));
135
+ }
136
+ }),
137
+ );
138
+
139
+ for (const document of vscode.workspace.textDocuments) {
140
+ refreshDiagnostics(document);
141
+ }
142
+ }
143
+
144
+ function deactivate() {}
145
+
146
+ module.exports = { activate, deactivate };
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "cluaupp-intellisense",
3
+ "displayName": "Cluaupp IntelliSense",
4
+ "description": "Completions, hover, and go-to-definition for Cluaupp C++ (Roblox APIs, DataService paths, project structs).",
5
+ "version": "0.1.4",
6
+ "publisher": "kartzdev",
7
+ "engines": {
8
+ "vscode": "^1.74.0"
9
+ },
10
+ "categories": [
11
+ "Programming Languages"
12
+ ],
13
+ "activationEvents": [
14
+ "onLanguage:cpp"
15
+ ],
16
+ "main": "./extension.js",
17
+ "contributes": {
18
+ "commands": [
19
+ {
20
+ "command": "cluaupp.restartIntelliSense",
21
+ "title": "Cluaupp: Restart IntelliSense"
22
+ }
23
+ ]
24
+ }
25
+ }
@@ -10,6 +10,8 @@ public:
10
10
  template <typename T>
11
11
  T Add(T object);
12
12
  template <typename T>
13
+ T Add(T object, bool callDirectly);
14
+ template <typename T>
13
15
  T Add(T object, string methodName);
14
16
  template <typename T>
15
17
  T Add(T object, string methodName, string index);
@@ -17,14 +19,15 @@ public:
17
19
  T AddObject(T constructor);
18
20
  template <typename P>
19
21
  P AddPromise(P promise);
22
+ template <typename P>
23
+ P AddPromise(P promise, string index);
20
24
  Janitor* Remove(string index);
21
25
  Janitor* RemoveNoClean(string index);
22
26
  Janitor* RemoveList(string index);
27
+ Janitor* RemoveListNoClean(string index);
23
28
  template <typename T>
24
29
  T Get(string index);
25
- template <typename T>
26
- T GetAll();
27
- bool Has(string index);
30
+ void GetAll();
28
31
  void Cleanup();
29
32
  void Destroy();
30
33
  RBXScriptConnection LinkToInstance(Instance* object);
@@ -32,4 +35,5 @@ public:
32
35
  Janitor* LinkToInstances(Instance* object);
33
36
  static bool Is(Instance* value);
34
37
  static bool Is(string value);
38
+ static bool instanceof(Instance* value);
35
39
  };
@@ -21,6 +21,25 @@ extern LuaSourceContainer* script;
21
21
  void print(string message);
22
22
  void warn(string message);
23
23
  void error(string message);
24
+
25
+ struct cout {
26
+ static void print(string message);
27
+ static void warn(string message);
28
+ static void error(string message);
29
+ static void ping(string message);
30
+ static void endl();
31
+ cout& operator<<(string value);
32
+ cout& operator<<(int value);
33
+ cout& operator<<(double value);
34
+ cout& operator<<(bool value);
35
+ } cout;
36
+
37
+ struct cerr {
38
+ cerr& operator<<(string value);
39
+ cerr& operator<<(int value);
40
+ } cerr;
41
+
42
+ const int endl = 0;
24
43
  double tick();
25
44
  double time();
26
45
  void wait(double seconds = 0);