| // Copyright (c) 2019 Pantor. All rights reserved. |
| |
| #ifndef INCLUDE_INJA_ENVIRONMENT_HPP_ |
| #define INCLUDE_INJA_ENVIRONMENT_HPP_ |
| |
| #include <memory> |
| #include <fstream> |
| #include <sstream> |
| #include <string> |
| |
| #include <nlohmann/json.hpp> |
| |
| #include "config.hpp" |
| #include "function_storage.hpp" |
| #include "parser.hpp" |
| #include "polyfill.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); |
| } |
| |
| } |
| |
| #endif // INCLUDE_INJA_ENVIRONMENT_HPP_ |