Skip to content

Commit

Permalink
Wire up import suggestions call. Need to get full qualified names, an…
Browse files Browse the repository at this point in the history
…d need to search all names known to project (not just in project sources).
  • Loading branch information
aemoncannon committed Oct 15, 2010
1 parent 33d8192 commit 64b758d
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 54 deletions.
10 changes: 9 additions & 1 deletion src/main/elisp/ensime.el
Expand Up @@ -57,7 +57,7 @@
(require 'apropos)
(require 'compile))

(defgroup ensime nil
(defgroup ensime nil
"Interaction with the ENhanced Scala Environment."
:group 'tools)

Expand Down Expand Up @@ -2320,6 +2320,14 @@ with the current project's dependencies loaded. Returns a property list."
,(or prefix "")
,is-constructor)))

(defun ensime-rpc-import-suggestions-at-point (names)
(ensime-eval
`(swank:import-suggestions
,buffer-file-name
,(ensime-computed-point)
,names
)))

(defun ensime-rpc-members-for-type-at-point (&optional prefix)
(ensime-eval
`(swank:type-completion
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/org/ensime/model/Model.scala
Expand Up @@ -20,6 +20,8 @@ case class SymbolInfoLight(
val tpeId: Int,
val isCallable: Boolean) {}

case class ImportSuggestions(symLists: Iterable[Iterable[SymbolInfoLight]])

class NamedTypeMemberInfo(override val name: String, val tpe: TypeInfo, val pos: Position, val declaredAs: scala.Symbol) extends EntityInfo(name, List()) {}

class NamedTypeMemberInfoLight(override val name: String, val tpeSig: String, val tpeId: Int, val isCallable: Boolean) extends EntityInfo(name, List()) {}
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/org/ensime/protocol/Protocol.scala
Expand Up @@ -183,6 +183,7 @@ trait ProtocolConversions{
def toWF(value:CallCompletionInfo):WireFormat
def toWF(value:InterfaceInfo):WireFormat
def toWF(value:TypeInspectInfo):WireFormat
def toWF(value:ImportSuggestions):WireFormat

def toWF(value:RefactorFailure):WireFormat
def toWF(value:RefactorEffect):WireFormat
Expand Down
12 changes: 12 additions & 0 deletions src/main/scala/org/ensime/protocol/SwankProtocol.scala
Expand Up @@ -233,6 +233,14 @@ trait SwankProtocol extends Protocol {
case _ => oops
}
}
case "swank:import-suggestions" => {
form match {
case SExpList(head :: StringAtom(file) :: IntAtom(point) :: SExpList(names) :: body) => {
rpcTarget.rpcImportSuggestions(file, point, names.map(_.toString).toList, callId)
}
case _ => oops
}
}
case "swank:package-member-completion" => {
form match {
case SExpList(head :: StringAtom(path) :: StringAtom(prefix) :: body) => {
Expand Down Expand Up @@ -624,6 +632,10 @@ trait SwankProtocol extends Protocol {
(":touched-files", SExpList(value.touched.map(f => strToSExp(f.getAbsolutePath)))))
}

def toWF(value: ImportSuggestions): SExp = {
SExpList(value.symLists.map { l => SExpList(l.map(toWF)) })
}

def toWF(value: Undo): SExp = {
SExp.propList(
(":id", value.id),
Expand Down
29 changes: 17 additions & 12 deletions src/main/scala/org/ensime/server/Analyzer.scala
Expand Up @@ -113,27 +113,30 @@ class Analyzer(val project: Project, val protocol: ProtocolConversions, val conf

case ScopeCompletionReq(file: File, point: Int,
prefix: String, constructor: Boolean) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val syms = scalaCompiler.askCompleteSymbolAt(p, prefix, constructor)
project ! RPCResultEvent(toWF(syms.map(toWF)), callId)
}

case TypeCompletionReq(file: File, point: Int, prefix: String) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val members = scalaCompiler.askCompleteMemberAt(p, prefix)
project ! RPCResultEvent(toWF(members.map(toWF)), callId)
}

case ImportSuggestionsReq(file: File, point: Int, names: List[String]) => {
val p = pos(file, point)
val suggestions = scalaCompiler.askImportSuggestions(p, names)
project ! RPCResultEvent(toWF(suggestions), callId)
}

case PackageMemberCompletionReq(path: String, prefix: String) => {
val members = scalaCompiler.askCompletePackageMember(path, prefix)
project ! RPCResultEvent(toWF(members.map(toWF)), callId)
}

case InspectTypeReq(file: File, point: Int) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val result = scalaCompiler.askInspectTypeAt(p) match {
case Some(info) => toWF(info)
case None => toWF(null)
Expand All @@ -150,8 +153,7 @@ class Analyzer(val project: Project, val protocol: ProtocolConversions, val conf
}

case SymbolAtPointReq(file: File, point: Int) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val result = scalaCompiler.askSymbolInfoAt(p) match {
case Some(info) => toWF(info)
case None => toWF(null)
Expand All @@ -168,8 +170,7 @@ class Analyzer(val project: Project, val protocol: ProtocolConversions, val conf
}

case TypeAtPointReq(file: File, point: Int) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val result = scalaCompiler.askTypeInfoAt(p) match {
case Some(info) => toWF(info)
case None => toWF(null)
Expand All @@ -194,8 +195,7 @@ class Analyzer(val project: Project, val protocol: ProtocolConversions, val conf
}

case TypeByNameAtPointReq(name: String, file: File, point: Int) => {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
val p = new OffsetPosition(f, point)
val p = pos(file, point)
val result = scalaCompiler.askTypeInfoByNameAt(name, p) match {
case Some(info) => toWF(info)
case None => toWF(null)
Expand Down Expand Up @@ -233,6 +233,11 @@ class Analyzer(val project: Project, val protocol: ProtocolConversions, val conf
}
}

def pos(file: File, offset: Int) = {
val f = scalaCompiler.sourceFileForPath(file.getAbsolutePath())
new OffsetPosition(f, offset)
}

override def finalize() {
System.out.println("Finalizing Analyzer actor.")
}
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/org/ensime/server/Project.scala
Expand Up @@ -25,6 +25,7 @@ case class ReloadAllReq()
case class RemoveFileReq(file: File)
case class ScopeCompletionReq(file: File, point: Int, prefix: String, constructor: Boolean)
case class TypeCompletionReq(file: File, point: Int, prefix: String)
case class ImportSuggestionsReq(file: File, point: Int, names:List[String])
case class PackageMemberCompletionReq(path: String, prefix: String)
case class SymbolAtPointReq(file: File, point: Int)
case class InspectTypeReq(file: File, point: Int)
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/org/ensime/server/RPCTarget.scala
Expand Up @@ -138,6 +138,10 @@ trait RPCTarget { self: Project =>
analyzer ! RPCRequestEvent(CallCompletionReq(id), callId)
}

def rpcImportSuggestions(f: String, point: Int, names: List[String], callId: Int) {
analyzer ! RPCRequestEvent(ImportSuggestionsReq(new File(f), point, names), callId)
}

def rpcTypeAtPoint(f: String, point: Int, callId: Int) {
analyzer ! RPCRequestEvent(TypeAtPointReq(new File(f), point), callId)
}
Expand Down
105 changes: 64 additions & 41 deletions src/main/scala/org/ensime/server/RichPresentationCompiler.scala
Expand Up @@ -9,6 +9,7 @@ import scala.tools.nsc.interactive.{ Global, CompilerControl }
import scala.tools.nsc.reporters.{ Reporter }
import scala.tools.nsc.symtab.{ Flags, Types }
import scala.tools.nsc.util.{ SourceFile, Position }
import scala.tools.refactoring.analysis.GlobalIndexes
import java.io.File

trait RichCompilerControl extends CompilerControl with RefactoringInterface { self: RichPresentationCompiler =>
Expand Down Expand Up @@ -76,27 +77,31 @@ trait RichCompilerControl extends CompilerControl with RefactoringInterface { se
}, t => None)

def askInspectTypeAt(p: Position): Option[TypeInspectInfo] = askOr({
reloadSources(List(p.source))
inspectTypeAt(p)
}, t => None)
reloadSources(List(p.source))
inspectTypeAt(p)
}, t => None)

def askCompletePackageMember(path: String, prefix: String): Iterable[PackageMemberInfoLight] = askOr({
completePackageMember(path, prefix)
}, t => List())
completePackageMember(path, prefix)
}, t => List())

def askCompleteSymbolAt(p: Position, prefix: String, constructor: Boolean): List[SymbolInfoLight] = askOr({
reloadSources(List(p.source))
completeSymbolAt(p, prefix, constructor)
}, t => List())
reloadSources(List(p.source))
completeSymbolAt(p, prefix, constructor)
}, t => List())

def askCompleteMemberAt(p: Position, prefix: String): List[NamedTypeMemberInfoLight] = askOr({
reloadSources(List(p.source))
completeMemberAt(p, prefix)
}, t => List())
reloadSources(List(p.source))
completeMemberAt(p, prefix)
}, t => List())

def askReloadAndTypeFiles(files: Iterable[SourceFile]) = askOr({
reloadAndTypeFiles(files)
}, t => ())
reloadAndTypeFiles(files)
}, t => ())

def askImportSuggestions(p: Position, names: Iterable[String]): ImportSuggestions = askOr({
ImportSuggestions(symbolSuggestions(names))
}, t => ImportSuggestions(List()))

def askClearTypeCache() = clearTypeCache

Expand All @@ -109,7 +114,8 @@ class RichPresentationCompiler(
reporter: Reporter,
var parent: Actor,
val config: ProjectConfig) extends Global(settings, reporter)
with ModelBuilders with RichCompilerControl with RefactoringImpl {
with ModelBuilders with RichCompilerControl with RefactoringImpl {


import Helpers._

Expand All @@ -126,8 +132,8 @@ class RichPresentationCompiler(
members(sym) = m
} catch {
case e =>
System.err.println("Error: Omitting member " + sym
+ ": " + e)
System.err.println("Error: Omitting member " + sym
+ ": " + e)
}
}
for (sym <- tpe.decls) {
Expand Down Expand Up @@ -179,8 +185,7 @@ class RichPresentationCompiler(
new TypeInspectInfo(
TypeInfo(tpe),
companionTypeOf(tpe).map(cacheType),
prepareSortedInterfaceInfo(typePublicMembers(tpe.asInstanceOf[Type]))
)
prepareSortedInterfaceInfo(typePublicMembers(tpe.asInstanceOf[Type])))
}

protected def inspectTypeAt(p: Position): Option[TypeInspectInfo] = {
Expand All @@ -189,9 +194,9 @@ class RichPresentationCompiler(
typeAt(p) match {
case Left(t) => {
Some(new TypeInspectInfo(
TypeInfo(t),
companionTypeOf(t).map(cacheType),
preparedMembers))
TypeInfo(t),
companionTypeOf(t).map(cacheType),
preparedMembers))
}
case Right(_) => None
}
Expand Down Expand Up @@ -222,9 +227,9 @@ class RichPresentationCompiler(
}

/*
* Fall back to full typecheck if targeted fails
* Removing this wrapper causes completion test failures.
*/
* Fall back to full typecheck if targeted fails
* Removing this wrapper causes completion test failures.
*/
def persistentTypedTreeAt(p: Position): Tree = {
try {

Expand All @@ -239,11 +244,11 @@ class RichPresentationCompiler(

} catch {
case e: FatalError =>
{
println("typedTreeAt threw FatalError: " + e + ", falling back to typedTree... ")
typedTree(p.source, true)
locateTree(p)
}
{
println("typedTreeAt threw FatalError: " + e + ", falling back to typedTree... ")
typedTree(p.source, true)
locateTree(p)
}
}
}

Expand Down Expand Up @@ -299,10 +304,10 @@ class RichPresentationCompiler(
}

/**
* Override scopeMembers to fix issues with finding method params
* and occasional exception in pre.memberType. Hopefully we can
* get these changes into Scala.
*/
* Override scopeMembers to fix issues with finding method params
* and occasional exception in pre.memberType. Hopefully we can
* get these changes into Scala.
*/
def scopeMembers(pos: Position, prefix: String, exactMatch: Boolean): List[ScopeMember] = {
persistentTypedTreeAt(pos) // to make sure context is entered
locateContext(pos) match {
Expand All @@ -312,7 +317,7 @@ class RichPresentationCompiler(
val ns = sym.nameString
val accessible = context.isAccessible(sym, pre, false)
if (accessible && ((exactMatch && ns == prefix)
|| (!exactMatch && ns.startsWith(prefix))) &&
|| (!exactMatch && ns.startsWith(prefix))) &&
!sym.nameString.contains("$") &&
!locals.contains(sym)) {
try {
Expand Down Expand Up @@ -343,7 +348,7 @@ class RichPresentationCompiler(
for (imp <- context.imports) {
val pre = imp.qual.tpe
val importedSyms = pre.members.flatMap(transformImport(
imp.tree.selectors, _))
imp.tree.selectors, _))
for (sym <- importedSyms) {
addSymbol(sym, pre, imp.qual)
}
Expand All @@ -363,8 +368,8 @@ class RichPresentationCompiler(
case List() => List()
case List(ImportSelector(nme.WILDCARD, _, _, _)) => List(sym)
case ImportSelector(from, _, to, _) :: _ if (from.toString == sym.name.toString) =>
if (to == nme.WILDCARD) List()
else { val sym1 = sym.cloneSymbol; sym1.name = to; List(sym1) }
if (to == nme.WILDCARD) List()
else { val sym1 = sym.cloneSymbol; sym1.name = to; List(sym1) }
case _ :: rest => transformImport(rest, sym)
}

Expand Down Expand Up @@ -422,17 +427,35 @@ class RichPresentationCompiler(
visibleMembers
}

protected def symbolSuggestions(names: Iterable[String]): Iterable[Iterable[SymbolInfoLight]] = {
val gi = new GlobalIndexes{
val global = RichPresentationCompiler.this
val cuIndexes = this.global.unitOfFile.values.map { u =>
CompilationUnitIndex(u.body) }
val index = GlobalIndex(cuIndexes.toList)
val result = names.map{ n =>
index.allDeclarations.keys.flatMap{d =>
if(d.nameString.contains(n)) Some(
SymbolInfoLight(d.asInstanceOf[RichPresentationCompiler.this.Symbol]))
else None
}
}
}
gi.result
}


/**
* Override so we send a notification to compiler actor when finished..
*/
* Override so we send a notification to compiler actor when finished..
*/
override def recompile(units: List[RichCompilationUnit]) {
super.recompile(units)
parent ! FullTypeCheckCompleteEvent()
}

/**
* Overriding for debug purposes..
*/
* Overriding for debug purposes..
*/
override def parse(unit: RichCompilationUnit): Unit = {
// System.err.println("DEBUG PARSE TRACE\n---------------------\n")
// (new RuntimeException()).printStackTrace(System.err);
Expand Down

0 comments on commit 64b758d

Please sign in to comment.