blob: d617f23b3e7fc52052b47460e11fe9a84ab79f81 [file] [log] [blame]
/*******************************************************************************
* 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.ruby.internal.ui.text.hyperlink;
import org.eclipse.dltk.ruby.core.RubyConstants;
import org.eclipse.dltk.ruby.core.RubyPlugin;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* {@link IHyperlinkDetector} implementation to navigate over require
* statements.
*/
public class RubyRequireHyperlinkDetector extends AbstractHyperlinkDetector {
@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer,
IRegion inputRegion, boolean canShowMultipleHyperlinks) {
if (inputRegion == null || textViewer == null) {
return null;
}
try {
final IDocument doc = textViewer.getDocument();
final int lineNumber = doc.getLineOfOffset(inputRegion.getOffset());
final IRegion region = doc.getLineInformation(lineNumber);
final String line = doc.get(region.getOffset(), region.getLength());
if (line != null && line.length() != 0) {
final IHyperlink link = checkLine(region.getOffset(), line);
if (link != null) {
return new IHyperlink[] { link };
}
}
} catch (BadLocationException e) {
if (RubyPlugin.DUMP_EXCEPTIONS_TO_CONSOLE) {
e.printStackTrace();
}
}
return null;
}
/**
* Checks if the specified line matches the <code>require</code> statement
*
* @param offset
* @param line
* @return
*/
public IHyperlink checkLine(int offset, final String line) {
int begin = 0;
int end = line.length();
while (begin < end && Character.isWhitespace(line.charAt(begin))) {
++begin;
}
while (begin < end && Character.isWhitespace(line.charAt(end - 1))) {
--end;
}
if (begin + RubyConstants.REQUIRE.length() < end
&& line.startsWith(RubyConstants.REQUIRE, begin)) {
begin += RubyConstants.REQUIRE.length();
while (begin < end && Character.isWhitespace(line.charAt(begin))) {
++begin;
}
if (begin + 2 < end && line.charAt(begin) == '('
&& line.charAt(end - 1) == ')') {
++begin;
--end;
while (begin < end
&& Character.isWhitespace(line.charAt(begin))) {
++begin;
}
while (begin < end
&& Character.isWhitespace(line.charAt(end - 1))) {
--end;
}
}
if (begin + 2 < end) {
final char quote = line.charAt(begin);
if ((quote == '\'' || quote == '"')
&& line.charAt(end - 1) == quote) {
++begin;
--end;
return createLink(offset, line, begin, end);
}
}
}
return null;
}
/**
* Creates {@link IHyperlink} instance.
*
* This method is extracted to simplify testing.
*
* @param offset
* @param line
* @param begin
* @param end
* @return
*/
protected IHyperlink createLink(int offset, final String line, int begin,
int end) {
final ITextEditor editor = getAdapter(ITextEditor.class);
if (editor != null) {
final String requiredFile = line.substring(begin, end);
final Region region = new Region(offset + begin, end - begin);
return new RubyRequireHyperlink(requiredFile, region, editor);
}
return null;
}
}