2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.openapi.vcs;
19 import com.intellij.lifecycle.PeriodicalTasksCloser;
20 import com.intellij.openapi.components.PersistentStateComponent;
21 import com.intellij.openapi.components.State;
22 import com.intellij.openapi.components.Storage;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.progress.ProcessCanceledException;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.SimpleModificationTracker;
27 import com.intellij.openapi.util.TextRange;
28 import com.intellij.util.io.URLUtil;
29 import com.intellij.util.xmlb.XmlSerializerUtil;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
41 @State(name = "IssueNavigationConfiguration", storages = @Storage("vcs.xml"))
42 public class IssueNavigationConfiguration extends SimpleModificationTracker
43 implements PersistentStateComponent<IssueNavigationConfiguration> {
44 private static final Logger LOG = Logger.getInstance(IssueNavigationConfiguration.class);
46 public static IssueNavigationConfiguration getInstance(Project project) {
47 return PeriodicalTasksCloser.getInstance().safeGetService(project, IssueNavigationConfiguration.class);
50 private List<IssueNavigationLink> myLinks = new ArrayList<>();
52 public List<IssueNavigationLink> getLinks() {
56 public void setLinks(final List<IssueNavigationLink> links) {
57 myLinks = new ArrayList<>(links);
58 incModificationCount();
61 public IssueNavigationConfiguration getState() {
65 public void loadState(IssueNavigationConfiguration state) {
66 XmlSerializerUtil.copyBean(state, this);
69 public static class LinkMatch implements Comparable {
70 private final TextRange myRange;
71 private final String myTargetUrl;
73 public LinkMatch(final TextRange range, final String targetUrl) {
75 myTargetUrl = targetUrl;
78 public TextRange getRange() {
82 public String getTargetUrl() {
86 public int compareTo(Object o) {
87 if (!(o instanceof LinkMatch)) {
90 return myRange.getStartOffset() - ((LinkMatch)o).getRange().getStartOffset();
94 public List<LinkMatch> findIssueLinks(CharSequence text) {
95 final List<LinkMatch> result = new ArrayList<>();
97 for (IssueNavigationLink link : myLinks) {
98 Pattern issuePattern = link.getIssuePattern();
99 Matcher m = issuePattern.matcher(text);
102 String replacement = issuePattern.matcher(m.group(0)).replaceFirst(link.getLinkRegexp());
103 addMatch(result, new TextRange(m.start(), m.end()), replacement);
105 catch (Exception e) {
106 LOG.debug("Malformed regex replacement. IssueLink: " + link + "; text: " + text, e);
110 Matcher m = URLUtil.URL_PATTERN.matcher(text);
112 addMatch(result, new TextRange(m.start(), m.end()), m.group());
115 catch (ProcessCanceledException e) {
116 //skip too long processing completely
118 Collections.sort(result);
122 private static void addMatch(final List<LinkMatch> result, final TextRange range, final String replacement) {
123 for (Iterator<LinkMatch> iterator = result.iterator(); iterator.hasNext(); ) {
124 LinkMatch oldMatch = iterator.next();
125 if (range.contains(oldMatch.getRange())) {
128 else if (oldMatch.getRange().contains(range)) {
132 result.add(new LinkMatch(range, replacement));