Skip to content

Commit 07a65b2

Browse files
BananeweizenCalixte
authored andcommitted
Online help for problem markers
* Register a problem marker help provider. * Calculate a context help topic for each marker and dynamically forward it to the original online help of the related check. For the end user, pressing F1 on a marker has the result of opening the integrated Eclipse help and showing the checkstyle problem description online. Fixes #568.
1 parent 66402bf commit 07a65b2

File tree

6 files changed

+221
-9
lines changed

6 files changed

+221
-9
lines changed

net.sf.eclipsecs.core/src/net/sf/eclipsecs/core/builder/CheckstyleMarker.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
package net.sf.eclipsecs.core.builder;
2222

23+
import org.eclipse.core.resources.IMarker;
24+
import org.eclipse.core.runtime.CoreException;
25+
2326
import net.sf.eclipsecs.core.CheckstylePlugin;
2427

2528
/**
@@ -45,6 +48,15 @@ public final class CheckstyleMarker {
4548
public static final String INFO_TYPE = CheckstylePlugin.PLUGIN_ID + ".info"; //$NON-NLS-1$
4649

4750
private CheckstyleMarker() {
48-
// NOOP
51+
// utility class
52+
}
53+
54+
public static boolean isCheckstyleMarker(IMarker marker) {
55+
try {
56+
return CheckstyleMarker.MARKER_ID.equals(marker.getType());
57+
} catch (CoreException ex) {
58+
// ignore
59+
}
60+
return false;
4961
}
5062
}

net.sf.eclipsecs.core/src/net/sf/eclipsecs/core/config/meta/MetadataFactory.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ private static RuleMetadata createRuleMetadata(ModuleDetails moduleDetails) {
176176
final String ruleDescription = sThirdPartyRuleGroupMap.get(lookupKey).get("description");
177177
final int rulePriority = Integer.parseInt(sThirdPartyRuleGroupMap.get(lookupKey)
178178
.get("priority"));
179-
group = new RuleGroupMetadata(ruleGroupName, ruleDescription, false, rulePriority);
179+
group = new RuleGroupMetadata(ruleGroupName, ruleGroupName, ruleDescription, false, rulePriority);
180180
sRuleGroupMetadata.put(ruleGroupName, group);
181181
}
182182
}
@@ -534,9 +534,8 @@ private static void doInitialization() throws CheckstylePluginException {
534534
try (InputStream metadataStream = classLoader.getResourceAsStream(metadataFile)) {
535535

536536
if (metadataStream != null) {
537-
538537
ResourceBundle metadataBundle = getMetadataI18NBundle(metadataFile, classLoader);
539-
parseMetadata(metadataStream, metadataBundle);
538+
parseMetadata(metadataStream, metadataBundle, groupId(metadataFile));
540539
}
541540
} catch (DocumentException | IOException ex) {
542541
CheckstyleLog.log(ex, "Could not read metadata " + metadataFile); //$NON-NLS-1$
@@ -546,6 +545,19 @@ private static void doInitialization() throws CheckstylePluginException {
546545
loadRuleMetadata();
547546
}
548547

548+
/**
549+
* @param metadataFile
550+
* @return
551+
*/
552+
private static String groupId(String metadataFile) {
553+
var start = metadataFile.indexOf("checks/") + 7;
554+
var end = metadataFile.lastIndexOf("/");
555+
if (start >= end) {
556+
return "";
557+
}
558+
return metadataFile.substring(start, end);
559+
}
560+
549561
/**
550562
* Creates RuleMetadata.
551563
*/
@@ -648,7 +660,7 @@ private static ResourceBundle getMetadataI18NBundle(String metadataFile,
648660
}
649661
}
650662

651-
private static void parseMetadata(InputStream metadataStream, ResourceBundle metadataBundle)
663+
private static void parseMetadata(InputStream metadataStream, ResourceBundle metadataBundle, String groupId)
652664
throws DocumentException, CheckstylePluginException {
653665

654666
SAXReader reader = new SAXReader();
@@ -660,7 +672,7 @@ private static void parseMetadata(InputStream metadataStream, ResourceBundle met
660672

661673
for (Element groupEl : groupElements) {
662674

663-
String groupName = groupEl.attributeValue(XMLTags.NAME_TAG).trim();
675+
var groupName = groupEl.attributeValue(XMLTags.NAME_TAG).trim();
664676
groupName = localize(groupName, metadataBundle);
665677

666678
// process description
@@ -680,7 +692,7 @@ private static void parseMetadata(InputStream metadataStream, ResourceBundle met
680692
priority = Integer.MAX_VALUE;
681693
}
682694

683-
group = new RuleGroupMetadata(groupName, groupDesc, hidden, priority);
695+
group = new RuleGroupMetadata(groupId, groupName, groupDesc, hidden, priority);
684696
sRuleGroupMetadata.put(groupName, group);
685697
}
686698

net.sf.eclipsecs.core/src/net/sf/eclipsecs/core/config/meta/RuleGroupMetadata.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
*/
2929
public class RuleGroupMetadata {
3030

31+
/**
32+
* group id, used for online help URL calculation
33+
*/
34+
private final String mGroupId;
35+
3136
/** The name of the group. */
3237
private String mGroupName;
3338

@@ -43,7 +48,8 @@ public class RuleGroupMetadata {
4348
/** The list of modules belonging to the group. */
4449
private List<RuleMetadata> mRuleMetadata = new LinkedList<>();
4550

46-
RuleGroupMetadata(String groupName, String groupDesc, boolean hidden, int priority) {
51+
RuleGroupMetadata(String groupId, String groupName, String groupDesc, boolean hidden, int priority) {
52+
mGroupId = groupId;
4753
mGroupName = groupName;
4854
mDescription = groupDesc;
4955
mIsHidden = hidden;
@@ -94,4 +100,11 @@ public int getPriority() {
94100
public final List<RuleMetadata> getRuleMetadata() {
95101
return mRuleMetadata;
96102
}
103+
104+
/**
105+
* @return the group id
106+
*/
107+
public String getGroupId() {
108+
return mGroupId;
109+
}
97110
}

net.sf.eclipsecs.ui/META-INF/MANIFEST.MF

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Bundle-ActivationPolicy: lazy
99
Require-Bundle: net.sf.eclipsecs.core,
1010
org.eclipse.core.expressions,
1111
org.eclipse.ui.workbench,
12-
org.eclipse.jface
12+
org.eclipse.jface,
13+
org.eclipse.help;bundle-version="3.9.0"
1314
Bundle-RequiredExecutionEnvironment: JavaSE-11
1415
Export-Package: net.sf.eclipsecs.ui,
1516
net.sf.eclipsecs.ui.properties.filter,

net.sf.eclipsecs.ui/plugin.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,5 +610,18 @@
610610
module="UpperEllCheck"
611611
class="net.sf.eclipsecs.ui.quickfixes.misc.UpperEllQuickfix">
612612
</quickfix>
613+
</extension>
614+
<extension
615+
point="org.eclipse.ui.ide.markerHelp">
616+
<markerHelp
617+
helpContextProvider="net.sf.eclipsecs.ui.quickfixes.MarkerHelpContextProvider"
618+
markerType="net.sf.eclipsecs.core.CheckstyleMarker"
619+
matchChildren="false"></markerHelp>
620+
</extension>
621+
<extension
622+
point="org.eclipse.help.contexts">
623+
<contextProvider
624+
class="net.sf.eclipsecs.ui.quickfixes.MarkerHelpContextProvider">
625+
</contextProvider>
613626
</extension>
614627
</plugin>
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//============================================================================
2+
//
3+
// Copyright (C) 2003-2023 the original author or authors.
4+
//
5+
// This library is free software; you can redistribute it and/or
6+
// modify it under the terms of the GNU Lesser General Public
7+
// License as published by the Free Software Foundation; either
8+
// version 2.1 of the License, or (at your option) any later version.
9+
//
10+
// This library is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
// Lesser General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Lesser General Public
16+
// License along with this library; if not, write to the Free Software
17+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
//
19+
//============================================================================
20+
21+
package net.sf.eclipsecs.ui.quickfixes;
22+
23+
import org.apache.commons.lang3.StringUtils;
24+
import org.eclipse.core.resources.IMarker;
25+
import org.eclipse.ui.IMarkerHelpContextProvider;
26+
27+
import net.sf.eclipsecs.core.builder.CheckstyleMarker;
28+
import net.sf.eclipsecs.core.config.meta.MetadataFactory;
29+
30+
import org.eclipse.help.AbstractContextProvider;
31+
import org.eclipse.help.IContext;
32+
import org.eclipse.help.IHelpResource;
33+
34+
/**
35+
* Provides context help for checkstyle markers.
36+
*/
37+
public class MarkerHelpContextProvider extends AbstractContextProvider
38+
implements IMarkerHelpContextProvider {
39+
40+
/**
41+
* package of the regexp checks
42+
*/
43+
private static final String REGEXP_PACKAGE = "com.puppycrawl.tools.checkstyle.checks.regexp.";
44+
/**
45+
* suffix of all standard check implementations
46+
*/
47+
private static final String CHECK_SUFFIX = "Check";
48+
/**
49+
* Common prefix for all Checkstyle marker help contexts. Must be same as plugin id and must end
50+
* with a dot.
51+
*/
52+
private static final String PLUGIN_PREFIX = "net.sf.eclipsecs.ui" + ".";
53+
54+
@Override
55+
public String getHelpContextForMarker(IMarker marker) {
56+
String module = getModule(marker);
57+
if (!module.endsWith(CHECK_SUFFIX)) {
58+
return null;
59+
}
60+
return PLUGIN_PREFIX + StringUtils.removeEnd(StringUtils.substringAfterLast(module, '.'), CHECK_SUFFIX);
61+
}
62+
63+
private String getModule(IMarker marker) {
64+
return marker.getAttribute(CheckstyleMarker.MODULE_NAME, StringUtils.EMPTY);
65+
}
66+
67+
@Override
68+
public boolean hasHelpContextForMarker(IMarker marker) {
69+
if (!CheckstyleMarker.isCheckstyleMarker(marker)) {
70+
return false;
71+
}
72+
if (getModule(marker).startsWith(REGEXP_PACKAGE)) {
73+
// regex rules don't provide useful help for understanding and fixing an issue
74+
return false;
75+
}
76+
return true;
77+
}
78+
79+
@Override
80+
public IContext getContext(String id, String locale) {
81+
var moduleName = StringUtils.substringAfter(id, PLUGIN_PREFIX);
82+
return new CheckstyleHelpContext(moduleName);
83+
}
84+
85+
@Override
86+
public String[] getPlugins() {
87+
return new String[] { "net.sf.eclipsecs.ui" };
88+
}
89+
90+
/**
91+
* @param moduleName
92+
* module name
93+
* @return online help URL
94+
*/
95+
public static String getOnlineHelp(String moduleName) {
96+
var metadata = MetadataFactory.getRuleMetadata(moduleName);
97+
if (metadata == null) {
98+
return null;
99+
}
100+
var group = metadata.getGroup().getGroupId().toLowerCase();
101+
// some web pages are different to the packages in Checkstyle
102+
if ("indentation".equals(group)) {
103+
group = "misc";
104+
}
105+
var file = moduleName.toLowerCase();
106+
return "https://checkstyle.org/checks/" + group + "/" + file + ".html#" + moduleName;
107+
}
108+
109+
/**
110+
* Help topic forwarding to the online help
111+
*/
112+
private static final class CheckstyleHelpTopic implements IHelpResource {
113+
private final String moduleName;
114+
115+
/**
116+
* @param moduleName
117+
* module name
118+
*/
119+
private CheckstyleHelpTopic(String moduleName) {
120+
this.moduleName = moduleName;
121+
}
122+
123+
@Override
124+
public String getLabel() {
125+
return null;
126+
}
127+
128+
@Override
129+
public String getHref() {
130+
return getOnlineHelp(moduleName);
131+
}
132+
}
133+
134+
/**
135+
* Dynamically created help context for a checkstyle marker
136+
*/
137+
private static final class CheckstyleHelpContext implements IContext {
138+
private final String moduleName;
139+
140+
/**
141+
* @param moduleName
142+
*/
143+
private CheckstyleHelpContext(String moduleName) {
144+
this.moduleName = moduleName;
145+
}
146+
147+
@Override
148+
public IHelpResource[] getRelatedTopics() {
149+
IHelpResource helpResource = new CheckstyleHelpTopic(moduleName);
150+
return new IHelpResource[] { helpResource };
151+
}
152+
153+
@Override
154+
public String getText() {
155+
// must be null, because the help manager will only show the URL immediately when no text is
156+
// defined
157+
return null;
158+
}
159+
}
160+
161+
}

0 commit comments

Comments
 (0)