diff options
-rw-r--r-- | build.xml | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/util/BashCompletion.scala | 132 |
3 files changed, 146 insertions, 5 deletions
@@ -873,8 +873,14 @@ PACKED QUICK BUILD (PACK) <chmod perm="ugo+rx" file="${build-pack.dir}/bin/scalap"/> <touch file="${build-pack.dir}/bin.complete" verbose="no"/> </target> + + <target name="pack.etc" depends="pack.bin" unless="pack.bin.available" > + <exec executable="${build-pack.dir}/bin/scala" output="${build-pack.dir}/etc/scala_completion.sh" failifexecutionfails="false" > + <arg line="scala.tools.util.BashCompletion" /> + </exec> + </target> - <target name="pack.done" depends="pack.bin"> + <target name="pack.done" depends="pack.etc"> <path id="pack.classpath"> <pathelement location="${build-pack.dir}/lib/scala-library.jar"/> <pathelement location="${build-pack.dir}/lib/scala-compiler.jar"/> diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 0590797e53..4e14ec6fb1 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -549,13 +549,16 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable /* The set of phase objects that is the basis for the compiler phase chain */ protected val phasesSet : HashSet[SubComponent] = new HashSet[SubComponent] - /** A description of the phases that will run */ - def phaseDescriptions: String = { + /** The names of the phases. */ + lazy val phaseNames = { new Run // force some initialization - - phaseDescriptors map (_.phaseName) mkString "\n" // todo: + " - " + phase.description + phaseDescriptors map (_.phaseName) } + /** A description of the phases that will run */ + def phaseDescriptions: String = + phaseNames mkString "\n" // todo: + " - " + phase.description + // ----------- Runs --------------------------------------- private var curRun: Run = null diff --git a/src/compiler/scala/tools/util/BashCompletion.scala b/src/compiler/scala/tools/util/BashCompletion.scala new file mode 100644 index 0000000000..bb36326b7e --- /dev/null +++ b/src/compiler/scala/tools/util/BashCompletion.scala @@ -0,0 +1,132 @@ +/* NSC -- new Scala compiler + * Copyright 2006-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package util + +import nsc.{ Global, Settings } +import Settings._ + +/** Examines Settings and generates a bash completion file + * containing both bells and whistles. + */ +object BashCompletion { + val completionTemplate = """ +# Bash Scala completion +# +# Add this file to /etc/bash_completion.d/ (or your local equivalent) +# or place a line like this in your .bashrc or .profile: +# +# . /path/to/file/scala_completion.sh +# +# For more information, see: +# +# http://bash-completion.alioth.debian.org/ +# +# This file is generated by running scala.tools.util.BashCompletion. +# + +SCALA_PHASES="@@PHASES@@" +SCALA_PHASE_SETTINGS=( @@PHASE_SETTINGS@@ ) +SCALA_OPTIONS="@@OPTIONS@@" +SCALA_OPTIONS_EXPANDED="@@OPTIONS_EXPANDED@@" + +_scala_completion() +{ + local cur prev opts colonprefixes + + COMPREPLY=() + opts="" + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + colonprefixes=${cur%"${cur##*:}"} + + # special case escaping madness because bash treats : as a separator. + case "${cur}" in + -*:*) + precolon=$(echo "${cur}" | sed 's/:.*//g') + + for p in ${SCALA_PHASE_SETTINGS[@]}; do + if [[ "${precolon}" == "${p}" ]] ; then + cur=$(echo "${cur}" | sed 's/.*://g') # cut cur down to postcolon part + opts=${SCALA_PHASES} + fi + done + + if [ "${opts}" == "" ] ; then + opts=${SCALA_OPTIONS_EXPANDED} + fi + ;; + esac + + if [ "${opts}" == "" ] ; then + opts=${SCALA_OPTIONS} + fi + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + + local i=${#COMPREPLY[*]} + while [ $((--i)) -ge 0 ]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} + done + + return 0 +} + +_scala_commands() +{ +@@PROGRAMS@@ +} +_scala_commands + """.trim + + private lazy val settings = new Settings() + + val phaseNames = "all" :: (new Global(settings) phaseNames) + val phaseSettings = settings.visibleSettings partialMap { case x: PhasesSetting => "\"" + x.name + "\"" } + + def settingStrings(s: Setting, expanded: Boolean) = s match { + case x: ChoiceSetting => if (expanded) x.choices map (x.name + ":" + _) else List(x.name + ":") + case x: PhasesSetting => List(x.name + ":") + case x => List(x.name) + } + + /** We embed one list which stops at : and another where all choice settings are expanded out + * to include the choices. + */ + def settingNames = settings.visibleSettings.toList flatMap (x => settingStrings(x, false)) sorted + def settingNamesExpanded = settings.visibleSettings.toList flatMap (x => settingStrings(x, true)) sorted + + def commandForName(name: String) = " complete -o default -F _scala_completion " + name + "\n" + def interpolate(template: String, what: (String, String)*) = + what.foldLeft(template) { + case (text, (key, value)) => + val token = "@@" + key + "@@" + + (text indexOf token) match { + case -1 => error("Token '%s' does not exist." format token) + case idx => (text take idx) + value + (text drop idx drop token.length) + } + } + + def create(cmds: List[String]) = { + interpolate(completionTemplate, + "PROGRAMS" -> (cmds map commandForName mkString ""), + "OPTIONS" -> (settingNames mkString " "), + "OPTIONS_EXPANDED" -> (settingNamesExpanded mkString " "), + "PHASES" -> (phaseNames mkString " "), + "PHASE_SETTINGS" -> (phaseSettings mkString " ") + ) + } + + def main(args: Array[String]): Unit = { + val commands = if (args.isEmpty) List("fsc", "scala", "scalac", "scaladoc") else args.toList + val result = create(commands) + if (result contains "@@") + error("Some tokens were not replaced: text is " + result) + + println(result) + } +}
\ No newline at end of file |