Skip to content

Commit

Permalink
Added public symbol search function
Browse files Browse the repository at this point in the history
  • Loading branch information
djspiewak committed Sep 23, 2011
1 parent 1835d06 commit 422b767
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/main/resources/actions.xml
Expand Up @@ -36,4 +36,9 @@
com.codecommit.es.EnsimePlugin.suggestImports(view);
</CODE>
</ACTION>
<ACTION NAME="ensime.symbol-search">
<CODE>
com.codecommit.es.EnsimePlugin.symbolSearch(view);
</CODE>
</ACTION>
</ACTIONS>
7 changes: 5 additions & 2 deletions src/main/resources/plugin.props
Expand Up @@ -12,15 +12,18 @@ options.ensime.code=new com.codecommit.es.ui.EnsimeOptionPane();
plugin.com.codecommit.es.EnsimePlugin.menu=ensime \
ensime.kill \
- \
ensime.inspect-type \
ensime.jump-to-declaration \
ensime.symbol-search \
- \
ensime.inspect-type \
ensime.expand-selection \
ensime.suggest-imports
options.menu.label=ENSIME
ensime.label=Initialize Project
ensime.kill.label=Kill Server for Project
ensime.inspect-type.label=Inspect Type
ensime.jump-to-declaration.label=Jump to Declaration
ensime.symbol-search.label=Public Symbol Search
ensime.inspect-type.label=Inspect Type
ensime.expand-selection.label=Expand Selection
ensime.suggest-imports.label=Suggest Imports

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/codecommit/es/EnsimeParser.scala
Expand Up @@ -31,7 +31,7 @@ class EnsimeParser extends SideKickParser("ensime") {
}

signal synchronized {
signal.wait(5000)
signal.wait(500)
}

if (finalResults != null) {
Expand Down
31 changes: 31 additions & 0 deletions src/main/scala/com/codecommit/es/EnsimePlugin.scala
Expand Up @@ -314,6 +314,37 @@ object EnsimePlugin {
}
}

def symbolSearch(view: View) {
val buffer = view.getBuffer
for (inst <- instanceForBuffer(buffer)) {
val dialog = new ui.SymbolSearchDialog(view, inst.Ensime.publicSymbolSearch)

for ((file, offset) <- dialog.open() if offset >= 0) {
EventQueue.invokeLater(new Runnable {
def run() {
type Navigator = { def addToHistory() }
type NavigatorPlugin = { def getNavigator(view: View): Navigator }

val navPlugin = Option(JEdit.getPlugin("ise.plugin.nav.NavigatorPlugin")) map { _.asInstanceOf[NavigatorPlugin] }
navPlugin foreach { _.getNavigator(view).addToHistory() }

val buffer = JEdit.openFile(view, file)
val pane = view.goToBuffer(buffer)
val area = pane.getTextArea

EventQueue.invokeLater(new Runnable {
def run() {
area.setCaretPosition(offset)

navPlugin foreach { _.getNavigator(view).addToHistory() }
}
})
}
})
}
}
}

private def instanceForBuffer(buffer: Buffer) =
parentDirs(new File(buffer.getPath)) flatMap instances.get headOption

Expand Down
Expand Up @@ -270,6 +270,36 @@ trait EnsimeProtocolComponent extends BackendComponent {
dispatchSwank(id, SExp(key("swank:import-suggestions"), file, point, SExpList(names map StringAtom), maxResults))
}

def publicSymbolSearch(names: List[String], maxResults: Int)(callback: List[(String, String, Int)] => Unit) {
val id = callId()

registerReturn(id) {
case SExpList(results) => {
val back = results collect {
case result: SExpList => {
val map = result.toKeywordMap

if (map.contains(key(":name")) && map.contains(key(":pos"))) {
val StringAtom(name) = map(key(":name"))

val pos = map(key(":pos")).asInstanceOf[SExpList].toKeywordMap
val StringAtom(file) = pos(key(":file"))
val IntAtom(offset) = pos(key(":offset"))

Some((name, file, offset))
} else {
None
}
}
}

callback(back.flatten.toList)
}
}

dispatchSwank(id, SExp(key("swank:public-symbol-search"), SExpList(names map StringAtom), maxResults))
}

private def dispatchSwank(id: Int, sexp: SExp) {
Backend.send(SExp(key(":swank-rpc"), sexp, id).toWireString)
}
Expand Down Expand Up @@ -297,6 +327,7 @@ trait EnsimeProtocolComponent extends BackendComponent {
def symbolAtPoint(file: String, offset: Int)(callback: Option[Location] => Unit)
def expandSelection(file: String, start: Int, end: Int)(callback: (Int, Int) => Unit)
def importSuggestions(file: String, point: Int, names: List[String], maxResults: Int)(callback: List[String] => Unit)
def publicSymbolSearch(names: List[String], maxResults: Int)(callback: List[(String, String, Int)] => Unit)
}
}

Expand Down
106 changes: 106 additions & 0 deletions src/main/scala/com/codecommit/es/ui/SymbolSearchDialog.scala
@@ -0,0 +1,106 @@
package com.codecommit
package es
package ui

import com.codecommit.es.client.EnsimeProtocolComponent
import java.awt.EventQueue
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import javax.swing.JTextField
import javax.swing.{JButton, JDialog, JFrame, JLabel, JList, JPanel, JScrollPane, ListSelectionModel, WindowConstants}

import java.awt.{BorderLayout, FlowLayout}
import java.awt.event.{ActionEvent, ActionListener}

class SymbolSearchDialog(parent: JFrame, publicSymbolSearch: (List[String], Int) => (List[(String, String, Int)] => Unit) => Unit) extends JDialog(parent, "Public Symbol Search", true) {
private var selected: Option[(String, Int)] = None
private var data = Vector[(String, Int)]()

{
getContentPane.setLayout(new BorderLayout)

val names = new JTextField
getContentPane.add(names, BorderLayout.NORTH)

val list = new JList
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
// list.setSelectionInterval(0, 0)
getContentPane.add(new JScrollPane(list))

names.addKeyListener(new KeyListener {
var hasOutstanding = false
var queryNames: Option[List[String]] = None

def keyPressed(e: KeyEvent) {
if (e.getKeyCode == KeyEvent.VK_ESCAPE) {
dispose()
} else if (e.getKeyCode == KeyEvent.VK_ENTER) {
selected = if (data.isEmpty) {
None
} else {
if (list.getSelectedIndex < 0)
data.headOption
else
Some(data(list.getSelectedIndex))
}

dispose()
} else if (e.getKeyCode == KeyEvent.VK_UP) {
if (list.getSelectedIndex > 0) {
list.setSelectedIndex(list.getSelectedIndex - 1)
}
e.consume()
} else if (e.getKeyCode == KeyEvent.VK_DOWN) {
if (list.getSelectedIndex < data.length - 1) {
list.setSelectedIndex(list.getSelectedIndex + 1)
}
e.consume()
}
}

def keyReleased(e: KeyEvent) {
}

def keyTyped(e: KeyEvent) {
queryNames = Some(names.getText split " " toList)
if (!hasOutstanding) {
requestCompletion()
}
}

private def requestCompletion() {
for (tokens <- queryNames) {
hasOutstanding = true
queryNames = None

publicSymbolSearch(tokens, 50) { results =>
val names2 = results map { case (n, _, _) => n }
val data2 = results map { case (_, f, o) => (f, o) }

EventQueue.invokeLater(new Runnable {
def run() {
data = Vector(data2: _*)
list.setListData(names2.toArray.asInstanceOf[Array[AnyRef]])
}
})

hasOutstanding = false
requestCompletion()
}
}
}
})

setSize(400, 400)

val screen = getToolkit.getScreenSize
setLocation((screen.width - getWidth) / 2, (screen.height - getHeight) / 2)

setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
}

def open() = {
setVisible(true)
selected
}
}

0 comments on commit 422b767

Please sign in to comment.