docs: def _construct_start_index(text, layer, markup_settings, spansStartingFrom=None):
      ''' Creates an index which stores all annotations of given text layer,
          indexed by the start position of the annotation (annotation[START]).
          Alternatively, if the index spansStartingFrom is already provided
          as an input argument, obtains annotation information from the given 
          text layer, and stores into the index;
          
          The method also creates an ( ANSI-terminal compatible ) mark-up of 
          the annotations (generates start and end tags), following the 
          specification in markup_settings. The markup_settings should be a
          dict, setting at least one of the following visualisation options:
            * 'bracket' : True -- annotations will be surrounded with brackets; 
                                  This works in any terminal;
            * 'underline' : True -- annotations will be underlined; This works in 
                                    an ANSI compatible terminal;
            * 'color' : ('red', 'green', 'blue' etc. ) -- annotated text will be 
                                                          displayed in given color; 
                                                          this works in an ANSI 
                                                          compatible terminal;
          
          Each start position (in the index) is associated with a list of 
          annotation objects (annotations starting from that position).
          An annotation object is a list containing the following information:
           *) START position (of the annotation),
           *) END position (of the annotation),
           *) layer (name), 
           *) startTags -- graphic or textual formatting of the start tag, 
           *) endTags -- graphic or textual formatting of the end tag, 
           *) graphicFormatting -- boolean (whether graphic formatting was used?), 
           *) bracketing -- boolean (whether bracketing was used?), 
         
          Multiple annotation objects starting from the same position are sorted by 
          their length: longer annotations preceding the shorter ones;
         
          The method returns created (or augmented) index (a dict object indexed 
          by START positions);
      '''
      if not markup_settings or not isinstance(markup_settings, dict):
         raise Exception('Error: markup_settings should be a dict containing markup specification;')
      # ----------------------------
      # 1) Construct start and end tags, considering the formatting settings
      startTags = ''
      endTags   = ''
      graphicFormatting = False
      bracketing        = False
      # -- Underlining
      if ('u' in markup_settings and markup_settings['u']) or \
         ('underline' in markup_settings and markup_settings['underline']):
         startTags += '\033[4m'
         endTags   += '\033[0m'
         graphicFormatting = True
      colorName = markup_settings['c'] if 'c' in markup_settings else None
      colorName = markup_settings['color'] if 'color' in markup_settings else colorName
      # -- Coloring
      if colorName:
         color = _get_ANSI_colored_font( colorName )
         if color:
            startTags += color
            endTags   += '\033[0m'
            graphicFormatting = True
         else:
            raise Exception('Unknown color:', colorName)
      # -- Bracketing
      if ('b' in markup_settings and markup_settings['b']) or \
         ('bracket' in markup_settings and markup_settings['bracket']):
         startTags += '['
         # Add ending bracket before graphics ends (otherwise the 
         # graphics have no effect on the ending bracket)
         endTags    = ']'+endTags
         bracketing = True
      # Hack: if both bracketing and graphic formatting are used, add graphic
      #       formatting before the closing bracket of the endTag (to ensure
      #       that graphic formatting of the ending bracket is not overwritten
      #       mistakenly);
      if graphicFormatting and bracketing:
         startTags2 = startTags.rstrip('[')
         endTags    = startTags2+endTags
  
      # ----------------------------
      # 2) Get extractor for the elements of given layer
      # >>> The following code borrows from estnltk.prettyprinter.marker :
      # decide which extractor to use
      # first just assume we need to use a multi layer text extractor
      extractor = lambda t: texts_multi(t, layer)
      # if user has specified his/her own callable, use it
      if hasattr(layer, '__call__'):
          extractor = layer
      elif text.is_simple(layer):
          # the given layer is simple, so use simple text extractor
          extractor = lambda t: texts_simple(t, layer)
      # >>>
  
      # ----------------------------
      # 3) Store an annotation for each span of given layer
      if not spansStartingFrom:
          spansStartingFrom = {}
      for elem in extractor(text):
          if elem[START] not in spansStartingFrom:
             spansStartingFrom[elem[START]] = []
          span1 = [elem[START], elem[END], layer, startTags, endTags, graphicFormatting, bracketing]
          # Insert the span into the index
          if not spansStartingFrom[elem[START]]:
             spansStartingFrom[elem[START]].append( span1 )
          else:
             # Make sure that spans are inserted in the order of decreasing length: 
             #  longer spans preceding the shorter ones;
             inserted = False
             for i in range( len(spansStartingFrom[elem[START]]) ):
                 span2 = spansStartingFrom[elem[START]][i]
                 # If an existing span is shorter than the current span, insert the
                 # current span before the existing span ...
                 if span1[1] > span2[1]:
                    spansStartingFrom[elem[START]].insert( i, span1 )
                    inserted = True
                    break
                 elif span1[1] == span2[1] and span1[2] < span2[2]:
                    # If both spans have equal length, order the spans in the alphabetical
                    # order of layer names:
                    spansStartingFrom[elem[START]].insert( i, span1 )
                    inserted = True
                    break
             if not inserted:
                 spansStartingFrom[elem[START]].append(span1)
      return spansStartingFrom