<commit_before>ChordProEditor = {
    //main function
    watch: function(classSelector){
        this.songs = document.querySelectorAll('textarea.'+classSelector);
        this.background_songs = [];

        this.insert_backgrounds(this.songs);
        //this.background_songs = document.querySelectorAll('div.'+classSelector);

        this.load_grammar();
    },

    debug:false,

    resfreshTimers: [],
    resfreshDelay: 500,

    // song tags transformation
    insert_backgrounds: function(songs) {
        var length = songs.length;
        var background_model = document.createElement('div');
        background_model.className = "chordpro-song";
        for (var i = 0; i < length; i++) {
            songs[i].dataset.id = i;
            this.textarea_adjust_height(songs[i]);
            var background_song = background_model.cloneNode(false);
            this.insert_background(songs[i], background_song);
        }
    },
    insert_background: function(song, background_song) {
        song.parentNode.insertBefore(background_song, song);
        this.background_songs.push(background_song);
    },


    textarea_adjust_height: function(song) {
        song.style.height = 'auto';
        song.style.height = song.scrollHeight+'px';
    },

    // song markup transformation
    initialize_markups: function(songs) {
        var length = songs.length;
        for (var i = 0; i < length; i++) {
            addEvent(songs[i], 'input', this.markup_changed);
            addEvent(songs[i], 'keyup', this.markup_changed);
            this.update_markup(songs[i]);
        }
    },
    markup_changed: function(event){
        var song = event.target;
        ChordProEditor.textarea_adjust_height(song);
        var id = song.dataset.id;
        window.clearTimeout(ChordProEditor.resfreshTimers[id]);
        ChordProEditor.resfreshTimers[id] = window.setTimeout(function(){
            ChordProEditor.update_markup(song);
        }, ChordProEditor.resfreshDelay);
    },
    clean_newlines: function(text){
        // add a leading newline
        clean_text = '\n' + text;
        // only "\n" type are considered
        clean_text = clean_text.replace(/\r\n/g ,'\n').replace(/\r/g ,'\n');
        // add a trailing newline if missing
        if(clean_text.slice(-1) != '\n'){
            clean_text += '\n';
        }
        return clean_text;
    },
    clean_formatted_newlines: function(text){
        // remove first newline and add a trailing newline
        return text.slice(1) + "\n";
    },
    insert_exception_markup: function(exception, text){
        if(ChordProEditor.debug){
            console.log(exception);
        }
        var line = exception.line - 1;
        var column = exception.column - 1;

        var max_line = (text.match(/\n/g) || []).length;
        if(line == max_line){
            line -= 1;
        }

        var regex_model = '^((?:[^\\n]*\\n){@line})([^\\n]{@column})([^\\n]?)([^\\n]*)((?:\\n.*)*)$';
        regex_model = regex_model.replace('@line', line);
        regex_model = regex_model.replace('@column', column);
        var regex = new RegExp(regex_model);

        matches = text.match(regex);

        formatted_text = matches[1];
        formatted_text += '<span class="error-line">';
        formatted_text += matches[2];
        formatted_text += '<span class="error-char">';
        formatted_text += matches[3];
        formatted_text += '</span>';
        formatted_text += matches[4];
        formatted_text += '</span>';
        formatted_text += matches[5];

        return formatted_text;
    },
    update_markup: function(song) {
        var id = song.dataset.id;
        var background_song = ChordProEditor.background_songs[id]

        var raw_text = ChordProEditor.clean_newlines(song.value);

        var parsed_text;
        try {
            parsed_text = ChordProEditor.peg.parse(raw_text);
        } catch (exception) {
            parsed_text = ChordProEditor.insert_exception_markup(exception, raw_text);
        }
        parsed_text = ChordProEditor.clean_formatted_newlines(parsed_text);

        background_song.innerHTML = parsed_text;
    },


    //load grammar file
    grammar_file: "js/grammar.txt",
    load_grammar: function(){
        this.load_file(this.grammar_file, this.parse_grammar);
    },
    parse_grammar: function(text){
        this.peg = PEG.buildParser(text);
        this.initialize_markups(this.songs);
    },<commit_msg>Prevent chords from overlapping onload<commit_after>ChordProEditor = {
    //main function
    watch: function(classSelector){
        this.songs = document.querySelectorAll('textarea.'+classSelector);
        this.background_songs = [];

        this.insert_backgrounds(this.songs);
        //this.background_songs = document.querySelectorAll('div.'+classSelector);

        this.load_grammar();
    },

    debug:false,

    resfreshTimers: [],
    resfreshDelay: 500,

    // song tags transformation
    insert_backgrounds: function(songs) {
        var length = songs.length;
        var background_model = document.createElement('div');
        background_model.className = "chordpro-song";
        for (var i = 0; i < length; i++) {
            songs[i].dataset.id = i;
            this.textarea_adjust_height(songs[i]);
            var background_song = background_model.cloneNode(false);
            this.insert_background(songs[i], background_song);
        }
    },
    insert_background: function(song, background_song) {
        song.parentNode.insertBefore(background_song, song);
        this.background_songs.push(background_song);
    },


    textarea_adjust_height: function(song) {
        song.style.height = 'auto';
        song.style.height = song.scrollHeight+'px';
    },

    // song markup transformation
    initialize_markups: function(songs) {
        var length = songs.length;
        for (var i = 0; i < length; i++) {
            addEvent(songs[i], 'input', this.markup_changed);
            addEvent(songs[i], 'keyup', this.markup_changed);
            this.update_markup(songs[i]);
        }
    },
    markup_changed: function(event){
        var song = event.target;
        ChordProEditor.textarea_adjust_height(song);
        var id = song.dataset.id;
        window.clearTimeout(ChordProEditor.resfreshTimers[id]);
        ChordProEditor.resfreshTimers[id] = window.setTimeout(function(){
            ChordProEditor.update_markup(song);
        }, ChordProEditor.resfreshDelay);
    },
    clean_newlines: function(text){
        // add a leading newline
        clean_text = '\n' + text;
        // only "\n" type are considered
        clean_text = clean_text.replace(/\r\n/g ,'\n').replace(/\r/g ,'\n');
        // add a trailing newline if missing
        if(clean_text.slice(-1) != '\n'){
            clean_text += '\n';
        }
        return clean_text;
    },
    clean_formatted_newlines: function(text){
        // remove first newline and add a trailing newline
        return text.slice(1) + "\n";
    },
    insert_exception_markup: function(exception, text){
        if(ChordProEditor.debug){
            console.log(exception);
        }
        var line = exception.line - 1;
        var column = exception.column - 1;

        var max_line = (text.match(/\n/g) || []).length;
        if(line == max_line){
            line -= 1;
        }

        var regex_model = '^((?:[^\\n]*\\n){@line})([^\\n]{@column})([^\\n]?)([^\\n]*)((?:\\n.*)*)$';
        regex_model = regex_model.replace('@line', line);
        regex_model = regex_model.replace('@column', column);
        var regex = new RegExp(regex_model);

        matches = text.match(regex);

        formatted_text = matches[1];
        formatted_text += '<span class="error-line">';
        formatted_text += matches[2];
        formatted_text += '<span class="error-char">';
        formatted_text += matches[3];
        formatted_text += '</span>';
        formatted_text += matches[4];
        formatted_text += '</span>';
        formatted_text += matches[5];

        return formatted_text;
    },
    update_markup: function(song) {
        var id = song.dataset.id;
        var background_song = ChordProEditor.background_songs[id]

        var raw_text = ChordProEditor.clean_newlines(song.value);

        var parsed_text;
        try {
            parsed_text = ChordProEditor.peg.parse(raw_text);
        } catch (exception) {
            parsed_text = ChordProEditor.insert_exception_markup(exception, raw_text);
        }
        parsed_text = ChordProEditor.clean_formatted_newlines(parsed_text);

        background_song.innerHTML = parsed_text;
    },


    //load grammar file
    grammar_file: "js/grammar.txt",
    load_grammar: function(){
        this.load_file(this.grammar_file, this.parse_grammar);
    },
    parse_grammar: function(text){
        this.peg = PEG.buildParser(text);
        this.initialize_markups(this.songs);
        this.prevent_chord_overlapping();
    },
{'fraction_non_alphanumeric': 0.13544572129867233, 'fraction_numerical': 0.0033470936070512107, 'mean_word_length': 2.449018853405156, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, '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': '3998599', 'n_tokens_mistral': 2782, 'n_tokens_neox': 2688, 'n_words': 469}