/*******************************************************************************
* Copyright (c) 2008, 2017 xored software, Inc. and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.tcl.internal.ui.text.completion;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.tcl.core.TclNature;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.documentation.ScriptDocumentationAccess;
import org.eclipse.dltk.ui.text.completion.HTMLPrinter;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationExtension;
import org.eclipse.swt.graphics.Image;
public class TclKeywordLazyContextInformation
implements IContextInformation, IContextInformationExtension {
private final ICompletionProposal proposal;
private final String target;
private final ISourceModule module;
private boolean informationComputed = false;
private String information;
/**
* @param iSourceModule
* @param completionProposal
* @since 2.0
*/
public TclKeywordLazyContextInformation(ICompletionProposal proposal,
String target, ISourceModule module) {
this.proposal = proposal;
this.target = removeColons(target);
this.module = module;
}
/**
* @param target2
* @return
*/
private static String removeColons(String s) {
int i = 0;
while (i < s.length() && s.charAt(i) == ':') {
++i;
}
return s.substring(i);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContextInformation#
* getContextDisplayString()
*/
@Override
public String getContextDisplayString() {
return proposal.getDisplayString();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.contentassist.IContextInformation#getImage()
*/
@Override
public Image getImage() {
return null;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContextInformation#
* getInformationDisplayString()
*/
@Override
public String getInformationDisplayString() {
if (!informationComputed) {
informationComputed = true;
information = computeInformation();
}
return information;
}
/**
* Returns all the documentation for this keyword
*
* @return
*/
private String getInfo() {
try {
final Reader reader = ScriptDocumentationAccess
.getKeywordDocumentation(TclNature.NATURE_ID, module,
target);
if (reader != null) {
return HTMLPrinter.read(reader);
}
} catch (ModelException e) {
DLTKUIPlugin.log(e);
}
return null;
}
/**
* @return
*/
private String computeInformation() {
final String content = getInfo();
if (content == null) {
return proposal.getDisplayString();
}
final Matcher matcher = HEADER.matcher(content);
int start = -1;
while (matcher.find()) {
if (start < 0) {
if (matcher.group(1).toUpperCase().indexOf(SYNOPSIS) >= 0) {
start = matcher.end();
}
} else {
return formatSynopsis(
content.substring(start, matcher.start()));
}
}
return proposal.getDisplayString();
}
/**
* @param synopsis
* @return
*/
private String formatSynopsis(String synopsis) {
synopsis = CUT_HTML_TAGS.matcher(synopsis).replaceAll(EMPTY);
final String[] parts = EOL.split(synopsis);
final String keyword = target;
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < parts.length; ++i) {
final String part = parts[i].trim();
if (part.length() != 0 && part.startsWith(keyword)) {
if (sb.length() != 0) {
sb.append('\n');
}
sb.append(part);
}
}
if (sb.length() == 0) {
for (int i = 0; i < parts.length; ++i) {
final String part = parts[i].trim();
if (part.length() != 0) {
if (sb.length() != 0) {
sb.append('\n');
}
sb.append(part);
}
}
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TclKeywordLazyContextInformation) {
final TclKeywordLazyContextInformation other = (TclKeywordLazyContextInformation) obj;
final String displayString = proposal.getDisplayString();
if (displayString != null) {
if (!displayString.equals(other.proposal.getDisplayString())) {
return false;
}
} else {
if (other.proposal.getDisplayString() != null) {
return false;
}
}
return getContextInformationPosition() == other
.getContextInformationPosition();
}
return false;
}
/*
* @see IContextInformationExtension#getContextInformationPosition()
*/
@Override
public int getContextInformationPosition() {
if (proposal instanceof ICompletionProposalExtension) {
return ((ICompletionProposalExtension) proposal)
.getContextInformationPosition();
}
return -1;
}
private static final String EMPTY = ""; //$NON-NLS-1$
private static final Pattern EOL = Pattern.compile("[\r\n]+"); //$NON-NLS-1$
private static final Pattern HEADER = Pattern.compile("<h\\d>(.*?)</h\\d>", //$NON-NLS-1$
Pattern.CASE_INSENSITIVE);
private static final String SYNOPSIS = "SYNOPSIS"; //$NON-NLS-1$
private static final Pattern CUT_HTML_TAGS = Pattern.compile("<[^>]+>"); //$NON-NLS-1$
}