<commit_before>/*
 * Copyright (c) 2015-2016 <NAME> <<EMAIL>>
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.vladsch.smart

import java.util.*

/**
 * markdown table formatter
 *
 * spacePadPipes:Boolean - true to put spaces before and after | characters
 * discretionaryAlignMarker:Int - -1 to always remove, 0 to leave as is, 1 to always add
 */
class MarkdownTableFormatter(val settings: MarkdownTableFormatSettings) {

    constructor() : this(MarkdownTableFormatSettings())

    private var myAlignmentDataPoints: List<SmartVersionedDataAlias<TextAlignment>> = listOf()
    private var myColumnWidthDataPoints: List<SmartVersionedDataAlias<Int>> = listOf()
    //    private val myRowColumns: ArrayList<List<SmartCharSequence>> = ArrayList()
    //    private val myRows: ArrayList<SmartCharSequence> = ArrayList()

    val columnCount: Int get() = myColumnWidthDataPoints.size

    fun columnWidth(index: Int): Int {
        return myColumnWidthDataPoints[index].value
    }

    fun columnAlignmentDataPoint(index: Int): TextAlignment {
        return myAlignmentDataPoints[index].value
    }

    fun formatTable(table: SmartCharSequence): SmartCharSequence {
        return formatTable(table, -1, CharWidthProvider.UNITY_PROVIDER)
    }

    //    val rows: Int get() = myRows.size
    //
    //    fun rowSequence(index: Int): SmartCharSequence {
    //        return myRows[index]
    //    }
    //
    //    fun rowColumns(index: Int): List<SmartCharSequence> {
    //        return myRowColumns[index]
    //    }

    fun formatTable(tableChars: SmartCharSequence, caretOffset: Int, charWidthProvider: CharWidthProvider): SmartCharSequence {
        val table = parseTable(tableChars, caretOffset, !settings.TABLE_ADJUST_COLUMN_WIDTH && settings.TABLE_TRIM_CELLS)

        if (settings.TABLE_FILL_MISSING_COLUMNS) {
            val unbalancedTable = table.minColumns != table.maxColumns
            if (unbalancedTable) table.fillMissingColumns(null)
        }

        return formatTable(table, table.indentPrefix, charWidthProvider)
    }

    fun formatTable(markdownTable: MarkdownTable, indentPrefix: CharSequence = EMPTY_SEQUENCE, charWidthProvider: CharWidthProvider): SmartCharSequence {
        val tableBalancer = SmartTableColumnBalancer(charWidthProvider)
        var formattedTable = EditableCharSequence()

        val pipeSequence = RepeatedCharSequence('|')
        val endOfLine = RepeatedCharSequence('\n')
        val space = RepeatedCharSequence(' ')
        val pipePadding = if (settings.TABLE_SPACE_AROUND_PIPE) space else EMPTY_SEQUENCE // or empty if don't want padding around pipes
        val alignMarker = RepeatedCharSequence(':')
        var rowColumns = ArrayList<SmartCharSequence>()

        var row = 0
        val addLeadTrailPipes = settings.TABLE_LEAD_TRAIL_PIPES || !indentPrefix.isEmpty() || markdownTable.minColumns < 2

        for (tableRow in markdownTable.rows) {
            var formattedRow = EditableCharSequence()

            if (addLeadTrailPipes) {
                formattedRow.append(indentPrefix, pipeSequence)
            } else {
                formattedRow.append(indentPrefix)
            }

            val segments = tableRow.rowCells
            var colIndex = 0
            var col = 0
            var lastSpan = 1
            var lastColumnEmpty = false

            while (colIndex < segments.size) {
                val tableCell = segments[colIndex]
                var columnChars:SmartCharSequence = SmartCharSequenceWrapper(tableCell.charSequence)

                if (settings.TABLE_TRIM_CELLS) columnChars = columnChars.trim()
                if (columnChars.isEmpty()) columnChars = columnChars.append(space)

                val separatorParts = if (row == markdownTable.separatorRow) columnChars.extractGroupsSegmented(SEPARATOR_COLUMN_PATTERN) else null
                assert(row != markdownTable.separatorRow || separatorParts != null, { "isSeparator but column does not match separator col" })

                val formattedCol: SmartVariableCharSequence

                if (separatorParts != null) {
                    val haveLeft = separatorParts.segments[2] != NULL_SEQUENCE
                    val haveRight = separatorParts.segments[4] != NULL_SEQUENCE

                    formattedCol = SmartVariableCharSequence(columnChars, SmartRepeatedCharSequence('-', 3 - haveLeft.ifElse(1, 0) - haveRight.ifElse(1, 0)), charWidthProvider)

                    formattedCol.leftPadChar = '-'
                    formattedCol.rightPadChar = '-'
                    when {
                        haveLeft && haveRight -> {
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) tableBalancer.alignment(colIndex, SmartImmutableData(TextAlignment.CENTER))
                            formattedCol.prefix = alignMarker
                            formattedCol.suffix = alignMarker
                        }
                        haveRight -> {
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) tableBalancer.alignment(colIndex, SmartImmutableData(TextAlignment.RIGHT))
                            formattedCol.suffix = alignMarker
                        }
                        else -> {
                            // when no alignment given use centered for header cells and left for body
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) tableBalancer.alignment(colIndex, SmartImmutableData(if (!haveLeft) TextAlignment.DEFAULT else TextAlignment.LEFT))
                            if (settings.TABLE_LEFT_ALIGN_MARKER == 1 || settings.TABLE_LEFT_ALIGN_MARKER == 0 && haveLeft) formattedCol.prefix = alignMarker
                        }
                    }<commit_msg>rework code style and app settings<commit_after>/*
 * Copyright (c) 2015-2016 <NAME> <<EMAIL>>
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.vladsch.smart

import java.util.*

/**
 * markdown table formatter
 *
 * spacePadPipes:Boolean - true to put spaces before and after | characters
 * discretionaryAlignMarker:Int - -1 to always remove, 0 to leave as is, 1 to always add
 */
class MarkdownTableFormatter(val settings: MarkdownTableFormatSettings) {

    constructor() : this(MarkdownTableFormatSettings())

    private var myAlignmentDataPoints: List<SmartVersionedDataAlias<TextAlignment>> = listOf()
    private var myColumnWidthDataPoints: List<SmartVersionedDataAlias<Int>> = listOf()
    //    private val myRowColumns: ArrayList<List<SmartCharSequence>> = ArrayList()
    //    private val myRows: ArrayList<SmartCharSequence> = ArrayList()

    val columnCount: Int get() = myColumnWidthDataPoints.size

    fun columnWidth(index: Int): Int {
        return myColumnWidthDataPoints[index].value
    }

    fun columnAlignmentDataPoint(index: Int): TextAlignment {
        return myAlignmentDataPoints[index].value
    }

    fun formatTable(table: SmartCharSequence): SmartCharSequence {
        return formatTable(table, -1, CharWidthProvider.UNITY_PROVIDER)
    }

    //    val rows: Int get() = myRows.size
    //
    //    fun rowSequence(index: Int): SmartCharSequence {
    //        return myRows[index]
    //    }
    //
    //    fun rowColumns(index: Int): List<SmartCharSequence> {
    //        return myRowColumns[index]
    //    }

    fun formatTable(tableChars: SmartCharSequence, caretOffset: Int, charWidthProvider: CharWidthProvider): SmartCharSequence {
        val table = parseTable(tableChars, caretOffset, !settings.TABLE_ADJUST_COLUMN_WIDTH && settings.TABLE_TRIM_CELLS)

        if (settings.TABLE_FILL_MISSING_COLUMNS) {
            val unbalancedTable = table.minColumns != table.maxColumns
            if (unbalancedTable) table.fillMissingColumns(null)
        }

        return formatTable(table, table.indentPrefix, charWidthProvider)
    }

    fun formatTable(markdownTable: MarkdownTable, indentPrefix: CharSequence = EMPTY_SEQUENCE, charWidthProvider: CharWidthProvider): SmartCharSequence {
        val tableBalancer = SmartTableColumnBalancer(charWidthProvider)
        var formattedTable = EditableCharSequence()

        val pipeSequence = RepeatedCharSequence('|')
        val endOfLine = RepeatedCharSequence('\n')
        val space = RepeatedCharSequence(' ')
        val pipePadding = if (settings.TABLE_SPACE_AROUND_PIPE) space else EMPTY_SEQUENCE // or empty if don't want padding around pipes
        val alignMarker = RepeatedCharSequence(':')
        var rowColumns = ArrayList<SmartCharSequence>()

        var row = 0
        val addLeadTrailPipes = settings.TABLE_LEAD_TRAIL_PIPES || !indentPrefix.isEmpty() || markdownTable.minColumns < 2

        for (tableRow in markdownTable.rows) {
            var formattedRow = EditableCharSequence()

            if (addLeadTrailPipes) {
                formattedRow.append(indentPrefix, pipeSequence)
            } else {
                formattedRow.append(indentPrefix)
            }

            val segments = tableRow.rowCells
            var colIndex = 0
            var col = 0
            var lastSpan = 1
            var lastColumnEmpty = false

            while (colIndex < segments.size) {
                val tableCell = segments[colIndex]
                var columnChars:SmartCharSequence = SmartCharSequenceWrapper(tableCell.charSequence)

                if (settings.TABLE_TRIM_CELLS) columnChars = columnChars.trim()
                if (columnChars.isEmpty()) columnChars = columnChars.append(space)

                val separatorParts = if (row == markdownTable.separatorRow) columnChars.extractGroupsSegmented(SEPARATOR_COLUMN_PATTERN) else null
                assert(row != markdownTable.separatorRow || separatorParts != null, { "isSeparator but column does not match separator col" })

                val formattedCol: SmartVariableCharSequence

                if (separatorParts != null) {
                    val haveLeft = separatorParts.segments[2] != NULL_SEQUENCE
                    val haveRight = separatorParts.segments[4] != NULL_SEQUENCE

                    formattedCol = SmartVariableCharSequence(columnChars, SmartRepeatedCharSequence('-', 3 - haveLeft.ifElse(1, 0) - haveRight.ifElse(1, 0)), charWidthProvider)

                    formattedCol.leftPadChar = '-'
                    formattedCol.rightPadChar = '-'
                    when {
                        haveLeft && haveRight -> {
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) tableBalancer.alignment(colIndex, SmartImmutableData(TextAlignment.CENTER))
                            formattedCol.prefix = alignMarker
                            formattedCol.suffix = alignMarker
                        }
                        haveRight -> {
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) tableBalancer.alignment(colIndex, SmartImmutableData(TextAlignment.RIGHT))
                            formattedCol.suffix = alignMarker
                        }
                        else -> {
                            // when no alignment given use centered for header cells and left for body
                            if (settings.TABLE_APPLY_COLUMN_ALIGNMENT) {
                                val tableHeadingDefaultAlignment = !haveLeft && settings.TABLE_LEFT_ALIGN_MARKER != 1 || haveLeft && !haveRight && settings.TABLE_LEFT_ALIGN_MARKER == -1
                                tableBalancer.alignment(colIndex, SmartImmutableData(if (tableHeadingDefaultAlignment) TextAlignment.DEFAULT else TextAlignment.LEFT))
                            }
                            if (settings.TABLE_LEFT_ALIGN_MARKER == 1 || settings.TABLE_LEFT_ALIGN_MARKER == 0 && haveLeft) formattedCol.prefix = alignMarker
                        }
                    }
{'fraction_non_alphanumeric': 0.0778898254063817, 'fraction_numerical': 0.004665863937387116, 'mean_word_length': 2.5165387668695423, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3825742', 'n_tokens_mistral': 3498, 'n_tokens_neox': 3295, 'n_words': 884}