<commit_before>fs = require "fs"
bibtexParse = require "zotero-bibtex-parse"
fuzzaldrin = require "fuzzaldrin"
XRegExp = require('xregexp').XRegExp
titlecaps = require "./titlecaps"
citeproc = require "./citeproc"
yaml = require "yaml-js"

module.exports =
class ReferenceProvider

  atom.deserializers.add(this)

  @deserialize: ({data}) -> new ReferenceProvider(data)

  constructor: (state) ->
    if state and Object.keys(state).length != 0
      @bibtex = state.bibtex
      @possibleWords = state.possibleWords
    else
      @buildWordListFromFiles(atom.config.get "autocomplete-bibtex.bibtex")

    if @bibtex.length == 0
      @buildWordListFromFiles(atom.config.get "autocomplete-bibtex.bibtex")

    atom.config.onDidChange "autocomplete-bibtex.bibtex", (bibtexFiles) =>
      @buildWordListFromFiles(bibtexFiles)

    resultTemplate = atom.config.get "autocomplete-bibtex.resultTemplate"
    atom.config.observe "autocomplete-bibtex.resultTemplate", (resultTemplate) =>
      @resultTemplate = resultTemplate

    allwords = @possibleWords

    @provider =
      selector: atom.config.get "autocomplete-bibtex.scope"
      disableForSelector: atom.config.get "autocomplete-bibtex.ignoreScope"
      inclusionPriority: 1
      excludeLowerPriority: true

      compare: (a,b) ->
        if a.score < b.score
          return -1
        if a.score > b.score
          return 1
        return 0

      getSuggestions: ({editor, bufferPosition}) ->
        prefix = @getPrefix(editor, bufferPosition)
        new Promise (resolve) ->
          if prefix[0] == "@"
            p = prefix.normalize().replace(/^@/, '')
            suggestions = []
            hits = fuzzaldrin.filter allwords, p, { key: 'author' }
            for h in hits
              h.score = fuzzaldrin.score(p, h.author)
            hits.sort @compare
            resultTemplate = atom.config.get "autocomplete-bibtex.resultTemplate"
            for word in hits
              suggestion = {
                text: resultTemplate.replace("[key]", word.key)
                displayText: word.label
                replacementPrefix: prefix
                leftLabel: word.key
                rightLabel: word.by
                className: word.type
                iconHTML: '<i class="icon-mortar-board"></i>'
              }
              if word.in?
                suggestion.description = word.in
              if word.url?
                suggestion.descriptionMoreURL = word.url
              suggestions = suggestions.concat suggestion
            resolve(suggestions)

      getPrefix: (editor, bufferPosition) ->
        # Whatever your prefix regex might be
        regex = /@[\w-]+/
        wordregex = XRegExp('(?:^|[\\p{WhiteSpace}\\p{Punctuation}])@[\\p{Letter}\\p{Number}\._-]*')
        cursor = editor.getCursors()[0]
        start = cursor.getBeginningOfCurrentWordBufferPosition({ wordRegex: wordregex, allowPrevious: false })
        end = bufferPosition
        # Get the text for the line up to the triggered buffer position
        line = editor.getTextInRange([start, bufferPosition])
        # Match the regex to the line, and return the match
        line.match(regex)?[0] or ''


  serialize: -> {
    deserializer: 'ReferenceProvider'
    data: { bibtex: @bibtex, possibleWords: @possibleWords }
  }

  buildWordList: () =>
    possibleWords = []
    for citation in @bibtex
      if citation.entryTags and citation.entryTags.title and (citation.entryTags.author or citation.entryTags.editor)
        citation.entryTags.prettyTitle =
          @prettifyTitle citation.entryTags.title

        citation.entryTags.authors = []

        if citation.entryTags.author?
          citation.entryTags.authors =
            citation.entryTags.authors.concat @cleanAuthors citation.entryTags.author.split ' and '

        if not citation.entryTags.editors
          if citation.entryTags.editor?
            citation.entryTags.authors =
              citation.entryTags.authors.concat @cleanAuthors citation.entryTags.editor.split ' and '

        citation.entryTags.prettyAuthors =
          @prettifyAuthors citation.entryTags.authors

        for author in citation.entryTags.authors
          new_word = {
            author: @prettifyName(author),
            key: citation.citationKey,
            label: "#{citation.entryTags.prettyTitle}"
            by: "#{citation.entryTags.prettyAuthors}"
            type: "#{citation.entryTags.type}"
          }
          if citation.entryTags.url?
            new_word.url = citation.entryTags.url
          if citation.entryTags.in?
            new_word.in = citation.entryTags.in
          possibleWords.push new_word

    @possibleWords = possibleWords

  buildWordListFromFiles: (bibtexFiles) =>
    @readBibtexFiles(bibtexFiles)
    @buildWordList()

  readReferenceFiles: (referenceFiles) =>
    if referenceFiles.newValue?
      referenceFiles = referenceFiles.newValue
    # Make sure our list of files is an array, even if it's only one file
    if not Array.isArray(referenceFiles)
      referenceFiles = [referenceFiles]
    try
      references = []
      for file in referenceFiles

        # What type of file is this?
        ftype = file.split('.')
        ftype = ftype[ftype.length - 1]

      for file in bibtexFiles
        if fs.statSync(file).isFile()
          parser = new bibtexParse(fs.readFileSync(file, 'utf-8'))

          if ftype is "bib"
            parser = new bibtexParse(fs.readFileSync(file, 'utf-8'))
            references = references.concat parser.parse()

          if ftype is "json"
            cpobject = JSON.parse fs.readFileSync(file, 'utf-8')
            citeproc_refs = citeproc.parse cpobject
            references = references.concat citeproc_refs

          if ftype is "yaml"
            cpobject = yaml.load fs.readFileSync(file, 'utf-8')
            citeproc_refs = citeproc.parse cpobject
            references = references.concat citeproc_refs

        else
          console.warn("'#{file}' does not appear to be a file, so autocomplete-bibtex will not try to parse it.")

      @bibtex = bibtex
    catch error
      console.error error

  prettifyTitle: (title) ->
    return if not title
    title = titlecaps(title)
    return title

  cleanAuthors: (authors) -><commit_msg>Clean up misreferences to '-bibtex-' where functions and variables have been renamed '-reference-'.<commit_after>fs = require "fs"
bibtexParse = require "zotero-bibtex-parse"
fuzzaldrin = require "fuzzaldrin"
XRegExp = require('xregexp').XRegExp
titlecaps = require "./titlecaps"
citeproc = require "./citeproc"
yaml = require "yaml-js"

module.exports =
class ReferenceProvider

  atom.deserializers.add(this)

  @deserialize: ({data}) -> new ReferenceProvider(data)

  constructor: (state) ->
    if state and Object.keys(state).length != 0
      @bibtex = state.bibtex
      @possibleWords = state.possibleWords
    else
      @buildWordListFromFiles(atom.config.get "autocomplete-bibtex.bibtex")

    if @bibtex.length == 0
      @buildWordListFromFiles(atom.config.get "autocomplete-bibtex.bibtex")

    atom.config.onDidChange "autocomplete-bibtex.bibtex", (bibtexFiles) =>
      @buildWordListFromFiles(bibtexFiles)

    resultTemplate = atom.config.get "autocomplete-bibtex.resultTemplate"
    atom.config.observe "autocomplete-bibtex.resultTemplate", (resultTemplate) =>
      @resultTemplate = resultTemplate

    allwords = @possibleWords

    @provider =
      selector: atom.config.get "autocomplete-bibtex.scope"
      disableForSelector: atom.config.get "autocomplete-bibtex.ignoreScope"
      inclusionPriority: 1
      excludeLowerPriority: true

      compare: (a,b) ->
        if a.score < b.score
          return -1
        if a.score > b.score
          return 1
        return 0

      getSuggestions: ({editor, bufferPosition}) ->
        prefix = @getPrefix(editor, bufferPosition)
        new Promise (resolve) ->
          if prefix[0] == "@"
            p = prefix.normalize().replace(/^@/, '')
            suggestions = []
            hits = fuzzaldrin.filter allwords, p, { key: 'author' }
            for h in hits
              h.score = fuzzaldrin.score(p, h.author)
            hits.sort @compare
            resultTemplate = atom.config.get "autocomplete-bibtex.resultTemplate"
            for word in hits
              suggestion = {
                text: resultTemplate.replace("[key]", word.key)
                displayText: word.label
                replacementPrefix: prefix
                leftLabel: word.key
                rightLabel: word.by
                className: word.type
                iconHTML: '<i class="icon-mortar-board"></i>'
              }
              if word.in?
                suggestion.description = word.in
              if word.url?
                suggestion.descriptionMoreURL = word.url
              suggestions = suggestions.concat suggestion
            resolve(suggestions)

      getPrefix: (editor, bufferPosition) ->
        # Whatever your prefix regex might be
        regex = /@[\w-]+/
        wordregex = XRegExp('(?:^|[\\p{WhiteSpace}\\p{Punctuation}])@[\\p{Letter}\\p{Number}\._-]*')
        cursor = editor.getCursors()[0]
        start = cursor.getBeginningOfCurrentWordBufferPosition({ wordRegex: wordregex, allowPrevious: false })
        end = bufferPosition
        # Get the text for the line up to the triggered buffer position
        line = editor.getTextInRange([start, bufferPosition])
        # Match the regex to the line, and return the match
        line.match(regex)?[0] or ''


  serialize: -> {
    deserializer: 'ReferenceProvider'
    data: { bibtex: @bibtex, possibleWords: @possibleWords }
  }

  buildWordList: () =>
    possibleWords = []
    for citation in @bibtex
      if citation.entryTags and citation.entryTags.title and (citation.entryTags.author or citation.entryTags.editor)
        citation.entryTags.prettyTitle =
          @prettifyTitle citation.entryTags.title

        citation.entryTags.authors = []

        if citation.entryTags.author?
          citation.entryTags.authors =
            citation.entryTags.authors.concat @cleanAuthors citation.entryTags.author.split ' and '

        if not citation.entryTags.editors
          if citation.entryTags.editor?
            citation.entryTags.authors =
              citation.entryTags.authors.concat @cleanAuthors citation.entryTags.editor.split ' and '

        citation.entryTags.prettyAuthors =
          @prettifyAuthors citation.entryTags.authors

        for author in citation.entryTags.authors
          new_word = {
            author: @prettifyName(author),
            key: citation.citationKey,
            label: "#{citation.entryTags.prettyTitle}"
            by: "#{citation.entryTags.prettyAuthors}"
            type: "#{citation.entryTags.type}"
          }
          if citation.entryTags.url?
            new_word.url = citation.entryTags.url
          if citation.entryTags.in?
            new_word.in = citation.entryTags.in
          possibleWords.push new_word

    @possibleWords = possibleWords

  buildWordListFromFiles: (bibtexFiles) =>
    @readReferenceFiles(bibtexFiles)
    @buildWordList()

  readReferenceFiles: (referenceFiles) =>
    if referenceFiles.newValue?
      referenceFiles = referenceFiles.newValue
    # Make sure our list of files is an array, even if it's only one file
    if not Array.isArray(referenceFiles)
      referenceFiles = [referenceFiles]
    try
      references = []
      for file in referenceFiles

        # What type of file is this?
        ftype = file.split('.')
        ftype = ftype[ftype.length - 1]

        if fs.statSync(file).isFile()
          parser = new bibtexParse(fs.readFileSync(file, 'utf-8'))

          if ftype is "bib"
            parser = new bibtexParse(fs.readFileSync(file, 'utf-8'))
            references = references.concat parser.parse()

          if ftype is "json"
            cpobject = JSON.parse fs.readFileSync(file, 'utf-8')
            citeproc_refs = citeproc.parse cpobject
            references = references.concat citeproc_refs

          if ftype is "yaml"
            cpobject = yaml.load fs.readFileSync(file, 'utf-8')
            citeproc_refs = citeproc.parse cpobject
            references = references.concat citeproc_refs

        else
          console.warn("'#{file}' does not appear to be a file, so autocomplete-bibtex will not try to parse it.")

      @bibtex = references
    catch error
      console.error error

  prettifyTitle: (title) ->
    return if not title
    title = titlecaps(title)
    return title

  cleanAuthors: (authors) ->
{'fraction_non_alphanumeric': 0.10075187969924812, 'fraction_numerical': 0.00221606648199446, 'mean_word_length': 2.3322784810126582, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 37, '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': '4781186', 'n_tokens_mistral': 3724, 'n_tokens_neox': 3460, 'n_words': 818}