Skip to content

Instantly share code, notes, and snippets.

@Duhemm
Created February 16, 2016 13:41
Show Gist options
  • Save Duhemm/2748118c3f2e697b4691 to your computer and use it in GitHub Desktop.
Save Duhemm/2748118c3f2e697b4691 to your computer and use it in GitHub Desktop.
package hijack
import sbt._
import Keys._
import sbt.complete.DefaultParsers._
object HijackShellPlugin extends AutoPlugin {
override def requires = sbt.plugins.JvmPlugin
override def trigger = allRequirements
override def buildSettings =
Seq(
commands += hijackShell,
onLoad in Global := {
val previous = (onLoad in Global).value
((s: State) => Hijack :: s) compose previous
}
)
private val Hijack = "hijack"
private def hijackShell =
Command.command(Hijack) { s => s.copy(definedCommands = s.definedCommands ++ Seq(hijackedShell)) }
private def getAllPluginKeys(plugins: DetectedPlugins): Seq[Def.Setting[_]] = {
val autoPlugins: Seq[AutoPlugin] = plugins.autoPlugins.map(_.value)
val nonAutoPlugins: Seq[Plugin] = plugins.plugins.values
val allAuto: Seq[Def.Setting[_]] = autoPlugins.flatMap { p =>
p.buildSettings ++ p.globalSettings ++ p.projectSettings
}
val allNonAuto: Seq[Def.Setting[_]] = nonAutoPlugins.flatMap { p =>
p.buildSettings ++ p.globalSettings ++ p.projectSettings
}
allAuto ++ allNonAuto
}
// Adapted from BasicCommands.scala
private def hijackedShell = Command.command(BasicCommandStrings.Shell) { s =>
val extracted = Project.extract(s)
val nonPluginKeys = BuiltinCommands.allTaskAndSettingKeys(s).map((k: AttributeKey[_]) => k.label).toSet
val keys: Iterable[String] =
for {
unit <- extracted.structure.units.values
key <- getAllPluginKeys(unit.unit.plugins.detected)
if (!nonPluginKeys.contains(key.key.key.label))
} yield key.key.key.label
val parser = token(OpOrID.examples(keys.toSeq: _*))
import BasicKeys._
val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
val prompt = (s get shellPrompt) match { case Some(pf) => pf(s); case None => "hijacked> " }
val reader = new FullReader(history, Command.combine(s.definedCommands)(s) | parser)
val line = reader.readLine(prompt)
line match {
case Some(line) =>
val newState = s.copy(onFailure = Some(BasicCommandStrings.Shell), remainingCommands = line +: BasicCommandStrings.Shell +: s.remainingCommands).setInteractive(true)
if (line.trim.isEmpty) newState else newState.clearGlobalLog
case None => s.setInteractive(false)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment