Skip to content

Commit 2170b7a

Browse files
committed
fix: add parser doc for c++ module
1 parent a8dcb49 commit 2170b7a

File tree

2 files changed

+239
-5
lines changed

2 files changed

+239
-5
lines changed

content/4.languages/2.cpp/3.export-functions.md

Lines changed: 238 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,248 @@ extern "C" PLUGIN_API void ExecuteWithCallback_Exported_Name(int32_t value, cons
248248
```
249249
::
250250

251+
## **Automating Manifest Generation**
252+
253+
::callout{icon="i-lucide-sparkles" color="blue"}
254+
**New:** You can now automate the generation of the `methods` section in your plugin manifest using clang-doc and a Python parser!
255+
::
256+
257+
Instead of manually writing the manifest JSON for each exported function, you can use automated tools to extract function signatures, types, parameter descriptions, and even enum definitions directly from your C++ source code.
258+
259+
### **Benefits of Automated Generation**
260+
261+
1. **No Manual JSON Writing**: Function signatures are automatically extracted from your code
262+
2. **Complete Type Information**: Enum structures and function typedefs are included automatically
263+
3. **Documentation Integration**: Doxygen comments are parsed and included in the manifest
264+
4. **Reduced Errors**: Eliminates typos and type mismatches between code and manifest
265+
5. **Easy Maintenance**: Changes to function signatures are automatically reflected
266+
267+
### **Setup: Adding Documentation Generation to CMake**
268+
269+
Add the following to your `CMakeLists.txt` to generate documentation and manifest JSON:
270+
271+
```cmake
272+
# Find clang-doc (usually comes with LLVM/Clang installation)
273+
find_program(CLANG_DOC clang-doc)
274+
275+
if(CLANG_DOC)
276+
# Generate YAML documentation from your exported functions
277+
add_custom_target(docs
278+
COMMAND ${CLANG_DOC}
279+
--executor=all-TUs
280+
-p ${CMAKE_CURRENT_BINARY_DIR}
281+
--output=${CMAKE_CURRENT_SOURCE_DIR}/docs
282+
--extra-arg=-Wno-error
283+
--format=yaml
284+
${CMAKE_SOURCE_DIR}/src/export/*.cpp # Path to your exported functions
285+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
286+
COMMENT "Generating documentation with clang-doc"
287+
)
288+
289+
# Optional: Automatically parse YAML to JSON after docs generation
290+
find_package(Python3 COMPONENTS Interpreter)
291+
if(Python3_FOUND)
292+
add_custom_command(TARGET docs POST_BUILD
293+
COMMAND ${Python3_EXECUTABLE}
294+
${CMAKE_SOURCE_DIR}/tools/parser.py
295+
${CMAKE_SOURCE_DIR}/docs/index.yaml
296+
${CMAKE_SOURCE_DIR}/exported_methods.json
297+
COMMENT "Parsing documentation to JSON"
298+
)
299+
endif()
300+
endif()
301+
```
302+
303+
### **Using the Parser**
304+
305+
::steps{level=4}
306+
#### **Install the Parser**
307+
308+
Download `parser.py` and place it in your project (e.g., in a `tools/` directory).
309+
310+
Install dependencies:
311+
```bash
312+
pip install pyyaml
313+
```
314+
315+
:read-more{icon="lucide:github" to="https://github.com/untrustedmodders/plugify-module-cpp/tree/main/tools/parser" title="GitHub Repository"}
316+
317+
#### **Document Your Functions**
318+
319+
Add Doxygen comments to your exported functions:
320+
321+
```cpp
322+
/**
323+
* @brief Creates a console command as an administrative command.
324+
* If the command does not exist, it is created. When this command is invoked,
325+
* the access rights of the player are automatically checked before allowing it to continue.
326+
*
327+
* @param name The name of the console command.
328+
* @param adminFlags The admin flags that indicate which admin level can use this command.
329+
* @param description A brief description of what the command does.
330+
* @param flags Command flags that define the behavior of the command.
331+
* @param callback A callback function that is invoked when the command is executed.
332+
* @param mode Whether the hook was in post mode (after processing) or pre mode (before processing).
333+
* @return A boolean indicating whether the command was successfully added.
334+
*/
335+
extern "C" PLUGIN_API bool AddAdminCommand(
336+
const plg::string& name,
337+
int64_t adminFlags,
338+
const plg::string& description,
339+
ConVarFlag flags,
340+
CommandCallback callback,
341+
HookMode mode
342+
);
343+
```
344+
345+
#### **Document Enums and Typedefs**
346+
347+
Document your enums and function typedefs:
348+
349+
```cpp
350+
/**
351+
* @brief Enum representing the type of callback.
352+
*/
353+
enum class HookMode : uint8_t {
354+
/** Callback will be executed before the original function */
355+
Pre = 0,
356+
/** Callback will be executed after the original function */
357+
Post = 1
358+
};
359+
360+
/**
361+
* @brief Handles the execution of a command triggered by a caller.
362+
* This function processes the command, interprets its context, and handles any provided arguments.
363+
*/
364+
using CommandCallback = ResultType (*)(int32_t caller, CommandCallingContext context, const plg::vector<plg::string>& arguments);
365+
```
366+
367+
#### **Generate Documentation**
368+
369+
Build the documentation target:
370+
```bash
371+
cmake --build . --target docs
372+
```
373+
374+
This generates `docs/index.yaml` with all your function information.
375+
376+
#### **Parse to JSON**
377+
378+
Run the parser to convert YAML to the manifest format:
379+
```bash
380+
python3 tools/parser.py docs/index.yaml exported_methods.json
381+
```
382+
383+
Or with filtering:
384+
```bash
385+
# Only functions from files starting with "commands"
386+
python3 tools/parser.py docs/index.yaml exported_methods.json --file-prefix "commands"
387+
388+
# Only functions with "Admin" in their name
389+
python3 tools/parser.py docs/index.yaml exported_methods.json --name-filter "Admin"
390+
```
391+
392+
#### **Use in Your Manifest**
393+
394+
Copy the generated `methods` array from `exported_methods.json` into your plugin manifest:
395+
396+
```json
397+
{
398+
"name": "ExamplePlugin",
399+
"version": "1.0.0",
400+
"methods": [
401+
// Paste the content from exported_methods.json here
402+
]
403+
}
404+
```
405+
::
406+
407+
### **Advanced: Enum Structures**
408+
409+
The parser automatically includes complete enum definitions when a parameter uses an enum type:
410+
411+
**Generated Output:**
412+
```json
413+
{
414+
"name": "mode",
415+
"type": "uint8",
416+
"description": "Whether the hook was in post mode or pre mode.",
417+
"enum": {
418+
"name": "HookMode",
419+
"description": "Enum representing the type of callback.",
420+
"values": [
421+
{
422+
"name": "Pre",
423+
"value": 0,
424+
"description": "Callback will be executed before the original function"
425+
},
426+
{
427+
"name": "Post",
428+
"value": 1,
429+
"description": "Callback will be executed after the original function"
430+
}
431+
]
432+
}
433+
}
434+
```
435+
436+
### **Advanced: Function Typedefs**
437+
438+
Function pointer typedefs are automatically parsed into complete prototypes:
439+
440+
**Generated Output:**
441+
```json
442+
{
443+
"name": "callback",
444+
"type": "function",
445+
"description": "A callback function that is invoked when the command is executed.",
446+
"prototype": {
447+
"name": "CommandCallback",
448+
"funcName": "CommandCallback",
449+
"description": "Handles the execution of a command triggered by a caller.",
450+
"paramTypes": [
451+
{
452+
"name": "param1",
453+
"type": "int32"
454+
},
455+
{
456+
"name": "param2",
457+
"type": "int32",
458+
"enum": {
459+
"name": "CommandCallingContext",
460+
"values": [...]
461+
}
462+
},
463+
{
464+
"name": "param3",
465+
"type": "string[]"
466+
}
467+
],
468+
"retType": {
469+
"type": "int32",
470+
"enum": {
471+
"name": "ResultType",
472+
"values": [...]
473+
}
474+
}
475+
}
476+
}
477+
```
478+
479+
::callout{icon="i-lucide-info" color="amber"}
480+
**Note:** Function typedef parameter names are auto-generated as `param1`, `param2`, etc. You may want to customize these in the manifest for better documentation.
481+
::
482+
251483
## **Best Practices**
252484

253485
1. **Use `PLUGIN_API`**: Always use the `PLUGIN_API` macro to mark functions for export.
254486
2. **Follow Type Conventions**: Adhere to Plugify's type conventions for parameters and return values.
255-
3. **Document Your Functions**: Clearly document the purpose, parameters, and return values of exported functions.
256-
4. **Test Thoroughly**: Test your exported functions to ensure they work as expected when called by other plugins.
257-
5. **Update the Manifest**: Always describe exported functions in the plugin manifest under the `methods` section.
487+
3. **Document Your Functions**: Use Doxygen-style comments (`@brief`, `@param`, `@return`) to document exported functions.
488+
4. **Automate When Possible**: Use the clang-doc parser to automate manifest generation and reduce manual errors.
489+
5. **Document Enums and Typedefs**: Include Doxygen comments on enums and typedefs for complete manifest generation.
490+
6. **Test Thoroughly**: Test your exported functions to ensure they work as expected when called by other plugins.
491+
7. **Keep Manifests Updated**: If using manual manifests, ensure they stay synchronized with your code. If using automation, regenerate after changes.
258492

259493
## **Conclusion**
260494

261-
Exporting functions in C++ plugins is straightforward when you follow Plugify's conventions and best practices. By using the `PLUGIN_API` macro, adhering to type conventions, and describing functions in the plugin manifest, you can create robust and interoperable plugins. For more advanced use cases, such as handling callbacks or returning C++ objects, use the techniques outlined in this guide.
495+
Exporting functions in C++ plugins is straightforward when you follow Plugify's conventions and best practices. By using the `PLUGIN_API` macro, adhering to type conventions, and optionally automating manifest generation with clang-doc and the Python parser, you can create robust and interoperable plugins with minimal manual effort. For more advanced use cases, such as handling callbacks or working with enums, the automated parser provides complete type information including enum structures and function prototypes.

content/4.languages/2.cpp/4.import-functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Plugify provides a Python script (`generator.py`) to automatically generate head
1616
#### **Locate the Generator Script**:
1717
- The `generator.py` script is located in the `generator` folder of the C++ language module.
1818

19-
:read-more{icon="lucide:link" to="https://github.com/untrustedmodders/plugify-module-cpp/tree/main/generator" title="GitHub Repository"}
19+
:read-more{icon="lucide:link" to="https://github.com/untrustedmodders/plugify-module-cpp/tree/main/tools/generator" title="GitHub Repository"}
2020

2121
#### **Run the Generator Script**:
2222
- Open a terminal or command prompt and navigate to the folder containing `generator.py`.

0 commit comments

Comments
 (0)