/** * Aptana Studio * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). * Please see the license.html included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.radrails.rails.internal.ui.hyperlink; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.debug.ui.console.IConsole; import org.eclipse.debug.ui.console.IConsoleLineTracker; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; import org.radrails.rails.ui.RailsUIPlugin; import com.aptana.core.logging.IdeLog; /** * Detects URLs or bare hostnames like www.cnn.com and generates hyperlinks for them. * * @author cwilliams */ public class URLDetector implements IConsoleLineTracker { // FIXME Combine with URLHyperlinkDetector in terminal plugin! /** * Detect URLs with protocol, or bare hostnames */ @SuppressWarnings("nls") private static final Pattern URL_DETECT_PATTERN = Pattern.compile("\\b\n" + " # Match the leading part (proto://hostname, or just hostname)\n" + " (\n" + " # http://, or https:// leading part\n" + " (https?)://[-\\w]+(\\.\\w[-\\w]*)+\n" + " |\n" + " # or, try to find a hostname with more specific sub-expression\n" + " (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \\. )+ # sub domains\n" + " # Now ending .com, etc. For these, require lowercase\n" + " (?-i: com\\b\n" + " | edu\\b\n" + " | biz\\b\n" + " | gov\\b\n" + " | in(?:t|fo)\\b # .int or .info\n" + " | mil\\b\n" + " | net\\b\n" + " | org\\b\n" + " | [a-z][a-z]\\.[a-z][a-z]\\b # two-letter country code\n" + " )\n" + " )\n" + "\n" + " # Allow an optional port number\n" + " ( : \\d+ )?\n" + " \n" + " # The rest of the URL is optional, and begins with /\n" + " (\n" + " /\n" + " # The rest are heuristics for what seems to work well\n" + " [^.!,?;\"\\'<>()\\[\\]\\{\\}\\s\\x7F-\\xFF]*\n" + " (\n" + " [.!,?]+ [^.!,?;\"\\'<>()\\[\\]\\{\\}\\s\\x7F-\\xFF]+\n" + " )*\n" + " )?", Pattern.CASE_INSENSITIVE | Pattern.COMMENTS); private IConsole fConsole; public void init(IConsole console) { this.fConsole = console; } public void lineAppended(IRegion line) { if (this.fConsole == null) { return; } try { String contents = this.fConsole.getDocument().get(line.getOffset(), line.getLength()); Matcher m = URL_DETECT_PATTERN.matcher(contents); int start = 0; while (m.find(start)) { String urlString = m.group().trim(); start = m.end(); IRegion region = new Region(m.start() + line.getOffset(), urlString.length()); if (!urlString.startsWith("http://")) //$NON-NLS-1$ { urlString = "http://" + urlString; //$NON-NLS-1$ // $codepro.audit.disable stringConcatenationInLoop } // this.fConsole.addLink(new AdaptingHyperlink(new URLHyperlink(region, urlString)), region.getOffset(), // region.getLength()); } } catch (BadLocationException e) { IdeLog.logError(RailsUIPlugin.getDefault(), e); } } public void dispose() { this.fConsole = null; } }