summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/interpreter/Completion.scala
blob: dc544ed657b341068ba6231c93222470091b34de (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
                            
                                

                        
 






                                                                                         

                                                                               

                                                                                
 

                       

              
                   
                                  
 



















































                                                                                                              
   
 



                                            
 

                     
 

                                                                            
 
        
   
 

                                        
 
                                                 

                                                      
                                              
                                                                           
 
                                                

                                                                                         
                                            
                                           
 

                                                                 
   
 
/* NSC -- new Scala compiler
 * Copyright 2005-2010 LAMP/EPFL
 * @author Paul Phillips
 */

//
// TODO, if practical:
//
// 1) Types: val s: String = x.<tab> should only show members which result in a String.
//      Possible approach: evaluate buffer as if current identifier is
// 2) Implicits: x.<tab> should show not only x's members but those of anything for which
//      there is an implicit conversion from x.
// 4) Imports: after import scala.collection.mutable._, HashMap should be among
//      my top level identifiers.
// 5) Caching: parsing the jars every startup seems wasteful, but experimentally
//      there is little to no gain from caching.

package scala.tools.nsc
package interpreter

import jline._
import java.net.URL
import java.util.{ List => JList }

// REPL completor - queries supplied interpreter for valid
// completions based on current contents of buffer.
class Completion(repl: Interpreter) extends Completor {
  private def asURLs(xs: List[String]) = xs map (x => io.File(x).toURL)
  private def classPath = (
    // compiler jars, scala-library.jar etc.
    (repl.compilerClasspath) :::
    // boot classpath, java.lang.* etc.
    (asURLs(repl.settings.bootclasspath.value split ':' toList))
  )

  // the unqualified vals/defs/etc visible in the repl
  val ids = new IdentCompletion(repl)
  // the top level packages we know about
  val pkgs = new PackageCompletion(classPath)

  // TODO - restore top level availability of scala.* java.lang.* scala.Predef
  // Old code:
  //
  // def membersOfPredef() = membersOfId("scala.Predef")
  //
  // def javaLangToHide(s: String) = (
  //   (s endsWith "Exception") ||
  //   (s endsWith "Error") ||
  //   (s endsWith "Impl") ||
  //   (s startsWith "CharacterData") ||
  //   !existsAndPublic("java.lang." + s)
  // )
  //
  // def scalaToHide(s: String) =
  //   (List("Tuple", "Product", "Function") exists (x => (x + """\d+""").r findPrefixMatchOf s isDefined)) ||
  //   (List("Exception", "Error") exists (s endsWith _))
  //
  // import reflect.Modifier.{ isPrivate, isProtected, isPublic, isStatic }
  // private def isSingleton(x: Int, isJava: Boolean) = !isJava || isStatic(x)
  // private def existsAndPublic(s: String): Boolean =
  //   (dottedPaths containsKey s) || {
  //     val clazz =
  //       try Class.forName(s)
  //       catch { case _: ClassNotFoundException | _: SecurityException => return false }
  //
  //     isPublic(clazz.getModifiers)
  //   }

  // the high level analysis
  def analyze(_buffer: String, clist: JList[String]): Int = {
    val parsed = new Parsed(_buffer)
    import parsed._

    val candidates = List(ids, pkgs) flatMap (_ completionsFor buffer)
    candidates foreach (clist add _)
    position
  }

  // chasing down results which won't parse
  def execute(line: String): Option[Any] = {
    val parsed = new Parsed(line)
    import parsed._

    if (!isQualified)
      return None

    for (topLevel <- List(ids, pkgs) ; exec <- topLevel executionFor buffer)
      return Some(exec)

    None
  }

  // override if history is available
  def lastCommand: Option[String] = None

  // For recording the buffer on the last tab hit
  private var lastTab: (String, String) = (null, null)

  // Does this represent two consecutive tabs?
  def isConsecutiveTabs(buf: String) = (buf, lastCommand orNull) == lastTab

  // This is jline's entry point for completion.
  override def complete(_buffer: String, cursor: Int, candidates: JList[String]): Int = {
    // println("_buffer = %s, cursor = %d".format(_buffer, cursor))
    val verbose = isConsecutiveTabs(_buffer)
    lastTab = (_buffer, lastCommand orNull)

    // modify the buffer in place and returns the cursor position
    analyze(_buffer, candidates)
  }
}