blob: a9673b454ed3353df02203ece95ceab4e2ef4850 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gitiles;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
/** Linkifier for blocks of text such as commit message descriptions. */
public class Linkifier {
private static final Pattern LINK_PATTERN;
static {
// HTTP URL regex adapted from com.google.gwtexpui.safehtml.client.SafeHtml.
String part = "(?:" +
"[a-zA-Z0-9$_.+!*',%;:@=?#/~<>-]" +
"|&(?!lt;|gt;)" +
")";
String httpUrl = "https?://" +
part + "{2,}" +
"(?:[(]" + part + "*" + "[)])*" +
part + "*";
String changeId = "\\bI[0-9a-f]{8,40}\\b";
LINK_PATTERN = Pattern.compile(Joiner.on("|").join(
"(" + httpUrl + ")",
"(" + changeId + ")"));
}
private final GitilesUrls urls;
public Linkifier(GitilesUrls urls) {
this.urls = checkNotNull(urls, "urls");
}
public List<Map<String, String>> linkify(HttpServletRequest req, String message) {
String baseGerritUrl = urls.getBaseGerritUrl(req);
List<Map<String, String>> parsed = Lists.newArrayList();
Matcher m = LINK_PATTERN.matcher(message);
int last = 0;
while (m.find()) {
addText(parsed, message.substring(last, m.start()));
if (m.group(1) != null) {
// Bare URL.
parsed.add(link(m.group(1), m.group(1)));
} else if (m.group(2) != null) {
if (baseGerritUrl != null) {
// Gerrit Change-Id.
parsed.add(link(m.group(2), baseGerritUrl + "#/q/" + m.group(2) + ",n,z"));
} else {
addText(parsed, m.group(2));
}
}
last = m.end();
}
addText(parsed, message.substring(last));
return parsed;
}
private static Map<String, String> link(String text, String url) {
return ImmutableMap.of("text", text, "url", url);
}
private static void addText(List<Map<String, String>> parts, String text) {
if (text.isEmpty()) {
return;
}
if (parts.isEmpty()) {
parts.add(ImmutableMap.of("text", text));
} else {
Map<String, String> old = parts.get(parts.size() - 1);
if (!old.containsKey("url")) {
parts.set(parts.size() - 1, ImmutableMap.of("text", old.get("text") + text));
} else {
parts.add(ImmutableMap.of("text", text));
}
}
}
}