//  [ruby]
    def haml_internal_concat(text = "", newline = true, indent = true)
      if haml_buffer.options[:ugly] || haml_buffer.tabulation == 0
        haml_buffer.buffer << "#{text}#{"\n" if newline}"
      else
        haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
      end
    end
    private :haml_internal_concat

    # Allows writing raw content. `haml_internal_concat_raw` isn't
    # effected by XSS mods. Used by #haml_tag to write the actual tags.
    alias :haml_internal_concat_raw :haml_internal_concat

    # @return [String] The indentation string for the current line
    def haml_indent
      '  ' * haml_buffer.tabulation
    end

    # Creates an HTML tag with the given name and optionally text and attributes.
    # Can take a block that will run between the opening and closing tags.
    # If the block is a Haml block or outputs text using \{#haml\_concat},
    # the text will be properly indented.
    #
    # `name` can be a string using the standard Haml class/id shorthand
    # (e.g. "span#foo.bar", "#foo").
    # Just like standard Haml tags, these class and id values
    # will be merged with manually-specified attributes.
    #
    # `flags` is a list of symbol flags
    # like those that can be put at the end of a Haml tag
    # (`:/`, `:<`, and `:>`).
    # Currently, only `:/` and `:<` are supported.
    #
    # `haml_tag` outputs directly to the buffer;
    # its return value should not be used.
    # If you need to get the results as a string,
    # use \{#capture\_haml\}.
    #
    # For example,
    #
    #     haml_tag :table do
    #       haml_tag :tr do
    #         haml_tag 'td.cell' do
    #           haml_tag :strong, "strong!"
    #           haml_concat "data"
    #         end
    #         haml_tag :td do
    #           haml_concat "more_data"
    #         end
    #       end
    #     end
    #
    # outputs
    #
    #     <table>
    #       <tr>
    #         <td class='cell'>
    #           <strong>
    #             strong!
    #           </strong>
    #           data
    #         </td>
    #         <td>
    #           more_data
    #         </td>
    #       </tr>
    #     </table>
    #
    # @param name [#to_s] The name of the tag
    #
    # @overload haml_tag(name, *rest, attributes = {})
    #   @yield The block of Haml code within the tag
    # @overload haml_tag(name, text, *flags, attributes = {})
    #   @param text [#to_s] The text within the tag
    #   @param flags [Array<Symbol>] Haml end-of-tag flags
    def haml_tag(name, *rest, &block)
      ret = ErrorReturn.new("haml_tag")

      text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
      flags = []
      flags << rest.shift while rest.first.is_a? Symbol
      attrs = (rest.shift || {})
      attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
      name, attrs = merge_name_and_attributes(name.to_s, attrs)

      attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
        haml_buffer.options[:attr_wrapper],
        haml_buffer.options[:escape_attrs],
        haml_buffer.options[:hyphenate_data_attrs],
        attrs)

      if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
        haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
        return ret
      end

      if flags.include?(:/)
        raise Error.new(Error.message(:self_closing_content)) if text
        raise Error.new(Error.message(:illegal_nesting_self_closing)) if block
      end

      tag = "<#{name}#{attributes}>"
      end_tag = "</#{name}>"
      if block.nil?
        text = text.to_s
        if text.include?("\n")
          haml_internal_concat_raw tag
          tab_up
          haml_internal_concat text
          tab_down
          haml_internal_concat_raw end_tag
        else
          haml_internal_concat_raw tag, false
          haml_internal_concat text, false, false
          haml_internal_concat_raw end_tag, true, false
        end
        return ret
      end

      if text
        raise Error.new(Error.message(:illegal_nesting_line, name))
      end

      if flags.include?(:<)
        haml_internal_concat_raw tag, false
        haml_internal_concat "#{capture_haml(&block).strip}", false, false
        haml_internal_concat_raw end_tag, true, false
        return ret
      end

      haml_internal_concat_raw tag
      tab_up
      block.call
      tab_down
      haml_internal_concat_raw end_tag

      ret
    end

    # Conditionally wrap a block in an element. If `condition` is `true` then
    # this method renders the tag described by the arguments in `tag` (using
    # \{#haml_tag}) with the given block inside, otherwise it just renders the block.
    #
    # For example,
    #
    #     - haml_tag_if important, '.important' do
    #       %p
    #         A (possibly) important paragraph.
    #
    # will produce
    #
    #     <div class='important'>
    #       <p>
    #         A (possibly) important paragraph.
    #       </p>
    #     </div>
    #
    # if `important` is truthy, and just
    #
    #     <p>
    #       A (possibly) important paragraph.
    #     </p>
    #
    # otherwise.
    #
    # Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
    # return value should not be used. Use \{#capture_haml} if you need to use
    # its results as a string.
    #
    # @param condition The condition to test to determine whether to render
    #   the enclosing tag
    # @param tag Definition of the enclosing tag. See \{#haml_tag} for details
    #   (specifically the form that takes a block)
    def haml_tag_if(condition, *tag)
      if condition
        haml_tag(*tag){ yield }
      else
        yield
      end
      ErrorReturn.new("haml_tag_if")
    end

    # Characters that need to be escaped to HTML entities from user input
    HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#039;' }

    HTML_ESCAPE_REGEX = /['"><&]/

    # Returns a copy of `text` with ampersands, angle brackets and quotes
    # escaped into HTML entities.
    #
    # Note that if ActionView is loaded and XSS protection is enabled
    # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
    # this won't escape text declared as "safe".
    #
    # @param text [String] The string to sanitize
    # @return [String] The sanitized string
    def html_escape(text)
      text = text.to_s
      text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
    end

    HTML_ESCAPE_ONCE_REGEX = /[\"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/

    # Escapes HTML entities in `text`, but without escaping an ampersand
    # that is already part of an escaped entity.
    #
    # @param text [String] The string to sanitize
    # @return [String] The sanitized string
    def escape_once(text)
      text = text.to_s
      text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
    end

    # Returns whether or not the current template is a Haml template.
    #
    # This function, unlike other {Haml::Helpers} functions,
    # also works in other `ActionView` templates,
    # where it will always return false.
    #
    # @return [Boolean] Whether or not the current template is a Haml template
    def is_haml?
      !@haml_buffer.nil? && @haml_buffer.active?
    end

    # Returns whether or not `block` is defined directly in a Haml template.
    #
    # @param block [Proc] A Ruby block
    # @return [Boolean] Whether or not `block` is defined directly in a Haml template
    def block_is_haml?(block)
      eval('!!defined?(_hamlout)', block.binding)
    end

    private

    # Parses the tag name used for \{#haml\_tag}
    # and merges it with the Ruby attributes hash.
    def merge_name_and_attributes(name, attributes_hash = {})
      # skip merging if no ids or classes found in name
      return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/

      return $1 || "div", AttributeBuilder.merge_attributes(
        Haml::Parser.parse_class_and_id($2), attributes_hash)
    end

    # Runs a block of code with the given buffer as the currently active buffer.
    #
    # @param buffer [Haml::Buffer] The Haml buffer to use temporarily
    # @yield A block in which the given buffer should be used
    def with_haml_buffer(buffer)
      @haml_buffer, old_buffer = buffer, @haml_buffer
      old_buffer.active, old_was_active = false, old_buffer.active? if old_buffer
      @haml_buffer.active, was_active = true, @haml_buffer.active?
      yield
    ensure
      @haml_buffer.active = was_active
      old_buffer.active = old_was_active if old_buffer
      @haml_buffer = old_buffer
    end

    # The current {Haml::Buffer} object.
    #
    # @return [Haml::Buffer]
    def haml_buffer
      @haml_buffer if defined? @haml_buffer
    end

    # Gives a proc the same local `_hamlout` and `_erbout` variables
    # that the current template has.
    #
    # @param proc [#call] The proc to bind
    # @return [Proc] A new proc with the new variables bound
    def haml_bind_proc(&proc)
      _hamlout = haml_buffer
      #double assignment is to avoid warnings
      _erbout = _erbout = _hamlout.buffer
      proc { |*args| proc.call(*args) }
    end

    def prettify(text)
      text = text.split(/^/)
      text.delete('')

      min_tabs = nil
      text.each do |line|
        tabs = line.index(/[^ ]/) || line.length
        min_tabs ||= tabs
        min_tabs = min_tabs > tabs ? tabs : min_tabs
      end

      text.each_with_object('') do |line, str|
        str << line.slice(min_tabs, line.length)
      end
    end
  end
end