<commit_before>###
 Project: opensong.js
 Description: displays OpenSong files nicely on a web page
 Author: <NAME>
 License: LGPL 2.1
###

class OpenSong

  constructor: (element, lyrics) ->
    @el = getDomElem element
    @tpl = do ->
      # TODO: support comments
      templateSrc = """
        {{#this}}
        <h2>{{human_header header}}</h2>
          {{#lines}}
        <table>
          <tr class="chords">
            {{#chords}}
            <td>{{transpose this}}</td>
            {{/chords}}
          </tr>
            {{#lyrics}}
          <tr class='lyrics'>
              {{#this}}
            <td>{{this}}</td>
              {{/this}}
          </tr>
            {{/lyrics}}
        </table>
          {{/lines}}
        {{/this}}
      """
      Handlebars.compile templateSrc

    this.setLyrics lyrics

  transpose: (amount) ->
    Handlebars.registerHelper 'transpose', (chord) ->
      opensong.helper.transposeChord chord, amount || 0

    this.renderLyrics() # rerender

  setLyrics: (lyrics) ->
    @model = opensong.helper.parseLyrics lyrics
    this.renderLyrics()

  renderLyrics: ->
    # clear Html Element and add opensong class
    @el.innerHTML = @tpl @model
    @el.className += " opensong" unless /opensong/.test @el.className


  getDomElem = (domElem) ->
    if typeof domElem is 'string'
      return document.getElementById domElem

    if domElem.jquery
      return domElem.get(0)

    if domElem.nodeType
      return domElem

    undefined

  Handlebars.registerHelper 'human_header', (abbr) ->
    opensong.helper.humanizeHeader abbr

  Handlebars.registerHelper 'transpose', (chord) ->
    chord # just return chord, no transposing initially


opensong = opensong || {}
opensong.helper = opensong.helper || {}

opensong.helper.transposeChord = (chord, amount) ->
  chords = [
    "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
    "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"
  ]

  outputChords = []
  for c in chord.split "/"
    m = /^([A-G][#b]?)(.*)$/.exec c
    return chord unless m

    [_, chordRoot, chordExt] = m
    index = chords.indexOf chordRoot
    if index < 0 # use chord if not found
      outputChords.push c
      continue

    # make negative amounts work, always transpose to sharps
    newIndex = (index + amount + chords.length) % (chords.length / 2)
    outputChords.push chords[newIndex] + chordExt

  outputChords.join "/"


opensong.helper.humanizeHeader = (abbr) ->
  abbArr = /([a-zA-Z]+)(\d*)/.exec(abbr)[1..]
  char = abbArr[0]

  abbArr[0] = switch char
    when "C"
      "Chorus"
    when "V"
      "Verse"
    when "B"
      "Bridge"
    when "T"
      "Tag"
    when "P"
      "Pre-Chorus"
    else
      char

  abbArr.pop() unless abbArr[1]? # remove num if empty
  abbArr.join " "

###

json = [
  {
    header: "V",
    lines: [
      {
        chords: ["A", "C"],
        lyrics: [
          ["Yeah", "Yeah, God is grea!"]
        ]
      },
      {
        comments: "This is a comment"
      }
    ]<commit_msg>fix if header has no num value<commit_after>###
 Project: opensong.js
 Description: displays OpenSong files nicely on a web page
 Author: <NAME>
 License: LGPL 2.1
###

class OpenSong

  constructor: (element, lyrics) ->
    @el = getDomElem element
    @tpl = do ->
      # TODO: support comments
      templateSrc = """
        {{#this}}
        <h2>{{human_header header}}</h2>
          {{#lines}}
        <table>
          <tr class="chords">
            {{#chords}}
            <td>{{transpose this}}</td>
            {{/chords}}
          </tr>
            {{#lyrics}}
          <tr class='lyrics'>
              {{#this}}
            <td>{{this}}</td>
              {{/this}}
          </tr>
            {{/lyrics}}
        </table>
          {{/lines}}
        {{/this}}
      """
      Handlebars.compile templateSrc

    this.setLyrics lyrics

  transpose: (amount) ->
    Handlebars.registerHelper 'transpose', (chord) ->
      opensong.helper.transposeChord chord, amount || 0

    this.renderLyrics() # rerender

  setLyrics: (lyrics) ->
    @model = opensong.helper.parseLyrics lyrics
    this.renderLyrics()

  renderLyrics: ->
    # clear Html Element and add opensong class
    @el.innerHTML = @tpl @model
    @el.className += " opensong" unless /opensong/.test @el.className


  getDomElem = (domElem) ->
    if typeof domElem is 'string'
      return document.getElementById domElem

    if domElem.jquery
      return domElem.get(0)

    if domElem.nodeType
      return domElem

    undefined

  Handlebars.registerHelper 'human_header', (abbr) ->
    opensong.helper.humanizeHeader abbr

  Handlebars.registerHelper 'transpose', (chord) ->
    chord # just return chord, no transposing initially


opensong = opensong || {}
opensong.helper = opensong.helper || {}

opensong.helper.transposeChord = (chord, amount) ->
  chords = [
    "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
    "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"
  ]

  outputChords = []
  for c in chord.split "/"
    m = /^([A-G][#b]?)(.*)$/.exec c
    return chord unless m

    [_, chordRoot, chordExt] = m
    index = chords.indexOf chordRoot
    if index < 0 # use chord if not found
      outputChords.push c
      continue

    # make negative amounts work, always transpose to sharps
    newIndex = (index + amount + chords.length) % (chords.length / 2)
    outputChords.push chords[newIndex] + chordExt

  outputChords.join "/"


opensong.helper.humanizeHeader = (abbr) ->
  abbArr = /([a-zA-Z]+)(\d*)/.exec(abbr)[1..]
  char = abbArr[0]

  abbArr[0] = switch char
    when "C"
      "Chorus"
    when "V"
      "Verse"
    when "B"
      "Bridge"
    when "T"
      "Tag"
    when "P"
      "Pre-Chorus"
    else
      char

  abbArr.pop() if abbArr[1] is "" # remove num if empty
  abbArr.join " "

###

json = [
  {
    header: "V",
    lines: [
      {
        chords: ["A", "C"],
        lyrics: [
          ["Yeah", "Yeah, God is grea!"]
        ]
      },
      {
        comments: "This is a comment"
      }
    ]
{'fraction_non_alphanumeric': 0.1601639344262295, 'fraction_numerical': 0.003934426229508197, 'mean_word_length': 2.11116777154513, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 51, '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': '1262365', 'n_tokens_mistral': 2148, 'n_tokens_neox': 2060, 'n_words': 519}