sdedic commented on a change in pull request #481: [NETBEANS-290] Provided support for hyperlink on dependencies. URL: https://github.com/apache/incubator-netbeans/pull/481#discussion_r179224485
########## File path: maven.grammar/src/org/netbeans/modules/maven/hyperlinks/HyperlinkProviderImpl.java ########## @@ -453,5 +215,331 @@ private FileObject getPath(FileObject parent, String path) { } return parent.getFileObject(path); } + + private class PomParserRunnable implements Runnable { + + private final PomHyperlinkInfo hyperLinkInfo; + private final Document document; + private final int offset; + + public PomParserRunnable(PomHyperlinkInfo hyperLinkInfo, Document document, int offset) { + this.hyperLinkInfo = hyperLinkInfo; + this.document = document; + this.offset = offset; + } + + @Override + public void run() { + TokenHierarchy th = TokenHierarchy.get(document); + TokenSequence<XMLTokenId> xml = th.tokenSequence(XMLTokenId.language()); + xml.move(offset); + xml.moveNext(); + Token<XMLTokenId> token = xml.token(); + + // when it's not a value -> do nothing. + if (token == null) { + return; + } + + if (token.id() == XMLTokenId.TEXT) { + hyperLinkInfo.calculateInfo(token, xml); + } + } + } + private class PomHyperlinkInfo { + final Document doc; + final int documentOffset; + final FileObject projectFileObject; + boolean isText; + int ftokenOff; + String ftext; + + String artifactId; + String groupId; + String version; + String type; + + public PomHyperlinkInfo(Document doc, int documentOffset) { + this.doc = doc; + this.documentOffset = documentOffset; + this.projectFileObject = getProjectDir(doc); + } + + boolean isHyperlinkUrl() { + return ftext != null && + (ftext.startsWith("http://") || //NOI18N + ftext.startsWith("https://")); //NOI18N; + } + + private boolean isFileSystemLink() { + FileObject fo = getProjectDir(doc); + return (fo != null && ftext != null) && getPath(fo, ftext) != null; + } + + boolean isMavenProperty() { + if (ftext != null) { + int ff = documentOffset - ftokenOff; + if (ff > -1 && ff < ftext.length()) { + String before = ftext.substring(0, ff); + String after = ftext.substring(ff, ftext.length()); + int bo = before.lastIndexOf("${");//NOI18N + int bc = before.lastIndexOf("}");//NOI18N + int ao = after.indexOf("${");//NOI18N + int ac = after.indexOf("}");//NOI18N + if (bo > bc && ac > -1 && (ac < ao || ao == -1)) { + return true; + } + } + } + return false; + } + + boolean isMavenDependency() { + return artifactId != null && groupId != null && version != null; + } + + boolean isHyperlinkPoint() { + return (isHyperlinkUrl() || isFileSystemLink() || isMavenProperty() || isMavenDependency()); + } + + private void calculateInfo(Token<XMLTokenId> token, TokenSequence<XMLTokenId> xml) { + isText = token.id() == XMLTokenId.TEXT; + if (isText) { + ftokenOff = xml.offset(); + ftext = token.text().toString(); + + if (projectFileObject != null && getPath(projectFileObject, ftext) != null) { + xml.movePrevious(); + token = xml.token(); + if (token != null && token.id().equals(XMLTokenId.TAG) && TokenUtilities.equals(token.text(), ">")) {//NOI18N + xml.movePrevious(); + token = xml.token(); + if (token != null && token.id().equals(XMLTokenId.TAG)) { + if (TokenUtilities.equals(token.text(), "<module")) {//NOI18N + if (!ftext.endsWith("/pom.xml")) { + ftext += "/pom.xml"; //NOI18N + } + } + } + } + } else { + xml.movePrevious(); + token = xml.token(); + if (token != null && token.id().equals(XMLTokenId.TAG) && TokenUtilities.equals(token.text(), ">")) { //NOI18N + xml.movePrevious(); + token = xml.token(); + if (TokenUtilities.equals(token.text(), "<artifactId") || //NOI18N + TokenUtilities.equals(token.text(), "<groupId") || //NOI18N + TokenUtilities.equals(token.text(), "<type") || //NOI18N + (TokenUtilities.equals(token.text(), "<version") && !ftext.startsWith("${"))) { //NOI18N + resetSequenceToDependencyTagToken(xml); + if (TokenUtilities.equals(xml.token().text(), "<dependency")) { + while(!TokenUtilities.equals(xml.token().text(), "</dependency")) { //NOI18N + xml.moveNext(); + token = xml.token(); + if (TokenUtilities.equals(token.text(), "<artifactId")) { //NOI18N + xml.moveNext(); + xml.moveNext(); + token = xml.token(); + artifactId = token.text().toString(); + xml.moveNext(); + } else if (TokenUtilities.equals(token.text(), "<groupId")) { //NOI18N + xml.moveNext(); + xml.moveNext(); + token = xml.token(); + groupId = token.text().toString(); + xml.moveNext(); + } else if (TokenUtilities.equals(token.text(), "<version")) { //NOI18N + xml.moveNext(); + xml.moveNext(); + token = xml.token(); + if (token.text().toString().startsWith("${")) { //NOI18N + Project nbprj = getProject(doc); + try { + version = (String)PluginPropertyUtils.createEvaluator(nbprj).evaluate(token.text().toString()); + } catch (ExpressionEvaluationException eee) { + LOG.log(Level.INFO, "Unable to evaluate property: " + token.text().toString(), eee); + } + } else { + version = token.text().toString(); + } + xml.moveNext(); + } else if (TokenUtilities.equals(token.text(), "<type")) { //NOI18N + xml.moveNext(); + xml.moveNext(); + token = xml.token(); + type = token.text().toString(); + xml.moveNext(); + } + } + // handle cases where the version element is covered in a + // parent pom/dependenciesManagement + if (version == null) { + MavenProject mavenProject = getNbMavenProject(doc).getMavenProject(); + for (Artifact artifact : mavenProject.getArtifacts()) { + if (artifact.getGroupId().equals(groupId) + && artifact.getArtifactId().equals(artifactId)) { + version = artifact.getVersion(); + break; + } + } + } + } + } + } + } + } + } + + String[] getTooltipText() { + if (isText) { + //we are in element text + String text = ftext; + int tokenOff = ftokenOff; + if (isMavenProperty()){ + Tuple tup = findProperty(text, tokenOff, documentOffset); + + if (tup != null) { + String prop = tup.value.substring("${".length(), tup.value.length() - 1); //remove the brackets + try { + Project nbprj = getProject(doc); + if (nbprj != null) { + Object exRes = PluginPropertyUtils.createEvaluator(nbprj).evaluate(tup.value); + if (exRes != null) { + return new String[] {prop, (String)exRes}; + } + } else { + //pom file in repository or settings file. + } + } catch (ExpressionEvaluationException ex) { + return null; + } + } + } else if(isMavenDependency()) { + return new String[] { getMavenArtifactAbsolutePomPath() }; + } + } + return null; + } + + String getMavenArtifactAbsolutePomPath() { + if (!isMavenDependency()) { + return null; + } else { + MavenEmbedder embedder = EmbedderFactory.getProjectEmbedder(); + Artifact mavenArtifact = embedder.createArtifact(groupId, artifactId, version, type == null ? "jar" : type); + return embedder.getLocalRepository().find(mavenArtifact).getFile().getAbsolutePath().replace(".jar", ".pom"); + } + } + + private int[] getHyperLinkSpan() { + if (isText) { + //we are in element text + FileObject fo = getProjectDir(doc); + if (fo != null && getPath(fo, ftext) != null) { + return new int[] { ftokenOff, ftokenOff + ftext.length() }; + } + // urls get opened.. + if (ftext != null && + (ftext.startsWith("http://") || //NOI18N + (ftext.startsWith("https://")))) { //NOI18N + return new int[] { ftokenOff, ftokenOff + ftext.length() }; + } + if (ftext != null) { + Tuple prop = findProperty(ftext, ftokenOff, documentOffset); + if (prop != null) { + return new int[] { prop.spanStart, prop.spanEnd}; + } + } + if (isMavenDependency()) { + return new int[] { ftokenOff, ftokenOff + ftext.length() }; + } + } + return null; + } + + private void resetSequenceToDependencyTagToken(TokenSequence<XMLTokenId> tokenSequence) { + while(!TokenUtilities.equals("<dependency", tokenSequence.token().text()) && Review comment: tokenSequence().token().text() materializes a String from the token, which makes usage of TokenUtilities unnecessary -- the methods in TokenUtilities work with CharSequences in order to avoid toString() conversions. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@netbeans.apache.org For additional commands, e-mail: notifications-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists