blob: 79ba7fa35e21528fa0683d897aeeb51e6342b275 [file] [log] [blame]
// Copyright (c) 2019 Pantor. All rights reserved.
#ifndef INCLUDE_INJA_ENVIRONMENT_HPP_
#define INCLUDE_INJA_ENVIRONMENT_HPP_
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include <nlohmann/json.hpp>
#include "config.hpp"
#include "function_storage.hpp"
#include "parser.hpp"
#include "renderer.hpp"
#include "string_view.hpp"
#include "template.hpp"
#include "utils.hpp"
namespace inja {
using json = nlohmann::json;
/*!
* \brief Class for changing the configuration.
*/
class Environment {
public:
Environment() : Environment("") {}
explicit Environment(const std::string &global_path) : m_input_path(global_path), m_output_path(global_path) {}
Environment(const std::string &input_path, const std::string &output_path)
: m_input_path(input_path), m_output_path(output_path) {}
/// Sets the opener and closer for template statements
void set_statement(const std::string &open, const std::string &close) {
m_lexer_config.statement_open = open;
m_lexer_config.statement_close = close;
m_lexer_config.update_open_chars();
}
/// Sets the opener for template line statements
void set_line_statement(const std::string &open) {
m_lexer_config.line_statement = open;
m_lexer_config.update_open_chars();
}
/// Sets the opener and closer for template expressions
void set_expression(const std::string &open, const std::string &close) {
m_lexer_config.expression_open = open;
m_lexer_config.expression_close = close;
m_lexer_config.update_open_chars();
}
/// Sets the opener and closer for template comments
void set_comment(const std::string &open, const std::string &close) {
m_lexer_config.comment_open = open;
m_lexer_config.comment_close = close;
m_lexer_config.update_open_chars();
}
/// Sets whether to remove the first newline after a block
void set_trim_blocks(bool trim_blocks) { m_lexer_config.trim_blocks = trim_blocks; }
/// Sets whether to strip the spaces and tabs from the start of a line to a block
void set_lstrip_blocks(bool lstrip_blocks) { m_lexer_config.lstrip_blocks = lstrip_blocks; }
/// Sets the element notation syntax
void set_element_notation(ElementNotation notation) { m_parser_config.notation = notation; }
Template parse(nonstd::string_view input) {
Parser parser(m_parser_config, m_lexer_config, m_included_templates);
return parser.parse(input);
}
Template parse_template(const std::string &filename) {
Parser parser(m_parser_config, m_lexer_config, m_included_templates);
return parser.parse_template(m_input_path + static_cast<std::string>(filename));
}
std::string render(nonstd::string_view input, const json &data) { return render(parse(input), data); }
std::string render(const Template &tmpl, const json &data) {
std::stringstream os;
render_to(os, tmpl, data);
return os.str();
}
std::string render_file(const std::string &filename, const json &data) {
return render(parse_template(filename), data);
}
std::string render_file_with_json_file(const std::string &filename, const std::string &filename_data) {
const json data = load_json(filename_data);
return render_file(filename, data);
}
void write(const std::string &filename, const json &data, const std::string &filename_out) {
std::ofstream file(m_output_path + filename_out);
file << render_file(filename, data);
file.close();
}
void write(const Template &temp, const json &data, const std::string &filename_out) {
std::ofstream file(m_output_path + filename_out);
file << render(temp, data);
file.close();
}
void write_with_json_file(const std::string &filename, const std::string &filename_data,
const std::string &filename_out) {
const json data = load_json(filename_data);
write(filename, data, filename_out);
}
void write_with_json_file(const Template &temp, const std::string &filename_data, const std::string &filename_out) {
const json data = load_json(filename_data);
write(temp, data, filename_out);
}
std::ostream &render_to(std::ostream &os, const Template &tmpl, const json &data) {
Renderer(m_included_templates, m_callbacks).render_to(os, tmpl, data);
return os;
}
std::string load_file(const std::string &filename) {
Parser parser(m_parser_config, m_lexer_config, m_included_templates);
return parser.load_file(m_input_path + filename);
}
json load_json(const std::string &filename) {
std::ifstream file = open_file_or_throw(m_input_path + filename);
json j;
file >> j;
return j;
}
void add_callback(const std::string &name, unsigned int numArgs, const CallbackFunction &callback) {
m_callbacks.add_callback(name, numArgs, callback);
}
/** Includes a template with a given name into the environment.
* Then, a template can be rendered in another template using the
* include "<name>" syntax.
*/
void include_template(const std::string &name, const Template &tmpl) { m_included_templates[name] = tmpl; }
private:
std::string m_input_path;
std::string m_output_path;
LexerConfig m_lexer_config;
ParserConfig m_parser_config;
FunctionStorage m_callbacks;
TemplateStorage m_included_templates;
};
/*!
@brief render with default settings to a string
*/
inline std::string render(nonstd::string_view input, const json &data) { return Environment().render(input, data); }
/*!
@brief render with default settings to the given output stream
*/
inline void render_to(std::ostream &os, nonstd::string_view input, const json &data) {
Environment env;
env.render_to(os, env.parse(input), data);
}
} // namespace inja
#endif // INCLUDE_INJA_ENVIRONMENT_HPP_