<commit_before>package com.redmadrobot.inputmask.helper

import com.redmadrobot.inputmask.model.CaretString
import com.redmadrobot.inputmask.model.Next
import com.redmadrobot.inputmask.model.State
import com.redmadrobot.inputmask.model.state.*

/**
 * ### Mask
 *
 * Iterates over user input. Creates formatted strings from it. Extracts value specified by mask
 * format.
 *
 * Provided mask format string is translated by the ```Compiler``` class into a set of states, which
 * define the formatting and value extraction.
 *
 * @see ```Compiler```, ```State``` and ```CaretString``` classes.
 *
 * @author taflanidi
 */
class Mask(format: String) {

    /**
     * ### Result
     *
     * The end result of mask application to the user input string.
     */
    class Result(formattedText: CaretString, extractedValue: String) {
        val formattedText: CaretString
        val extractedValue: String

        init {
            this.formattedText = formattedText
            this.extractedValue = extractedValue
        }
    }

    private val initialState: State

    /**
     * Constructor.
     *
     * @param format mask format.
     *
     * @returns Initialized ```Mask``` instance.
     *
     * @throws ```FormatError``` if format string is incorrect.
     */
    init {
        this.initialState = Compiler().compile(format)
    }

    /**
     * Apply mask to the user input string.
     *
     * @param toText user input string with current cursor position
     *
     * @returns Formatted text with extracted value an adjusted cursor position.
     */
    fun apply(text: CaretString, autocomplete: Boolean): Result {
        val iterator: CaretStringIterator = CaretStringIterator(text)

        var extractedValue: String = ""
        var modifiedString: String = ""
        var modifiedCaretPosition: Int = text.caretPosition

        var state: State = this.initialState
        var beforeCaret: Boolean = iterator.beforeCaret()
        var character: Char? = iterator.next()

        while (null != character) {
            val next: Next? = state.accept(character)
            if (null != next) {
                state = next.state
                modifiedString += next.insert ?: ""
                extractedValue += next.value ?: ""
                if (next.pass) {
                    beforeCaret = iterator.beforeCaret()
                    character = iterator.next()
                } else {
                    if (beforeCaret && null != next.insert) {
                        modifiedCaretPosition += 1
                    }
                }
            } else {
                if (beforeCaret) {
                    modifiedCaretPosition -= 1
                }
                beforeCaret = iterator.beforeCaret()
                character = iterator.next()
            }
        }

        while (autocomplete && beforeCaret) {
            val next: Next? = state.autocomplete()
            if (null == next) break
            state = next.state
            modifiedString += if (null != next.insert) next.insert else ""
            extractedValue += if (null != next.value) next.value else ""<commit_msg>Fix for edge case, when cursor is at the end of the line.<commit_after>package com.redmadrobot.inputmask.helper

import com.redmadrobot.inputmask.model.CaretString
import com.redmadrobot.inputmask.model.Next
import com.redmadrobot.inputmask.model.State
import com.redmadrobot.inputmask.model.state.*

/**
 * ### Mask
 *
 * Iterates over user input. Creates formatted strings from it. Extracts value specified by mask
 * format.
 *
 * Provided mask format string is translated by the ```Compiler``` class into a set of states, which
 * define the formatting and value extraction.
 *
 * @see ```Compiler```, ```State``` and ```CaretString``` classes.
 *
 * @author taflanidi
 */
class Mask(format: String) {

    /**
     * ### Result
     *
     * The end result of mask application to the user input string.
     */
    class Result(formattedText: CaretString, extractedValue: String) {
        val formattedText: CaretString
        val extractedValue: String

        init {
            this.formattedText = formattedText
            this.extractedValue = extractedValue
        }
    }

    private val initialState: State

    /**
     * Constructor.
     *
     * @param format mask format.
     *
     * @returns Initialized ```Mask``` instance.
     *
     * @throws ```FormatError``` if format string is incorrect.
     */
    init {
        this.initialState = Compiler().compile(format)
    }

    /**
     * Apply mask to the user input string.
     *
     * @param toText user input string with current cursor position
     *
     * @returns Formatted text with extracted value an adjusted cursor position.
     */
    fun apply(text: CaretString, autocomplete: Boolean): Result {
        val iterator: CaretStringIterator = CaretStringIterator(text)

        var extractedValue: String = ""
        var modifiedString: String = ""
        var modifiedCaretPosition: Int = text.caretPosition

        var state: State = this.initialState
        var beforeCaret: Boolean = iterator.beforeCaret()
        var character: Char? = iterator.next()

        while (null != character) {
            val next: Next? = state.accept(character)
            if (null != next) {
                state = next.state
                modifiedString += next.insert ?: ""
                extractedValue += next.value ?: ""
                if (next.pass) {
                    beforeCaret = iterator.beforeCaret()
                    character = iterator.next()
                } else {
                    if (beforeCaret && null != next.insert) {
                        modifiedCaretPosition += 1
                    }
                }
            } else {
                if (iterator.beforeCaret()) {
                    modifiedCaretPosition -= 1
                }
                beforeCaret = iterator.beforeCaret()
                character = iterator.next()
            }
        }

        while (autocomplete && beforeCaret) {
            val next: Next? = state.autocomplete()
            if (null == next) break
            state = next.state
            modifiedString += if (null != next.insert) next.insert else ""
            extractedValue += if (null != next.value) next.value else ""
{'fraction_non_alphanumeric': 0.09891150023663038, 'fraction_numerical': 0.0006310143555765894, 'mean_word_length': 1.917625402669121, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '1890315', 'n_tokens_mistral': 1662, 'n_tokens_neox': 1601, 'n_words': 474}