Skip to content

Commit

Permalink
-added header and source generation mode;
Browse files Browse the repository at this point in the history
-changed command line interface;
-set version to 2.0.0;
  • Loading branch information
kamchatka-volcano committed Jan 3, 2025
1 parent 37edf65 commit 6eb4e2a
Show file tree
Hide file tree
Showing 20 changed files with 666 additions and 116 deletions.
14 changes: 10 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.18)
project(hypertextcpp VERSION 1.2.1 DESCRIPTION "hypertextcpp")
project(hypertextcpp VERSION 2.0.0 DESCRIPTION "hypertextcpp")

include(external/seal_lake)

SealLake_Import(cmdlime 2.6.0
SealLake_Import(cmdlime 2.7.0
GIT_REPOSITORY https://github.com/kamchatka-volcano/cmdlime
GIT_TAG dev
GIT_TAG v2.7.0
)

SealLake_Import(sfun 5.1.0
Expand All @@ -24,6 +24,10 @@ SealLake_Bundle(
GIT_REPOSITORY https://github.com/ericniebler/range-v3
GIT_TAG 0.12.0
)
SealLake_Import(fmt 9.1.0
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG 9.1.0
)

set(SRC
src/codenode.cpp
Expand All @@ -41,7 +45,8 @@ set(SRC
src/utils.cpp
src/node_utils.cpp
src/single_header_transpiler_renderer.cpp
src/shared_lib_transpiler_renderer.cpp)
src/shared_lib_transpiler_renderer.cpp
src/header_and_source_transpiler_renderer.cpp)


SealLake_Executable(
Expand All @@ -54,6 +59,7 @@ SealLake_Executable(
cmdlime::cmdlime
sfun::sfun
Microsoft.GSL::GSL
fmt::fmt
)

SealLake_OptionalSubProjects(tests examples)
Expand Down
91 changes: 69 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,33 +252,66 @@ Now the tasks list can be output to stdout by itself like this:
### Command line parameters
```console
kamchatka-volcano@home:~$ hypertextcpp --help
Usage: hypertextcpp <input> [params] [flags]
Usage: hypertextcpp [commands] [flags]
Flags:
--help show usage info and exit
Commands:
generateHeaderOnly [options] generate header only file
generateSharedLibrarySource [options] generate shared library source
file
generateHeaderAndSource [options] generate header and source files
```

Single header renderer generation:
```console
kamchatka-volcano@home:~$ hypertextcpp generateHeaderOnly --help
Usage: hypertextcpp generateHeaderOnly <input> [params] [flags]
Arguments:
<input> (path) .htcpp file to transpile
-outputDir=<path> output dir
(if empty, current working directory is used)
(optional, default: "")
-className=<string> generated class name
(if empty, input file name is used)
(optional, default: "")
Flags:
--help show usage info and exit
```

Header and source renderer generation:
```console
kamchatka-volcano@home:~$ hypertextcpp generateHeaderAndSource --help
Usage: hypertextcpp generateHeaderAndSource <input> -configClassName=<string> [params] [flags]
Arguments:
<input> (path) .htcpp file to transpile
Parameters:
-o, --output <path> output c++ file path
-configClassName=<string> config class name
-outputDir=<path> output dir
(if empty, current working directory is used)
(optional, default: "")
-c, --class-name <string> generated class name
(optional)
-className=<string> generated class name
(if empty, input file name is used)
(optional, default: "")
Flags:
-s, --shared-lib generate result as shared library source
files
--class-pascalcase generate class name by using .htcpp filename
in PascalCase
--class-snakecase generate class name by using .htcpp filename
in snake_case
--class-lowercase generate class name by using .htcpp filename
in lowercase
--help show usage info and exit


Process finished with exit code 0
--help show usage info and exit
```

Shared library renderer generation:
```console
kamchatka-volcano@home:~$ hypertextcpp generateSharedLibrarySource --help
Usage: hypertextcpp generateSharedLibrarySource <input> [params] [flags]
Arguments:
<input> (path) .htcpp file to transpile
-outputDir=<path> output dir
(if empty, current working directory is used)
(optional, default: "")
Flags:
--help show usage info and exit
```


### Single header renderer
By default, the **hypertextcpp** transpiler works in a single header mode and generates a C++ header file that you're supposed to simply include in your project. A generated renderer class has the name of the `.htcpp` template file. You can override the name by using the `--class-name` parameter, or you can specify one of the following flags: `--class-pascalcase`, `--class-snakecase`, or `--class-lowercase` to use the `.htcpp` template's filename converted to the corresponding case as a class name.
In this mode, the **hypertextcpp** generates a C++ header file that you're supposed to simply include in your project. A generated renderer class has the name of the `.htcpp` template file.
Converting the template to C++ code each time you modify it is a laborious task, so it makes sense to add this step to your build process. To do this with CMake you can use `hypertextcpp_GenerateHeader` function from the `hypertextcpp.cmake` file.
Note that this function launches the `hypertextcpp` executable, so it should be installed on your system first.

Expand All @@ -288,23 +321,37 @@ cmake_minimum_required(VERSION 3.18)
include(../../hypertextcpp.cmake)
hypertextcpp_GenerateHeader(NAME todolist CLASS_NAME TodoList)
hypertextcpp_GenerateHeader(
TEMPLATE_FILE todolist.htcpp
CLASS_NAME TodoList
)
set(SRC
todolist_printer.cpp
todolist.h)
#Please note that to generate the header todolist.h, it must pe passed to the target sources
add_executable(todolist_printer ${SRC})
target_compile_features(todolist_printer PUBLIC cxx_std_17)
set_target_properties(todolist_printer PROPERTIES CXX_EXTENSIONS OFF)
```

Now, every time you change the template, the corresponding header will be regenerated on the next build.
Now, every time you change the template `todolist.htcpp`, the corresponding header will be regenerated on the next build.

### Header and source renderer
It can feel quite wasteful to rebuild all object files that include the renderer header each time the template file is changed, so `hypertextcpp` supports the generation of the renderer as a header and implementation file. In this mode, the generated rendering methods aren't function templates, and you need to provide the config name as a command-line parameter and either define the config structure inside the template or include it from there (check `examples/ex_06` and `examples/ex_07`).
To do this with CMake, you can use the `hypertextcpp_GenerateHeaderAndSource` function from the `hypertextcpp.cmake` file.

```
hypertextcpp_GenerateHeaderAndSource(
TEMPLATE_FILE todolist.htcpp
CONFIG_CLASS_NAME PageParams)
```

### Shared library renderer
It can feel quite wasteful to rebuild your project each time the template file is changed, so **hypertextcpp** supports the generation of a C++ source file for building templates in the form of shared libraries and linking them dynamically from your application.
It requires duplicating the config declaration in the .htcpp template, registering it with the `HTCPP_CONFIG` macro in both the template and the application source, generating the renderer code with the `--shared-lib` command line flag, building the library, and loading it using the tiny API installed from the `shared_lib_api/` directory. It sounds scarier than it is, so let's quickly update the todolist example to see how it works.
**hypertextcpp** also supports the generation of a C++ source file for building templates in the form of shared libraries and linking them dynamically from your application. This way it's possible to rebuild the template and update it without restarting the application.
It requires duplicating the config declaration in the .htcpp template, registering it with the `HTCPP_CONFIG` macro in both the template and the application source, generating the renderer code with the `generateSharedLibrarySource` command, building the library, and loading it using the tiny API installed from the `shared_lib_api/` directory. It sounds scarier than it is, so let's quickly update the todolist example to see how it works.

First we need to copy the config structure declaration in the template:
[`examples/05/todolist.htcpp`](examples/05/todolist.htcpp)
Expand Down Expand Up @@ -336,7 +383,7 @@ First we need to copy the config structure declaration in the template:
</html>
```

Be sure to use an exact copy; any mismatch of the config structure between the template and the application can't be handled gracefully. So, if you try to load a template library with a different structure, you'll definitely crash the application and maybe hurt someone as a result.
Be sure to use an exact copy; any mismatch in the config structure between the template and the application can't be handled gracefully. So, if you try to load a template library with a different structure, your application will abort with a runtime error. This means that by using a htcpp template in the form of shared libraries, you lose one of the main advantages of hypertextcpp—compile-time type safety. Because of this, it's recommended to use this mode only after your template config has stabilized and doesn't change often.

Next, we need to build our template renderer as a library. It's not possible to bundle multiple template files in one library, so we can build a library from a single `.htcpp` file by using the `hypertextcpp_BuildSharedLibrary` CMake function from `hypertextcpp.cmake`:

Expand Down
4 changes: 3 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ add_subdirectory(ex_01)
add_subdirectory(ex_02)
add_subdirectory(ex_03)
add_subdirectory(ex_04)
add_subdirectory(ex_05)
add_subdirectory(ex_05)
add_subdirectory(ex_06)
add_subdirectory(ex_07)
3 changes: 2 additions & 1 deletion examples/ex_01/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ project(ex_01)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeader(NAME todolist)
hypertextcpp_GenerateHeader(
TEMPLATE_FILE todolist.htcpp)

set(SRC
todolist_printer.cpp
Expand Down
7 changes: 5 additions & 2 deletions examples/ex_02/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ project(ex_02)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeader(NAME todolist)
hypertextcpp_GenerateHeader(
TEMPLATE_FILE todolist.htcpp
OUTPUT_DIR template
)

set(SRC
todolist_printer.cpp
todolist.h)
template/todolist.h)

add_executable(${PROJECT_NAME} ${SRC})

Expand Down
2 changes: 1 addition & 1 deletion examples/ex_02/todolist_printer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "todolist.h"
#include "template/todolist.h"
#include <string>
#include <vector>

Expand Down
2 changes: 1 addition & 1 deletion examples/ex_03/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ project(ex_03)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeader(NAME todolist)
hypertextcpp_GenerateHeader(TEMPLATE_FILE todolist.htcpp)

set(SRC
todolist_printer.cpp
Expand Down
5 changes: 4 additions & 1 deletion examples/ex_04/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ project(ex_04)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeader(NAME todolist CLASS_NAME TodoList)
hypertextcpp_GenerateHeader(
TEMPLATE_FILE todolist.htcpp
CLASS_NAME TodoList
)

set(SRC
todolist_printer.cpp
Expand Down
3 changes: 1 addition & 2 deletions examples/ex_05/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ target_link_libraries(${PROJECT_NAME} ${CMAKE_DL_LIBS})

include(../../hypertextcpp.cmake)
hypertextcpp_BuildSharedLibrary(
NAME todolist
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}
TEMPLATE_FILE todolist.htcpp
)
add_dependencies(${PROJECT_NAME} todolist)
20 changes: 20 additions & 0 deletions examples/ex_06/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.18)
project(ex_06)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeaderAndSource(
TEMPLATE_FILE todolist.htcpp
CLASS_NAME TodoList
CONFIG_CLASS_NAME PageParams)

set(SRC
todolist_printer.cpp
todolist.h
todolist.cpp)

add_executable(${PROJECT_NAME} ${SRC})

target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF)

24 changes: 24 additions & 0 deletions examples/ex_06/todolist.htcpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#{
#include <vector>
struct PageParams{
struct Task{
std::string name;
bool isCompleted = false;
};
std::string name = "Bob";
std::vector<Task> tasks = {{"laundry", true}, {"cooking", false}};
};
}

#taskList(){
<li [[style="text-decoration: line-through;"]]?(task.isCompleted)>$(task.name)</li>@(auto task : cfg.tasks)
}
<html>
<body>
<h1>$(cfg.name)'s todo list:</h1>
<p> No tasks found </p>?(cfg.tasks.empty())
<ul>
$(taskList())
</ul>
</body>
</html>
11 changes: 11 additions & 0 deletions examples/ex_06/todolist_printer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "todolist.h"
#include <string>
#include <vector>

int main()
{
PageParams pageParams;
auto page = TodoList{};
page.print(pageParams);
return 0;
}
20 changes: 20 additions & 0 deletions examples/ex_07/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.18)
project(ex_07)

include(../../hypertextcpp.cmake)

hypertextcpp_GenerateHeaderAndSource(
TEMPLATE_FILE todolist.htcpp
CLASS_NAME TodoList
CONFIG_CLASS_NAME PageParams)

set(SRC
todolist_printer.cpp
todolist.h
todolist.cpp)

add_executable(${PROJECT_NAME} ${SRC})

target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF)

12 changes: 12 additions & 0 deletions examples/ex_07/pageparams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <vector>

struct PageParams{
struct Task{
std::string name;
bool isCompleted = false;
};
std::string name = "Bob";
std::vector<Task> tasks = {{"laundry", true}, {"cooking", false}};
};
16 changes: 16 additions & 0 deletions examples/ex_07/todolist.htcpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#{
#include "pageparams.h"
}

#taskList(){
<li [[style="text-decoration: line-through;"]]?(task.isCompleted)>$(task.name)</li>@(auto task : cfg.tasks)
}
<html>
<body>
<h1>$(cfg.name)'s todo list:</h1>
<p> No tasks found </p>?(cfg.tasks.empty())
<ul>
$(taskList())
</ul>
</body>
</html>
11 changes: 11 additions & 0 deletions examples/ex_07/todolist_printer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "todolist.h"
#include <string>
#include <vector>

int main()
{
PageParams pageParams;
auto page = TodoList{};
page.print(pageParams);
return 0;
}
Loading

0 comments on commit 6eb4e2a

Please sign in to comment.