Blame src/emitter.cpp

Packit Service 7770af
#include "sass.hpp"
Packit Service 7770af
#include "util.hpp"
Packit Service 7770af
#include "context.hpp"
Packit Service 7770af
#include "output.hpp"
Packit Service 7770af
#include "emitter.hpp"
Packit Service 7770af
#include "utf8_string.hpp"
Packit Service 7770af
Packit Service 7770af
namespace Sass {
Packit Service 7770af
Packit Service 7770af
  Emitter::Emitter(struct Sass_Output_Options& opt)
Packit Service 7770af
  : wbuf(),
Packit Service 7770af
    opt(opt),
Packit Service 7770af
    indentation(0),
Packit Service 7770af
    scheduled_space(0),
Packit Service 7770af
    scheduled_linefeed(0),
Packit Service 7770af
    scheduled_delimiter(false),
Packit Service 7770af
    scheduled_mapping(0),
Packit Service 7770af
    in_comment(false),
Packit Service 7770af
    in_wrapped(false),
Packit Service 7770af
    in_media_block(false),
Packit Service 7770af
    in_declaration(false),
Packit Service 7770af
    in_space_array(false),
Packit Service 7770af
    in_comma_array(false)
Packit Service 7770af
  { }
Packit Service 7770af
Packit Service 7770af
  // return buffer as string
Packit Service 7770af
  std::string Emitter::get_buffer(void)
Packit Service 7770af
  {
Packit Service 7770af
    return wbuf.buffer;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  Sass_Output_Style Emitter::output_style(void) const
Packit Service 7770af
  {
Packit Service 7770af
    return opt.output_style;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // PROXY METHODS FOR SOURCE MAPS
Packit Service 7770af
Packit Service 7770af
  void Emitter::add_source_index(size_t idx)
Packit Service 7770af
  { wbuf.smap.source_index.push_back(idx); }
Packit Service 7770af
Packit Service 7770af
  std::string Emitter::render_srcmap(Context &ctx)
Packit Service 7770af
  { return wbuf.smap.render_srcmap(ctx); }
Packit Service 7770af
Packit Service 7770af
  void Emitter::set_filename(const std::string& str)
Packit Service 7770af
  { wbuf.smap.file = str; }
Packit Service 7770af
Packit Service 7770af
  void Emitter::schedule_mapping(const AST_Node_Ptr node)
Packit Service 7770af
  { scheduled_mapping = node; }
Packit Service 7770af
  void Emitter::add_open_mapping(const AST_Node_Ptr node)
Packit Service 7770af
  { wbuf.smap.add_open_mapping(node); }
Packit Service 7770af
  void Emitter::add_close_mapping(const AST_Node_Ptr node)
Packit Service 7770af
  { wbuf.smap.add_close_mapping(node); }
Packit Service 7770af
  ParserState Emitter::remap(const ParserState& pstate)
Packit Service 7770af
  { return wbuf.smap.remap(pstate); }
Packit Service 7770af
Packit Service 7770af
  // MAIN BUFFER MANIPULATION
Packit Service 7770af
Packit Service 7770af
  // add outstanding delimiter
Packit Service 7770af
  void Emitter::finalize(bool final)
Packit Service 7770af
  {
Packit Service 7770af
    scheduled_space = 0;
Packit Service 7770af
    if (output_style() == SASS_STYLE_COMPRESSED)
Packit Service 7770af
      if (final) scheduled_delimiter = false;
Packit Service 7770af
    if (scheduled_linefeed)
Packit Service 7770af
      scheduled_linefeed = 1;
Packit Service 7770af
    flush_schedules();
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // flush scheduled space/linefeed
Packit Service 7770af
  void Emitter::flush_schedules(void)
Packit Service 7770af
  {
Packit Service 7770af
    // check the schedule
Packit Service 7770af
    if (scheduled_linefeed) {
Packit Service 7770af
      std::string linefeeds = "";
Packit Service 7770af
Packit Service 7770af
      for (size_t i = 0; i < scheduled_linefeed; i++)
Packit Service 7770af
        linefeeds += opt.linefeed;
Packit Service 7770af
      scheduled_space = 0;
Packit Service 7770af
      scheduled_linefeed = 0;
Packit Service 7770af
      append_string(linefeeds);
Packit Service 7770af
Packit Service 7770af
    } else if (scheduled_space) {
Packit Service 7770af
      std::string spaces(scheduled_space, ' ');
Packit Service 7770af
      scheduled_space = 0;
Packit Service 7770af
      append_string(spaces);
Packit Service 7770af
    }
Packit Service 7770af
    if (scheduled_delimiter) {
Packit Service 7770af
      scheduled_delimiter = false;
Packit Service 7770af
      append_string(";");
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // prepend some text or token to the buffer
Packit Service 7770af
  void Emitter::prepend_output(const OutputBuffer& output)
Packit Service 7770af
  {
Packit Service 7770af
    wbuf.smap.prepend(output);
Packit Service 7770af
    wbuf.buffer = output.buffer + wbuf.buffer;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // prepend some text or token to the buffer
Packit Service 7770af
  void Emitter::prepend_string(const std::string& text)
Packit Service 7770af
  {
Packit Service 7770af
    wbuf.smap.prepend(Offset(text));
Packit Service 7770af
    wbuf.buffer = text + wbuf.buffer;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // append some text or token to the buffer
Packit Service 7770af
  void Emitter::append_string(const std::string& text)
Packit Service 7770af
  {
Packit Service 7770af
Packit Service 7770af
    // write space/lf
Packit Service 7770af
    flush_schedules();
Packit Service 7770af
Packit Service 7770af
    if (in_comment && output_style() == COMPACT) {
Packit Service 7770af
      // unescape comment nodes
Packit Service 7770af
      std::string out = comment_to_string(text);
Packit Service 7770af
      // add to buffer
Packit Service 7770af
      wbuf.buffer += out;
Packit Service 7770af
      // account for data in source-maps
Packit Service 7770af
      wbuf.smap.append(Offset(out));
Packit Service 7770af
    } else {
Packit Service 7770af
      // add to buffer
Packit Service 7770af
      wbuf.buffer += text;
Packit Service 7770af
      // account for data in source-maps
Packit Service 7770af
      wbuf.smap.append(Offset(text));
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // append some white-space only text
Packit Service 7770af
  void Emitter::append_wspace(const std::string& text)
Packit Service 7770af
  {
Packit Service 7770af
    if (text.empty()) return;
Packit Service 7770af
    if (peek_linefeed(text.c_str())) {
Packit Service 7770af
      scheduled_space = 0;
Packit Service 7770af
      append_mandatory_linefeed();
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // append some text or token to the buffer
Packit Service 7770af
  // this adds source-mappings for node start and end
Packit Service 7770af
  void Emitter::append_token(const std::string& text, const AST_Node_Ptr node)
Packit Service 7770af
  {
Packit Service 7770af
    flush_schedules();
Packit Service 7770af
    add_open_mapping(node);
Packit Service 7770af
    // hotfix for browser issues
Packit Service 7770af
    // this is pretty ugly indeed
Packit Service 7770af
    if (scheduled_mapping) {
Packit Service 7770af
      add_open_mapping(scheduled_mapping);
Packit Service 7770af
      scheduled_mapping = 0;
Packit Service 7770af
    }
Packit Service 7770af
    append_string(text);
Packit Service 7770af
    add_close_mapping(node);
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // HELPER METHODS
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_indentation()
Packit Service 7770af
  {
Packit Service 7770af
    if (output_style() == COMPRESSED) return;
Packit Service 7770af
    if (output_style() == COMPACT) return;
Packit Service 7770af
    if (in_declaration && in_comma_array) return;
Packit Service 7770af
    if (scheduled_linefeed && indentation)
Packit Service 7770af
      scheduled_linefeed = 1;
Packit Service 7770af
    std::string indent = "";
Packit Service 7770af
    for (size_t i = 0; i < indentation; i++)
Packit Service 7770af
      indent += opt.indent;
Packit Service 7770af
    append_string(indent);
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_delimiter()
Packit Service 7770af
  {
Packit Service 7770af
    scheduled_delimiter = true;
Packit Service 7770af
    if (output_style() == COMPACT) {
Packit Service 7770af
      if (indentation == 0) {
Packit Service 7770af
        append_mandatory_linefeed();
Packit Service 7770af
      } else {
Packit Service 7770af
        append_mandatory_space();
Packit Service 7770af
      }
Packit Service 7770af
    } else if (output_style() != COMPRESSED) {
Packit Service 7770af
      append_optional_linefeed();
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_comma_separator()
Packit Service 7770af
  {
Packit Service 7770af
    // scheduled_space = 0;
Packit Service 7770af
    append_string(",");
Packit Service 7770af
    append_optional_space();
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_colon_separator()
Packit Service 7770af
  {
Packit Service 7770af
    scheduled_space = 0;
Packit Service 7770af
    append_string(":");
Packit Service 7770af
    append_optional_space();
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_mandatory_space()
Packit Service 7770af
  {
Packit Service 7770af
    scheduled_space = 1;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_optional_space()
Packit Service 7770af
  {
Packit Service 7770af
    if ((output_style() != COMPRESSED) && buffer().size()) {
Packit Service 7770af
      unsigned char lst = buffer().at(buffer().length() - 1);
Packit Service 7770af
      if (!isspace(lst) || scheduled_delimiter) {
Packit Service 7770af
        append_mandatory_space();
Packit Service 7770af
      }
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_special_linefeed()
Packit Service 7770af
  {
Packit Service 7770af
    if (output_style() == COMPACT) {
Packit Service 7770af
      append_mandatory_linefeed();
Packit Service 7770af
      for (size_t p = 0; p < indentation; p++)
Packit Service 7770af
        append_string(opt.indent);
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_optional_linefeed()
Packit Service 7770af
  {
Packit Service 7770af
    if (in_declaration && in_comma_array) return;
Packit Service 7770af
    if (output_style() == COMPACT) {
Packit Service 7770af
      append_mandatory_space();
Packit Service 7770af
    } else {
Packit Service 7770af
      append_mandatory_linefeed();
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_mandatory_linefeed()
Packit Service 7770af
  {
Packit Service 7770af
    if (output_style() != COMPRESSED) {
Packit Service 7770af
      scheduled_linefeed = 1;
Packit Service 7770af
      scheduled_space = 0;
Packit Service 7770af
      // flush_schedules();
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  void Emitter::append_scope_opener(AST_Node_Ptr node)
Packit Service 7770af
  {
Packit Service 7770af
    scheduled_linefeed = 0;
Packit Service 7770af
    append_optional_space();
Packit Service 7770af
    flush_schedules();
Packit Service 7770af
    if (node) add_open_mapping(node);
Packit Service 7770af
    append_string("{");
Packit Service 7770af
    append_optional_linefeed();
Packit Service 7770af
    // append_optional_space();
Packit Service 7770af
    ++ indentation;
Packit Service 7770af
  }
Packit Service 7770af
  void Emitter::append_scope_closer(AST_Node_Ptr node)
Packit Service 7770af
  {
Packit Service 7770af
    -- indentation;
Packit Service 7770af
    scheduled_linefeed = 0;
Packit Service 7770af
    if (output_style() == COMPRESSED)
Packit Service 7770af
      scheduled_delimiter = false;
Packit Service 7770af
    if (output_style() == EXPANDED) {
Packit Service 7770af
      append_optional_linefeed();
Packit Service 7770af
      append_indentation();
Packit Service 7770af
    } else {
Packit Service 7770af
      append_optional_space();
Packit Service 7770af
    }
Packit Service 7770af
    append_string("}");
Packit Service 7770af
    if (node) add_close_mapping(node);
Packit Service 7770af
    append_optional_linefeed();
Packit Service 7770af
    if (indentation != 0) return;
Packit Service 7770af
    if (output_style() != COMPRESSED)
Packit Service 7770af
      scheduled_linefeed = 2;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
}