All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.interactive.InteractiveSamples.kt Maven / Gradle / Ivy

There is a newer version: 0.0.88
Show newest version
package pl.mareklangiewicz.interactive

import pl.mareklangiewicz.annotations.*
import pl.mareklangiewicz.bad.*
import pl.mareklangiewicz.kground.io.*
import pl.mareklangiewicz.kommand.*
import pl.mareklangiewicz.kommand.samples.*
import pl.mareklangiewicz.ulog.*
import pl.mareklangiewicz.ure.*
import pl.mareklangiewicz.ureflect.*
import pl.mareklangiewicz.usubmit.*
import pl.mareklangiewicz.usubmit.xd.*


/**
 * @param reference Either "xclip", or reference in format like from IntelliJ:CopyReference action.
 *   For example, "pl.mareklangiewicz.kommand.demo.MyDemoSamples#getBtop"
 */
@NotPortableApi
@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun tryInteractivelySomethingRef(reference: String = "xclip") {
  val log = implictx()
  log.i("tryInteractivelySomethingRef(\"$reference\")")
  val ref = if (reference == "xclip")
    xclipOut(XClipSelection.Clipboard).ax().singleOrNull()
      ?: bad { "Clipboard has to have code reference in single line." }
  else reference
  val ure = ure {
    +ure("className") {
      +chWordFirst
      1..MAX of chWordOrDot
      +chWord
    }
    +ch('#')
    +ureIdent().withName("methodName")
  }
  val result = ure.matchEntireOrThrow(ref)
  val className by result.namedValues
  val methodName by result.namedValues
  tryInteractivelyClassMember(className!!, methodName!!)
}

@NotPortableApi
@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun tryInteractivelyClassMember(className: String, memberName: String) {
  val log = implictx()
  log.i("tryInteractivelyClassMember(\"$className\", \"$memberName\")")
  val call = getReflectCallOrNull(className, memberName) ?: return
  // Note: prepareCallFor fails early if member not found,
  // before we start to interact with the user,
  // but the code is never called without confirmation.
  ifInteractiveCodeEnabled {
    val submit = implictx()
    submit.askIf("Call member $memberName\nfrom class $className?") || return
    val member: Any? = call()
    // Note: call() will either already "do the thing" (when the member is just a fun to call)
    //  or it will only get the property (like ReducedScript/Sample etc.) which will be tried (or not) later.
    member.tryInteractivelyAnything()
  }
}


@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun Any?.tryInteractivelyAnything() = when (this) {
  is Sample -> tryInteractivelyCheckSample()
  is Kommand -> toInteractiveCheck().ax()
  is ReducedSample<*> -> tryInteractivelyCheckReducedSample() // Note: ReducedSample is also ReducedScript
  is ReducedScript<*> -> tryInteractivelyCheckReducedScript()
  else -> tryOpenDataInIDEOrGVim()
}


@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun Sample.tryInteractivelyCheckSample() =
  kommand.toInteractiveCheck(expectedLineRaw).ax()

@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun ReducedSample<*>.tryInteractivelyCheckReducedSample() {
  reducedKommand.lineRawOrNull() chkEq expectedLineRaw // so also if both are nulls it's treated as fine.
  tryInteractivelyCheckReducedScript("Exec ReducedSample ?")
}

@DelicateApi("API for manual interactive experimentation. Conditionally skips")
suspend fun ReducedScript<*>.tryInteractivelyCheckReducedScript(
  question: String = "Exec ReducedScript ?",
) {
  val submit = implictx()
  submit.askIf(question) || return
  val reducedOut = ax()
  reducedOut.tryOpenDataInIDEOrGVim("Open ReducedOut: ${reducedOut.about} in tmp.notes in IDE (if running) or in GVim ?")
}

@DelicateApi("API for manual interactive experimentation. Conditionally skips")
/** @param question null means default question */
suspend fun Any?.tryOpenDataInIDEOrGVim(question: String? = null): Any {
  val log = implictx()
  val fs = implictx()
  val submit = implictx()
  return when {
    this == null -> log.i("It is null. Nothing to open.")
    this is Unit -> log.i("It is Unit. Nothing to open.")
    this is Int && this in 0..10 -> log.i("It is small Int: $this. Nothing to open.")
    this is Long && this in 0..10 -> log.i("It is small Long: $this. Nothing to open.")
    this is Boolean -> log.i("It is Boolean: $this. Nothing to open.")
    this is String && isEmpty() -> log.i("It is empty string. Nothing to open.")
    this is Collection<*> && isEmpty() -> log.i("It is empty collection. Nothing to open.")
    !submit.askIf(question ?: "Open $about in tmp.notes in IDE (if running) or in GVim ?") -> log.i("Not opening.")
    else -> {
      val lines = if (this is Collection<*>) map { it.toString() } else toString().lines()
      val notes = fs.pathToTmpNotes.toString() // FIXME_later: use Path type everywhere
      writeFileWithDD(lines, notes).ax()
      ideOrGVimOpen(notes).ax()
    }
  }
}

private val Any?.about: String
  get() = when (this) {
    null -> "null"
    Unit -> "Unit"
    is Number -> this::class.simpleName + ":$this"
    is Collection<*> -> this::class.simpleName + "(size:$size)"
    is CharSequence ->
      if (length < 20) this::class.simpleName + ": \"$this\""
      else this::class.simpleName + "(length:$length)"
    else -> this::class.simpleName ?: "???"
  }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy