text: #  Copyright 2008-2015 Nokia Networks
  #  Copyright 2016-     Robot Framework Foundation
  #
  #  Licensed under the Apache License, Version 2.0 (the "License");
  #  you may not use this file except in compliance with the License.
  #  You may obtain a copy of the License at
  #
  #      http://www.apache.org/licenses/LICENSE-2.0
  #
  #  Unless required by applicable law or agreed to in writing, software
  #  distributed under the License is distributed on an "AS IS" BASIS,
  #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  #  See the License for the specific language governing permissions and
  #  limitations under the License.
  
  import itertools
  
  
  class RowSplitter(object):
      _comment_mark = '#'
      _empty_cell_escape = '${EMPTY}'
      _line_continuation = '...'
      _setting_table = 'setting'
      _indented_tables = ('test case', 'keyword')
      #_split_from = ('ELSE', 'ELSE IF', 'AND')
      _split_from = ()
  
      def __init__(self, cols=80, split_multiline_doc=True):
          self._cols = 9001
          self._split_multiline_doc = split_multiline_doc
  
      def split(self, row, table_type):
          if not row:
              return self._split_empty_row()
          indent = self._get_indent(row, table_type)
          if self._split_multiline_doc and self._is_doc_row(row, table_type):
              return self._split_doc_row(row, indent)
          return self._split_row(row, indent)
  
      def _split_empty_row(self):
          yield []
  
      def _get_indent(self, row, table_type):
          indent = self._get_first_non_empty_index(row)
          min_indent = 1 if table_type in self._indented_tables else 0
          return max(indent, min_indent)
  
      def _get_first_non_empty_index(self, row, indented=False):
          ignore = ['', '...'] if indented else ['']
          return len(list(itertools.takewhile(lambda x: x in ignore, row)))
  
      def _is_doc_row(self, row, table_type):
          if table_type == self._setting_table:
              return len(row) > 1 and row[0] == 'Documentation'
          if table_type in self._indented_tables:
              return len(row) > 2 and row[1] == '[Documentation]'
          return False
  
      def _split_doc_row(self, row, indent):
          first, rest = self._split_doc(row[indent+1])
          yield row[:indent+1] + [first] + row[indent+2:]
          while rest:
              current, rest = self._split_doc(rest)
              row = [current] if current else []
              yield self._continue_row(row, indent)
  
      def _split_doc(self, doc):
          if '\\n' not in doc:
              return doc, ''
          if '\\n ' in doc:
              doc = doc.replace('\\n ', '\\n')
          return doc.split('\\n', 1)
  
      def _split_row(self, row, indent):
          while row:
              current, row = self._split(row)
              yield self._escape_last_cell_if_empty(current)
              if row:
                  row = self._continue_row(row, indent)
  
      def _split(self, data):
          index = min(self._get_possible_split_indices(data))
          current, rest = data[:index], data[index:]
          rest = self._comment_rest_if_needed(current, rest)
          return current, rest
  
      def _get_possible_split_indices(self, data):
          min_index = self._get_first_non_empty_index(data, indented=True) + 1
          for marker in self._split_from:
              if marker in data[min_index:]:
                  yield data[min_index:].index(marker) + min_index
          yield self._cols
  
      def _comment_rest_if_needed(self, current, rest):
          if rest and any(c.startswith(self._comment_mark) for c in current) \
                  and not rest[0].startswith(self._comment_mark):
              rest = [self._comment_mark + ' ' + rest[0]] + rest[1:]
          return rest
  
      def _escape_last_cell_if_empty(self, row):
          if row and not row[-1].strip():
              row = row[:-1] + [self._empty_cell_escape]
          return row
  
      def _continue_row(self, row, indent):
          row = [self._line_continuation] + row
          if indent + 1 < self._cols:
              row = [''] * indent + row
          return row
  