| /******************************************************************************* |
| * Copyright (c) 2008, 2018 Alphonse Van Assche and others. |
| * |
| * 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: |
| * Alphonse Van Assche - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.linuxtools.internal.rpm.ui.editor.hyperlink; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.text.MessageFormat; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.ITextSelection; |
| 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.viewers.ISelection; |
| import org.eclipse.linuxtools.internal.rpm.ui.editor.SpecfileEditor; |
| import org.eclipse.linuxtools.rpm.ui.editor.parser.Specfile; |
| |
| /** |
| * Mail hyperlink detector. Largely inspired of |
| * {@link org.eclipse.jface.text.hyperlink.URLHyperlinkDetector} |
| */ |
| public class MailHyperlinkDetector extends AbstractHyperlinkDetector { |
| |
| private SpecfileEditor editor; |
| |
| @Override |
| public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { |
| if (region == null || textViewer == null) { |
| return null; |
| } |
| if (editor == null) { |
| editor = this.getAdapter(SpecfileEditor.class); |
| if (editor == null) { |
| return null; |
| } |
| } |
| |
| IDocument document = textViewer.getDocument(); |
| |
| int offset = region.getOffset(); |
| |
| String urlString = null; |
| if (document == null) { |
| return null; |
| } |
| |
| IRegion lineInfo; |
| String line; |
| String mail; |
| int mailLength = 0; |
| int mailOffsetInLine; |
| try { |
| lineInfo = document.getLineInformationOfOffset(offset); |
| line = document.get(lineInfo.getOffset(), lineInfo.getLength()); |
| } catch (BadLocationException ex) { |
| ex.printStackTrace(); |
| return null; |
| } |
| |
| int startSeparator = line.indexOf('<'); |
| mailOffsetInLine = startSeparator + 1; |
| |
| if (startSeparator != -1) { |
| int endSeparator = line.indexOf('>'); |
| |
| if (endSeparator < 5) { |
| return null; |
| } |
| |
| mail = line.substring(startSeparator + 1, endSeparator).trim(); |
| mailLength = mail.length(); |
| |
| // Some cleanups, maybe we can add more. |
| mail = mail.replaceAll("(?i) at ", "@"); //$NON-NLS-1$ //$NON-NLS-2$ |
| mail = mail.replaceAll("(?i) dot ", "."); //$NON-NLS-1$ //$NON-NLS-2$ |
| mail = mail.replaceAll("(?i)_at_", "@"); //$NON-NLS-1$ //$NON-NLS-2$ |
| mail = mail.replaceAll("(?i)_dot_", "."); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| mail = mail.replaceAll(" +", " "); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (mail.split(" ").length == 3) { //$NON-NLS-1$ |
| if (mail.indexOf('@') == -1) { |
| mail = mail.replaceFirst(" ", "@").replaceFirst(" ", "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| } |
| mail = mail.replaceAll(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| } else { |
| |
| int offsetInLine = offset - lineInfo.getOffset(); |
| |
| boolean startDoubleQuote = false; |
| mailOffsetInLine = 0; |
| |
| int mailSeparatorOffset = line.indexOf('@'); |
| while (mailSeparatorOffset >= 0) { |
| |
| // (left to "@") |
| mailOffsetInLine = mailSeparatorOffset; |
| char ch; |
| do { |
| mailOffsetInLine--; |
| ch = ' '; |
| if (mailOffsetInLine > -1) { |
| ch = line.charAt(mailOffsetInLine); |
| } |
| startDoubleQuote = ch == '"'; |
| } while (Character.isLetterOrDigit(ch) || ch == '.' || ch == '_' || ch == '-'); |
| mailOffsetInLine++; |
| |
| // a valid mail contain a left part. |
| if (mailOffsetInLine == mailSeparatorOffset) { |
| return null; |
| } |
| |
| // Right to "@" |
| StringTokenizer tokenizer = new StringTokenizer(line.substring(mailSeparatorOffset + 3), " \t\n\r\f<>", //$NON-NLS-1$ |
| false); |
| if (!tokenizer.hasMoreTokens()) { |
| return null; |
| } |
| |
| mailLength = tokenizer.nextToken().length() + 3 + mailSeparatorOffset - mailOffsetInLine; |
| if (offsetInLine >= mailOffsetInLine && offsetInLine <= mailOffsetInLine + mailLength) { |
| break; |
| } |
| |
| mailSeparatorOffset = line.indexOf('@', mailSeparatorOffset + 1); |
| } |
| |
| if (mailSeparatorOffset < 0) { |
| return null; |
| } |
| |
| if (startDoubleQuote) { |
| int endOffset = -1; |
| int nextDoubleQuote = line.indexOf('"', mailOffsetInLine); |
| int nextWhitespace = line.indexOf(' ', mailOffsetInLine); |
| if (nextDoubleQuote != -1 && nextWhitespace != -1) { |
| endOffset = Math.min(nextDoubleQuote, nextWhitespace); |
| } else if (nextDoubleQuote != -1) { |
| endOffset = nextDoubleQuote; |
| } else if (nextWhitespace != -1) { |
| endOffset = nextWhitespace; |
| } |
| if (endOffset != -1) { |
| mailLength = endOffset - mailOffsetInLine; |
| } |
| } |
| if (mailLength == 0) { |
| return null; |
| } |
| |
| mail = line.substring(mailOffsetInLine, mailOffsetInLine + mailLength); |
| } |
| |
| try { |
| // mail address contain at less one '@' and one '.' character. |
| if (!mail.contains("@") || !mail.contains(".")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| return null; |
| } |
| |
| urlString = "mailto:" + mail; //$NON-NLS-1$ |
| char separator = '?'; |
| String subject = getSubject(); |
| if (subject != null) { |
| urlString += separator + "subject=" + subject; //$NON-NLS-1$ |
| separator = '&'; |
| } |
| String body = getBody(); |
| if (body != null) { |
| urlString += separator + "body=" + body; //$NON-NLS-1$ |
| } |
| |
| // url don't like % |
| urlString = urlString.replaceAll("\\%", "\\%25"); //$NON-NLS-1$ //$NON-NLS-2$ |
| new URL(urlString); |
| } catch (MalformedURLException ex) { |
| ex.printStackTrace(); |
| urlString = null; |
| return null; |
| } |
| |
| IRegion urlRegion = new Region(lineInfo.getOffset() + mailOffsetInLine, mailLength); |
| return new IHyperlink[] { new MailHyperlink(urlRegion, urlString) }; |
| } |
| |
| private String getSubject() { |
| Specfile specfile = editor.getSpecfile(); |
| return MessageFormat.format("[{0}.spec - {1}-{2}]", specfile.getName(), specfile.getVersion(), //$NON-NLS-1$ |
| specfile.getRelease()); |
| } |
| |
| private String getBody() { |
| String body = null; |
| // Get current selection |
| IDocument document = editor.getAdapter(IDocument.class); |
| ISelection currentSelection = editor.getSpecfileSourceViewer().getSelection(); |
| if (currentSelection instanceof ITextSelection) { |
| ITextSelection selection = (ITextSelection) currentSelection; |
| try { |
| String txt = selection.getText(); |
| if (txt.trim().length() > 0) { |
| int begin = document.getLineOffset(selection.getStartLine()); |
| body = document.get().substring(begin, selection.getOffset() + selection.getLength()); |
| // replace left spaces or tabs and add a space at the begin of each line. |
| body = body.replaceAll("(?m)^[ \\t]+|[ \\t]+$|^", " "); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } catch (BadLocationException e) { |
| } |
| |
| } |
| return body; |
| } |
| |
| public void setEditor(SpecfileEditor editor) { |
| this.editor = editor; |
| } |
| } |