1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/*******************************************************************************
* Copyright (c) 2004, 2009 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
* David Green - fix for bug 266693
* Abner Ballardo - fix for bug 288427
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.editors;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.AbstractTaskHyperlinkDetector;
/**
* Detects URLs based on a regular expression.
*
* @author David Green
*/
public class TaskUrlHyperlinkDetector extends AbstractTaskHyperlinkDetector {
// based on RFC 3986
// even though it's valid, the platform hyperlink detector doesn't detect hyperlinks that end with '.', ',' or ')'
// so we do the same here
private static final Pattern URL_PATTERN = Pattern.compile("([a-zA-Z][a-zA-Z+.-]{0,10}://[a-zA-Z0-9%._~!$&?#'()*+,;:@/=-]*[a-zA-Z0-9%_~!$&?#'(*+;:@/=-])"); //$NON-NLS-1$
private static final String CLOSED_PARENTHESIS_PATTERN = "[^)]"; //$NON-NLS-1$
private static final String OPEN_PARENTHESIS_PATTERN = "[^(]"; //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
public TaskUrlHyperlinkDetector() {
}
@Override
protected List<IHyperlink> detectHyperlinks(ITextViewer textViewer, String content, int indexInContent,
int contentOffset) {
List<IHyperlink> links = null;
Matcher m = URL_PATTERN.matcher(content);
while (m.find()) {
if (isInRegion(indexInContent, m)) {
String urlString = getUrlString(content, m);
TaskUrlHyperlink link = null;
if (getAdapter(TaskRepository.class) != null) {
try {
new URL(urlString);
link = createTaskUrlHyperlink(contentOffset, m, urlString);
} catch (MalformedURLException e) {
// ignore
}
} else {
if (TasksUiInternal.isTaskUrl(urlString)) {
link = createTaskUrlHyperlink(contentOffset, m, urlString);
}
}
if (link != null) {
if (links == null) {
links = new ArrayList<IHyperlink>();
}
links.add(link);
}
}
}
return links;
}
private String getUrlString(String content, Matcher m) {
String urlString = m.group(1);
// check if the urlString has more opening parenthesis than closing
int parenthesisDiff = urlString.replaceAll(OPEN_PARENTHESIS_PATTERN, EMPTY_STRING).length()
- urlString.replaceAll(CLOSED_PARENTHESIS_PATTERN, EMPTY_STRING).length();
if (parenthesisDiff > 0) {
// if any open paranthesis were not closed assume that trailing closing parenthesis are part of URL
for (int i = m.end(); i - m.end() < parenthesisDiff; i++) {
if (i >= content.length() || content.charAt(i) != ')') {
break;
}
urlString += ')';
}
}
return urlString;
}
private static boolean isInRegion(int offsetInText, Matcher m) {
return (offsetInText == -1) || (offsetInText >= m.start() && offsetInText <= m.end());
}
private static TaskUrlHyperlink createTaskUrlHyperlink(int textOffset, Matcher m, String urlString) {
return new TaskUrlHyperlink(new Region(textOffset + m.start(), urlString.length()), urlString);
}
}
|