<commit_before>class window.AutoComplete

  KEY_LEFT = 37
  KEY_RIGHT = 39

  constructor: (@variables=[], @functions=[]) ->

    @parser = new window.excellent.Parser('@', ['channel', 'contact', 'date', 'extra', 'flow', 'step']);
    @completions = @variables.concat(@functions)

    # mark our functions as functions
    for f in @functions
      f['function'] = true
      f['example'] = f['signature']

    ac = this

    @config =
      at: "@"
      insertBackPos: 1
      data: @variables
      searchKey: "name"
      insertTpl: @getInsertTemplate
      startWithSpace: true
      displayTpl: @getDisplayTemplate
      limit: 100
      maxLen: 100
      suffix: ""
      callbacks:

        highlighter: (li, query) -> return li

        matcher: (flag, subtext) ->
          return ac.parser.expressionContext(subtext)

        filter: (query, data, searchKey) ->

          if query and query[0] is '('
            data = ac.completions

          subQuery = ac.parseFilterQuery(query)
          lastIdx = if subQuery then subQuery.lastIndexOf('.') else -1
          start = subQuery.substring(0, lastIdx)
          results = ac.findCompletions(subQuery, data, start, lastIdx)

          return results

        sorter: (query, items, searchKey) ->

          # add an option to show our functions
          lastOptFunctions =
            'name': '('
            'display': "Functions",
            'function': true

          subQuery = ac.parseQuery(query);

          results = []
          for item in items
            if query
              item.order = new String(item[searchKey]).toLowerCase().indexOf(subQuery.toLowerCase())
              if item.order > -1
                results.push(item)
            else
              results.push(item)

          if not query or query.match(/[(.]/g) is null
            results.push(lastOptFunctions)

          results.sort (a,b) ->

            # prefer order if one is higher
            if a.order != b.order
              return a.order - b.order

            # otherwise, sort non-functions first
            if a.function and not b.function
              return 1
            else if b.function and not a.function
              return -1

            # lastly, just do alpha sort
            if (a.function and b.function) or (not a.function and not b.function)
              if a.name > b.name
                return 1
              else
                return -1

          return results

        tplEval: (tpl, map, action) ->

          template = tpl;
          query = this.query.text
          subQuery = ac.parseQuery(query)

          try
            template = tpl(map, query, subQuery)

            template.replace /\$\{([^\}]*)\}/g, (tag, key, pos) -> map[key]
          catch error
            return ""

        beforeInsert: (value, item) ->

          completionChars = new RegExp("([A-Za-z_\d\.]*)$", 'gi')
          valueForName = ""
          match = completionChars.exec(value)
          if match
            valueForName = match[2] || match[1]

          hasMore = false
          for option in ac.variables
            hasMore = valueForName and option.name.indexOf(valueForName) is 0 and option.name isnt valueForName
            if hasMore
              break

          value += '.' if hasMore

          isFunction = false
          for option in ac.functions
            isFunction = valueForName and option.name.indexOf(valueForName) is 0 and option.name is valueForName
            if isFunction
              break

          value += '()' if isFunction

          if valueForName is "" and value is '@('
            value += ')'
          else if valueForName and not hasMore and not isFunction
            value += " "

          return value

  getDisplayTemplate: (map, query, subQuery) ->
    template = "<li><div class='completion-dropdown'><div class='option-name'>${name}</div><small class='option-display'>${display}</small></div></li>"
    if typeof map.example isnt "undefined"
      template = "<li><div class='completion-dropdown'><div class='option-name'>${name}</div><div class='option-example'><div class='display-labels'>Example</div>${example}</div><div class='option-display'><div class='display-labels'>Summary</div>${display}</div></div></li>"<commit_msg>Don't append '.' to autocompleted items if they are just substrings of other items<commit_after>class window.AutoComplete

  KEY_LEFT = 37
  KEY_RIGHT = 39

  constructor: (@variables=[], @functions=[]) ->

    @parser = new window.excellent.Parser('@', ['channel', 'contact', 'date', 'extra', 'flow', 'step']);
    @completions = @variables.concat(@functions)

    # mark our functions as functions
    for f in @functions
      f['function'] = true
      f['example'] = f['signature']

    ac = this

    @config =
      at: "@"
      insertBackPos: 1
      data: @variables
      searchKey: "name"
      insertTpl: @getInsertTemplate
      startWithSpace: true
      displayTpl: @getDisplayTemplate
      limit: 100
      maxLen: 100
      suffix: ""
      callbacks:

        highlighter: (li, query) -> return li

        matcher: (flag, subtext) ->
          return ac.parser.expressionContext(subtext)

        filter: (query, data, searchKey) ->

          if query and query[0] is '('
            data = ac.completions

          subQuery = ac.parseFilterQuery(query)
          lastIdx = if subQuery then subQuery.lastIndexOf('.') else -1
          start = subQuery.substring(0, lastIdx)
          results = ac.findCompletions(subQuery, data, start, lastIdx)

          return results

        sorter: (query, items, searchKey) ->

          # add an option to show our functions
          lastOptFunctions =
            'name': '('
            'display': "Functions",
            'function': true

          subQuery = ac.parseQuery(query);

          results = []
          for item in items
            if query
              item.order = new String(item[searchKey]).toLowerCase().indexOf(subQuery.toLowerCase())
              if item.order > -1
                results.push(item)
            else
              results.push(item)

          if not query or query.match(/[(.]/g) is null
            results.push(lastOptFunctions)

          results.sort (a,b) ->

            # prefer order if one is higher
            if a.order != b.order
              return a.order - b.order

            # otherwise, sort non-functions first
            if a.function and not b.function
              return 1
            else if b.function and not a.function
              return -1

            # lastly, just do alpha sort
            if (a.function and b.function) or (not a.function and not b.function)
              if a.name > b.name
                return 1
              else
                return -1

          return results

        tplEval: (tpl, map, action) ->

          template = tpl;
          query = this.query.text
          subQuery = ac.parseQuery(query)

          try
            template = tpl(map, query, subQuery)

            template.replace /\$\{([^\}]*)\}/g, (tag, key, pos) -> map[key]
          catch error
            return ""

        beforeInsert: (value, item) ->

          completionChars = new RegExp("([A-Za-z_\d\.]*)$", 'gi')
          valueForName = ""
          match = completionChars.exec(value)
          if match
            valueForName = match[2] || match[1]

          hasMore = false
          for option in ac.variables
            hasMore = valueForName and option.name.indexOf(valueForName + '.') is 0 and option.name isnt valueForName
            if hasMore
              break

          value += '.' if hasMore

          isFunction = false
          for option in ac.functions
            isFunction = valueForName and option.name.indexOf(valueForName) is 0 and option.name is valueForName
            if isFunction
              break

          value += '()' if isFunction

          if valueForName is "" and value is '@('
            value += ')'
          else if valueForName and not hasMore and not isFunction
            value += " "

          return value

  getDisplayTemplate: (map, query, subQuery) ->
    template = "<li><div class='completion-dropdown'><div class='option-name'>${name}</div><small class='option-display'>${display}</small></div></li>"
    if typeof map.example isnt "undefined"
      template = "<li><div class='completion-dropdown'><div class='option-name'>${name}</div><div class='option-example'><div class='display-labels'>Example</div>${example}</div><div class='option-display'><div class='display-labels'>Summary</div>${display}</div></div></li>"
{'fraction_non_alphanumeric': 0.11849275362318841, 'fraction_numerical': 0.005333333333333333, 'mean_word_length': 1.8525132275132274, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2993127', 'n_tokens_mistral': 2406, 'n_tokens_neox': 2295, 'n_words': 651}