/* * Copyright 2000-2009 JetBrains s.r.o. * * 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 org.intellij.lang.xpath.xslt.run; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.HyperlinkInfo; import com.intellij.execution.filters.InvalidExpressionException; import com.intellij.execution.filters.OpenFileHyperlinkInfo; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.io.URLUtil; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Copy of com.intellij.execution.filters.RegexpFilter * * Sascha Weinreuter - 2005-11-07 - Modfied to be able to use a customized filename/url pattern * * @author Yura Cangea * @version 1.0 */ @SuppressWarnings({"ALL"}) public class CustomRegexpFilter implements Filter { @SuppressWarnings({"HardCodedStringLiteral"}) public static final String FILE_PATH_MACROS = "$FILE_PATH$"; @SuppressWarnings({"HardCodedStringLiteral"}) public static final String LINE_MACROS = "$LINE$"; @SuppressWarnings({"HardCodedStringLiteral"}) public static final String COLUMN_MACROS = "$COLUMN$"; @SuppressWarnings({"HardCodedStringLiteral"}) private static final String DEFAULT_REGEXP = "((?:\\p{Alpha}\\:)?[0-9 a-z_A-Z\\-\\\\./]+)"; private static final String NUMBER_REGEXP = "([0-9]+)"; private int myFileRegister; private int myLineRegister; private int myColumnRegister; private Pattern myPattern; private Project myProject; private final VirtualFile myBase; private final String myFilePathRegexp; public CustomRegexpFilter(Project project, String expression, VirtualFile base) { this(project, expression, base, DEFAULT_REGEXP); } public CustomRegexpFilter(Project project, String expression, VirtualFile base, String filePathExpr) { myFilePathRegexp = filePathExpr; myProject = project; myBase = base; validate(expression); if (expression == null || "".equals(expression.trim())) { throw new InvalidExpressionException("expression == null or empty"); } int filePathIndex = expression.indexOf(FILE_PATH_MACROS); int lineIndex = expression.indexOf(LINE_MACROS); int columnIndex = expression.indexOf(COLUMN_MACROS); if (filePathIndex == -1) { throw new InvalidExpressionException("Expression must contain " + FILE_PATH_MACROS + " macros."); } final TreeMap<Integer, String> map = new TreeMap<Integer, String>(); map.put(new Integer(filePathIndex), "file"); expression = StringUtil.replace(expression, FILE_PATH_MACROS, myFilePathRegexp); if (lineIndex != -1) { expression = StringUtil.replace(expression, LINE_MACROS, NUMBER_REGEXP); map.put(new Integer(lineIndex), "line"); } if (columnIndex != -1) { expression = StringUtil.replace(expression, COLUMN_MACROS, NUMBER_REGEXP); map.put(new Integer(columnIndex), "column"); } // The block below determines the registers based on the sorted map. int count = 0; final Iterator<Integer> itr = map.keySet().iterator(); while (itr.hasNext()) { count++; final String s = map.get(itr.next()); if ("file".equals(s)) { filePathIndex = count; } else if ("line".equals(s)) { lineIndex = count; } else if ("column".equals(s)) { columnIndex = count; } } myFileRegister = filePathIndex; myLineRegister = lineIndex; myColumnRegister = columnIndex; myPattern = Pattern.compile(expression, Pattern.MULTILINE); } public void validate(String expression) { if (expression == null || "".equals(expression.trim())) { throw new InvalidExpressionException("expression == null or empty"); } expression = substituteMacrosesWithRegexps(expression); Pattern.compile(expression, Pattern.MULTILINE); } private String substituteMacrosesWithRegexps(String expression) { int filePathIndex = expression.indexOf(FILE_PATH_MACROS); int lineIndex = expression.indexOf(LINE_MACROS); int columnIndex = expression.indexOf(COLUMN_MACROS); if (filePathIndex == -1) { throw new InvalidExpressionException("Expression must contain " + FILE_PATH_MACROS + " macros."); } expression = StringUtil.replace(expression, FILE_PATH_MACROS, myFilePathRegexp); if (lineIndex != -1) { expression = StringUtil.replace(expression, LINE_MACROS, NUMBER_REGEXP); } if (columnIndex != -1) { expression = StringUtil.replace(expression, COLUMN_MACROS, NUMBER_REGEXP); } return expression; } @SuppressWarnings({"ConstantConditions"}) public Result applyFilter(final String line, final int entireLength) { final Matcher matcher = myPattern.matcher(line); if (matcher.find()) { return createResult(matcher, entireLength - line.length()); } return null; } private Result createResult(final Matcher matcher, final int entireLen) { final String filePath = matcher.group(myFileRegister); String lineNumber = "0"; String columnNumber = "0"; if (myLineRegister != -1) { lineNumber = matcher.group(myLineRegister); } if (myColumnRegister != -1) { columnNumber = matcher.group(myColumnRegister); } int line = 0; int column = 0; try { line = Integer.parseInt(lineNumber); column = Integer.parseInt(columnNumber); } catch (NumberFormatException e) { // Do nothing, so that line and column will remain at their initial // zero values. } if (line > 0) line -= 1; if (column > 0) column -= 1; // Calculate the offsets relative to the entire text. final int highlightStartOffset; final int highlightEndOffset; if ((filePath == null || filePath.length() == 0) && myLineRegister != -1) { highlightStartOffset = entireLen + matcher.start(myLineRegister); highlightEndOffset = highlightStartOffset + lineNumber.length(); } else { highlightStartOffset = entireLen + matcher.start(myFileRegister); highlightEndOffset = highlightStartOffset + filePath.length(); } final HyperlinkInfo info = createOpenFileHyperlink(filePath, line, column); // don't return a result if the filename cannot be resolved to a file return info != null ? new Result(highlightStartOffset, highlightEndOffset, info) : null; } protected HyperlinkInfo createOpenFileHyperlink(String fileName, final int line, int column) { if ((fileName == null || fileName.length() == 0)) { if (myBase != null) { fileName = myBase.getPresentableUrl(); } else { return null; } } fileName = fileName.replace(File.separatorChar, '/'); VirtualFile file; // try to interpret the filename as URL if (URLUtil.containsScheme(fileName)) { try { file = VfsUtil.findFileByURL(new URL(fileName)); } catch (MalformedURLException e) { file = VirtualFileManager.getInstance().findFileByUrl(VfsUtil.pathToUrl(fileName)); } } else { file = VfsUtil.findRelativeFile(fileName, myBase); } if (file == null) { //noinspection ConstantConditions return null; } final FileType fileType = file.getFileType(); if (fileType != null && column > 0) { final Document document = FileDocumentManager.getInstance().getDocument(file); final int start = document.getLineStartOffset(line); final int max = document.getLineEndOffset(line); final int tabSize = CodeStyleSettingsManager.getInstance(myProject).getCurrentSettings().getTabSize(fileType); column = EditorUtil.calcColumnNumber(null, document.getCharsSequence(), start, Math.min(start + column, max), tabSize); } return new OpenFileHyperlinkInfo(myProject, file, line, column); } public static String[] getMacrosName() { return new String[] {FILE_PATH_MACROS, LINE_MACROS, COLUMN_MACROS}; } }