content: package tern.swing.rsyntaxtextarea.samples;
  
  import java.awt.Point;
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.swing.JOptionPane;
  import javax.swing.text.BadLocationException;
  import javax.swing.text.JTextComponent;
  
  import org.fife.ui.autocomplete.AbstractCompletionProvider;
  import org.fife.ui.autocomplete.BasicCompletion;
  import org.fife.ui.autocomplete.Completion;
  import org.fife.ui.autocomplete.CompletionCellRenderer;
  import org.fife.ui.autocomplete.CompletionProvider;
  import org.fife.ui.autocomplete.FunctionCompletion;
  import org.fife.ui.autocomplete.ParameterizedCompletion;
  import org.fife.ui.autocomplete.VariableCompletion;
  
  import tern.TernException;
  import tern.server.ITernServer;
  import tern.server.protocol.IJSONObjectHelper;
  import tern.server.protocol.TernDoc;
  import tern.server.protocol.completions.ITernCompletionCollector;
  import tern.server.protocol.completions.TernCompletionItem;
  import tern.server.protocol.completions.TernCompletionProposalRec;
  import tern.server.protocol.completions.TernCompletionsQuery;
  
  public class JavaScriptCompletionProvider extends AbstractCompletionProvider {
  
  	private String prefix;
  	private ITernServer server;
  	private List<Completion> _completions;
  
  	public JavaScriptCompletionProvider(ITernServer server) {
  		this.server = server;
  		setAutoActivationRules(true, ".");
  		setParameterizedCompletionParams('(', ",", ')');
  		setListCellRenderer(new CompletionCellRenderer());
  	}
  
  	@Override
  	public String getAlreadyEnteredText(JTextComponent comp) {
  		computeCompletions(comp);
  		return prefix == null ? "" : prefix;
  	}
  
  	@Override
  	public List<Completion> getCompletions(JTextComponent comp) {
  		return getCompletionsAtOffset(comp, comp.getCaretPosition());
  	}
  
  	@Override
  	public List<Completion> getCompletionsAt(JTextComponent comp, Point p) {
  		return null;
  	}
  
  	private List<Completion> getCompletionsAtOffset(JTextComponent comp, int offset) {
  		return _completions;
  	}
  
  	@Override
  	public List<ParameterizedCompletion> getParameterizedCompletions(JTextComponent tc) {
  		// TODO: is this better?
  		return new ArrayList<>();
  	}
  
  	private void computeCompletions(JTextComponent comp) {
  		_completions = new ArrayList<>();
  
  		prefix = null;
  
  		int offset = comp.getCaretPosition();
  
  		if (offset < 0 || offset > comp.getDocument().getLength()) {
  			return;
  		}
  
  		queryCompletions(comp, new ITernCompletionCollector() {
  
  			@Override
  			public void addProposal(TernCompletionProposalRec proposal, Object completion,
  					IJSONObjectHelper jsonManager) {
  
  				TernCompletionItem serverCompl = new TernCompletionItem(proposal);
  
  				JavaScriptCompletionProvider provider = JavaScriptCompletionProvider.this;
  
  				if (prefix == null) {
  					try {
  						prefix = comp.getDocument().getText(proposal.start, proposal.end - proposal.start);
  					} catch (BadLocationException e) {
  						e.printStackTrace();
  						JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  					}
  				}
  
  				BasicCompletion compl;
  				if (serverCompl.isFunction()) {
  					FunctionCompletion func = new JavaScriptFunctionCompletion(provider, serverCompl);
  					compl = func;
  				} else {
  					String type = serverCompl.getJsType();
  					for (char c : type.toCharArray()) {
  						if (!Character.isJavaIdentifierPart(c)) {
  							type = "Object";
  							break;
  						}
  					}
  					VariableCompletion var = new VariableCompletion(provider, serverCompl.getName(), type);
  					compl = var;
  				}
  				compl.setRelevance(0);
  				compl.setShortDescription(serverCompl.getDoc());
  				compl.setSummary(serverCompl.getDoc());
  				_completions.add(compl);
  			}
  		});
  	}
  
  	private void queryCompletions(JTextComponent comp, ITernCompletionCollector collector) {
  		int offset = comp.getCaretPosition();
  		String content = comp.getText();
  
  		String filename = "source.js";
  		TernCompletionsQuery query = new TernCompletionsQuery(filename, Integer.valueOf(offset));
  		query.setDocs(true);
  		query.setTypes(true);
  		query.setGuess(false);
  		query.setCaseInsensitive(false);
  		query.setOrigins(false);
  		query.setUrls(false);
  
  		// query.set("sort", false);
  		// query.set("includeKeywords", true);
  
  		TernDoc doc = new TernDoc(query);
  		doc.addFile(filename, content, null, null);
  		try {
  			server.request(doc, collector);
  		} catch (TernException e) {
  			e.printStackTrace();
  			JOptionPane.showMessageDialog(null, e.getMessage(), "Tern", JOptionPane.INFORMATION_MESSAGE);
  		}
  	}
  
  	static class JavaScriptFunctionCompletion extends FunctionCompletion {
  
  		private TernCompletionItem _serverCompl;
  
  		public JavaScriptFunctionCompletion(CompletionProvider provider, TernCompletionItem serverCompl) {
  			super(provider, serverCompl.getName(), serverCompl.getJsType());
  			_serverCompl = serverCompl;
  
  			List<Parameter> list = new ArrayList<>();
  			List<tern.server.protocol.completions.Parameter> params = serverCompl.getParameters();
  			if (params != null) {
  				for (tern.server.protocol.completions.Parameter param : params) {
  					Parameter complParam = new Parameter(param.getType(), param.getName());
  					list.add(complParam);
  				}
  			}
  			setParams(list);
  		}
  
  		@Override
  		public String getShortDescription() {
  			return _serverCompl.getDoc();
  		}
  
  		@Override
  		public String getDefinitionString() {
  			return _serverCompl.getText();
  		}
  
  		@Override
  		public String getReplacementText() {
  			return _serverCompl.getName();
  		}
  	}
  }
  