blob: 1b2cd8f3ddd8e16f8680f352b668d4baa0404832 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2018 Alexander Kurtakov.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Kurtakov - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.rpm.ui.editor.hyperlink;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
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.linuxtools.internal.rpm.ui.editor.ISpecfileSpecialSymbols;
import org.eclipse.linuxtools.internal.rpm.ui.editor.SpecfileEditor;
import org.eclipse.linuxtools.internal.rpm.ui.editor.parser.SpecfileSource;
import org.eclipse.linuxtools.rpm.ui.editor.parser.Specfile;
import org.eclipse.linuxtools.rpm.ui.editor.parser.SpecfileDefine;
import org.eclipse.linuxtools.rpm.ui.editor.parser.SpecfileElement;
import org.eclipse.linuxtools.rpm.ui.editor.parser.SpecfileParser;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.FileEditorInput;
/**
* Hyperlink detector for source, patch and defines in the spec file.
*
*/
public class SpecfileElementHyperlinkDetector extends AbstractHyperlinkDetector {
private static final String PATCH_IDENTIFIER = "%patch"; //$NON-NLS-1$
private static final String SOURCE_IDENTIFIER = "%{SOURCE"; //$NON-NLS-1$
private Specfile specfile;
@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
if (region == null || textViewer == null) {
return null;
}
IDocument document = textViewer.getDocument();
if (document == null) {
return null;
}
// Keeps the errorHandler on the initial opening of the .spec file
// otherwise, a new SpecfileParser does not initialize errorHandler
// until a SpecfileEditor#editorSaved is called
if (specfile == null) {
SpecfileEditor a = this.getAdapter(SpecfileEditor.class);
if (a != null && a.getSpecfile() != null) {
specfile = a.getSpecfile();
} else {
SpecfileParser parser = new SpecfileParser();
specfile = parser.parse(document);
}
}
int offset = region.getOffset();
IRegion lineInfo;
String line;
try {
lineInfo = document.getLineInformationOfOffset(offset);
line = document.get(lineInfo.getOffset(), lineInfo.getLength());
} catch (BadLocationException ex) {
return null;
}
int offsetInLine = offset - lineInfo.getOffset();
StringTokenizer tokens = new StringTokenizer(line);
String word = ""; //$NON-NLS-1$
int tempLineOffset = 0;
int wordOffsetInLine = 0;
while (tokens.hasMoreTokens()) {
String tempWord = tokens.nextToken();
Pattern defineRegexp = Pattern.compile("%\\{(.*?)\\}"); //$NON-NLS-1$
Matcher fit = defineRegexp.matcher(tempWord);
while (fit.find()) {
if ((fit.start() + tempLineOffset <= offsetInLine) && (offsetInLine <= fit.end() + tempLineOffset)) {
tempWord = fit.group();
wordOffsetInLine = fit.start();
tempLineOffset += fit.start();
break;
}
}
tempLineOffset += tempWord.length();
word = tempWord;
if (tempLineOffset > offsetInLine) {
break;
}
}
if (word.startsWith(SOURCE_IDENTIFIER)) {
int sourceNumber = Integer.valueOf(word.substring(SOURCE_IDENTIFIER.length(), word.length() - 1))
.intValue();
SpecfileSource source = specfile.getSource(sourceNumber);
if (source != null) {
return prepareHyperlink(lineInfo, line, word, source);
}
} else if (word.startsWith(PATCH_IDENTIFIER)) {
int sourceNumber = Integer.valueOf(word.substring(PATCH_IDENTIFIER.length(), word.length())).intValue();
SpecfileSource source = specfile.getPatch(sourceNumber);
if (source != null) {
return prepareHyperlink(lineInfo, line, word, source);
}
} else {
String defineName = getDefineName(word);
SpecfileDefine define = specfile.getDefine(defineName);
if (define != null) {
return prepareHyperlink(lineInfo, line, defineName, define, wordOffsetInLine);
}
}
return null;
}
private String getDefineName(String word) {
if (word.startsWith(ISpecfileSpecialSymbols.MACRO_START_LONG)) {
return word.substring(2, word.length() - 1);
}
return ""; //$NON-NLS-1$
}
private IHyperlink[] prepareHyperlink(IRegion lineInfo, String line, String word, SpecfileElement source,
int lineIndex) {
IRegion urlRegion = new Region(lineInfo.getOffset() + line.indexOf(word, lineIndex), word.length());
// will only work with 1 active page
// does not work with CompareEditor
IWorkbench wb = PlatformUI.getWorkbench();
IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
IWorkbenchPage page = win.getActivePage();
IEditorPart editor = page.getActiveEditor();
// A IFile cannot be retrieve from a IFileStoreEditorInput, so at this time
// we can only provide this functionality for resources inside the workbench.
if (editor.getEditorInput() instanceof FileEditorInput) {
IFile original = ((FileEditorInput) editor.getEditorInput()).getFile();
return new IHyperlink[] { new SpecfileElementHyperlink(urlRegion, source, original) };
} else {
return null;
}
}
private IHyperlink[] prepareHyperlink(IRegion lineInfo, String line, String word, SpecfileElement source) {
return prepareHyperlink(lineInfo, line, word, source, 0);
}
public void setSpecfile(Specfile specfile) {
this.specfile = specfile;
}
}