<commit_before>package com.gitlab.artismarti.tinbo.timer

import com.gitlab.artismarti.tinbo.Notification
import com.gitlab.artismarti.tinbo.config.Default
import org.fusesource.jansi.Ansi
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.shell.core.CommandMarker
import org.springframework.shell.core.JLineShellComponent
import org.springframework.shell.core.annotation.CliCommand
import org.springframework.shell.core.annotation.CliOption
import org.springframework.stereotype.Component
import java.util.concurrent.CompletableFuture
import java.util.logging.Level

/**
 * Commands with that users can interact in timer mode.
 *
 * @author artur
 */
@Component
class TimerCommands @Autowired constructor(val shell: JLineShellComponent) : CommandMarker {

    private var currentTimer = Timer.INVALID
    private var running = false

    @Suppress("unused")
    @CliCommand(value = "start", help = "Starts the timer and waits for you to type 'stop' to finish it if no arguments are specified. " +
            "Parameters '--minutes | --mins | --m' and '--seconds | --secs | --s' can be used to specify how long the timer should run.")
    fun startTimer(@CliOption(key = arrayOf("minutes", "m", "mins"), unspecifiedDefaultValue = "0", help = "Duration of timer in minutes.") mins: Int,
                   @CliOption(key = arrayOf("seconds", "s", "mins"), unspecifiedDefaultValue = "0", help = "Duration of timer in seconds.") seconds: Int,
                   @CliOption(key = arrayOf("bg", "background"), unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") bg: Boolean,
                   @CliOption(key = arrayOf("name", "n"), unspecifiedDefaultValue = Default.MAIN_CATEGORY_NAME,
                           specifiedDefaultValue = Default.MAIN_CATEGORY_NAME) name: String) {

        if (inputsAreInvalid(mins, seconds)) {
            shell.flash(Level.WARNING, "Invalid parameters: minutes and seconds have to be positiv and seconds not bigger than 59.\n", "inputs")
            return;
        }

        if (currentTimer.isInvalid()) {
            running = true
            val mode = specifyTimerMode(bg)
            CompletableFuture.runAsync {
                startPrintingTime(Timer(mode, name, stopDateTime = Timer.calcStopTime(mins, seconds)))
            }
        } else {
            shell.flash(Level.FINE, "Other timer already in process. Stop the timer before starting a new one.\n", "id")
        }
    }

    private fun specifyTimerMode(bg: Boolean): TimerMode {
        if (bg) return TimerMode.BACKGROUND
        else return TimerMode.DEFAULT
    }

    private fun inputsAreInvalid(mins: Int, seconds: Int): Boolean {
        return !(mins >= 0 && seconds >= 0 && seconds < 60)
    }

    @Suppress("unused")
    @CliCommand(value = "stop", help = "Stops the timer.")
    fun stopTimer() {
        internalStop()
    }

    @Suppress("unused")
    @CliCommand(value = "q", help = "Stops the timer.")
    fun stopTimerWithQ() {
        internalStop()
    }

    private fun internalStop() {
        if (!currentTimer.isInvalid()) {
            running = false
            saveAndResetCurrentTimer()
        } else {
            shell.flash(Level.FINE, "Other timer already in process. Stop the timer before starting a new one.", "id")
        }
    }

    private fun saveAndResetCurrentTimer() {
        notify()
        currentTimer = Timer.INVALID
    }

    private fun notify() {
        Notification.finished(currentTimer.toString())
    }

    private fun startPrintingTime(timer: Timer) {
        currentTimer = timer
        while (running) {
            if (currentTimer.timerMode == TimerMode.DEFAULT)
                printInfo("\rElapsed time: $timer")
            if (currentTimer.isFinished())
                internalStop()
            Thread.sleep(1000L)
        }
    }

    fun printInfo(message: String) {
        print(Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.WHITE).a(message).reset())
    }


}
<commit_msg>Combine timer data holder with timer commands and save new timer entries<commit_after>package com.gitlab.artismarti.tinbo.timer

import com.gitlab.artismarti.tinbo.Notification
import com.gitlab.artismarti.tinbo.config.Default
import org.fusesource.jansi.Ansi
import org.springframework.shell.core.CommandMarker
import org.springframework.shell.core.annotation.CliCommand
import org.springframework.shell.core.annotation.CliOption
import org.springframework.stereotype.Component
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.CompletableFuture

/**
 * Commands with that users can interact in timer mode.
 *
 * @author artur
 */
@Component
class TimerCommands(val timerDataHolder: TimerDataHolder = Injekt.get()) : CommandMarker {

    private var currentTimer = Timer.INVALID
    private var running = false

    @CliCommand(value = "list")
    fun listData(): String {
        return timerDataHolder.data.toString()
    }

    @Suppress("unused")
    @CliCommand(value = "start", help = "Starts the timer and waits for you to type 'stop' to finish it if no arguments are specified. " +
            "Parameters '--minutes | --mins | --m' and '--seconds | --secs | --s' can be used to specify how long the timer should run.")
    fun startTimer(@CliOption(key = arrayOf("minutes", "m", "mins"), unspecifiedDefaultValue = "0", help = "Duration of timer in minutes.") mins: Int,
                   @CliOption(key = arrayOf("seconds", "s", "mins"), unspecifiedDefaultValue = "0", help = "Duration of timer in seconds.") seconds: Int,
                   @CliOption(key = arrayOf("bg", "background"), unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") bg: Boolean,
                   @CliOption(key = arrayOf("name", "n"), unspecifiedDefaultValue = Default.MAIN_CATEGORY_NAME,
                           specifiedDefaultValue = Default.MAIN_CATEGORY_NAME) name: String) {

        if (inputsAreInvalid(mins, seconds)) {
            printlnInfo("Invalid parameters: minutes and seconds have to be positiv and seconds not bigger than 59.")
            return;
        }

        if (currentTimer.isInvalid()) {
            running = true
            val mode = specifyTimerMode(bg)
            CompletableFuture.runAsync {
                startPrintingTime(Timer(mode, name, stopDateTime = Timer.calcStopTime(mins, seconds)))
            }
        } else {
            printlnInfo("Other timer already in process. Stop the timer before starting a new one.")
        }
    }

    private fun specifyTimerMode(bg: Boolean): TimerMode {
        if (bg) return TimerMode.BACKGROUND
        else return TimerMode.DEFAULT
    }

    private fun inputsAreInvalid(mins: Int, seconds: Int): Boolean {
        return !(mins >= 0 && seconds >= 0 && seconds < 60)
    }

    @Suppress("unused")
    @CliCommand(value = "stop", help = "Stops the timer.")
    fun stopTimer() {
        internalStop()
    }

    @Suppress("unused")
    @CliCommand(value = "q", help = "Stops the timer.")
    fun stopTimerWithQ() {
        internalStop()
    }

    private fun internalStop() {
        if (!currentTimer.isInvalid()) {
            running = false
            saveAndResetCurrentTimer()
        } else {
            printlnInfo("Other timer already in process. Stop the timer before starting a new one.")
        }
    }

    private fun saveAndResetCurrentTimer() {
        notify()
        timerDataHolder.persistEntry(currentTimer.name, TimerEntry())
        currentTimer = Timer.INVALID
    }

    private fun notify() {
        Notification.finished(currentTimer.toString())
    }

    private fun startPrintingTime(timer: Timer) {
        currentTimer = timer
        while (running) {
            if (currentTimer.timerMode == TimerMode.DEFAULT)
                printInfo("\rElapsed time: $timer")
            if (currentTimer.isFinished())
                internalStop()
            Thread.sleep(1000L)
        }
    }

    fun printInfo(message: String) {
        print(Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.WHITE).a(message).reset())
    }

    fun printlnInfo(message: String) {
        printInfo(message + "\n")
    }
}

{'fraction_non_alphanumeric': 0.11067724222086638, 'fraction_numerical': 0.0029286150091519217, 'mean_word_length': 2.7170068027210883, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '3402246', 'n_tokens_mistral': 2342, 'n_tokens_neox': 2230, 'n_words': 598}