Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4358,8 +4358,11 @@ protected ComputedHints computeHints(final NbTestCase test, final Rule hint, Str
}
}
if (HintsSettings.getSeverity(manager, ucr) == HintSeverity.CURRENT_LINE_WARNING) {
manager.setTestingRules(null, Collections.EMPTY_MAP, testHints, null);
manager.setTestingRules(null, testHints, testHints, null);
provider.computeSuggestions(manager, context, hints, caretOffset);
} else if(HintsSettings.getSeverity(manager, ucr) == HintSeverity.ERROR || HintsSettings.getSeverity(manager, ucr) == HintSeverity.WARNING) {
manager.setTestingRules(null, testHints, testHints, null);
provider.computeErrors(manager, context, hints, new ArrayList<Error>());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test, that all current tests invoking computeHints, potentially transitively, still work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not yet. I just thought that the pipes will show me the result and I just saw some failing tests of Latte. PHP where not triggert here at github inside my branch. I will just revert this change as you said and will try to implement a better logic into the HtmlHintsProvider as similiar as for PHP and JS.

} else {
manager.setTestingRules(null, testHints, null, null);
context.caretOffset = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,7 @@ MSG_SET_DEFAULT_HTML_VERSION=Change project default to {0}
MSG_FatalHtmlRuleName=Fatal Errors
MSG_FatalHtmlErrorAddendum=Further processing of the file may be significantly affected by this fatal error. Please fix the problem before continuing editing of this file!

AddMissingAltAttributeRule=Provide Text Alternatives
AddMissingAltAttributeRule_Desc=Find img/applet/area elements where no alt attribute is provided.

#MSG_HINT_GENERATE_REQUIRED_ATTRIBUTES=Generate required attributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.modules.html.editor.hints.other;

import java.awt.EventQueue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary import

import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary import

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean, they are unnecessary, when I change the logik, right? Because atm I need them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither Document, nor Source are used. I admit, that I only noticed that because NetBeans marked these:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those three are correct marked as not used, but your both other comments have different lines. That's why I'm asking. It was about the matcher, pattern, the exception, etc. That's why I was confused about it.

import org.netbeans.editor.BaseDocument;
import org.netbeans.modules.csl.api.Hint;
import org.netbeans.modules.csl.api.HintFix;
import org.netbeans.modules.csl.api.OffsetRange;
import org.netbeans.modules.html.editor.hints.HtmlRuleContext;
import org.netbeans.modules.html.editor.utils.HtmlTagContextUtils;
import org.netbeans.modules.parsing.api.Source;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary import

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above


/**
*
* @author Christian Lenz
*/
public class AddMissingAltAttributeHint extends Hint {

public AddMissingAltAttributeHint(HtmlRuleContext context, OffsetRange range) {
super(AddMissingAltAttributeRule.getInstance(),
AddMissingAltAttributeRule.getInstance().getDescription(),
context.getFile(),
range,
Collections.<HintFix>singletonList(new AddMissingAltAttributeHintFix(context, range)),
10);
}

private static class AddMissingAltAttributeHintFix implements HintFix {

private static final Logger LOGGER = Logger.getLogger(AddMissingAltAttributeHintFix.class.getSimpleName());

HtmlRuleContext context;
OffsetRange range;
Comment on lines +56 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be private and final


public AddMissingAltAttributeHintFix(HtmlRuleContext context, OffsetRange range) {
this.context = context;
this.range = range;
}

@Override
public String getDescription() {
return AddMissingAltAttributeRule.getInstance().getDisplayName();
}

@Override
public void implement() throws Exception {
BaseDocument document = (BaseDocument) context.getSnapshot().getSource().getDocument(true);
document.runAtomic(() -> {
try {
OffsetRange adjustedRange = HtmlTagContextUtils.adjustContextRange(document, range.getStart(), range.getEnd(), true);
String tagContent = document.getText(adjustedRange.getStart(), adjustedRange.getLength());

// Find last self-closing or non self-closing tag
Pattern closingTagPattern = Pattern.compile("(/?>)");
Matcher closingTagMatcher = closingTagPattern.matcher(tagContent);

if (closingTagMatcher.find()) {
int altInsertPosition = adjustedRange.getStart() + closingTagMatcher.start(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might lead to wrong results. Consider PHP with embedded HTML. The document could look like this:

<img src='demo.png' alt='<?php echo htmlspecialchars('x > y');?>' />

I would use the HTML token stream and either use the start of the closing token or, if that does not exist, the start of the last HTML token + length.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH, I didn't try PHP yet, will do it too. Thx for the hint. If I guess it correct, your example will not trigger the hint, because you already have the alt attribute. But yes It would be better to take the HTML token instead of just looking for the closing tag symbol with an regex.


// Check whether a space before alt is needed or not
boolean needsSpaceBefore = altInsertPosition == 0 || tagContent.charAt(closingTagMatcher.start(1) - 1) != ' ';
boolean isSelfClosing = closingTagMatcher.group(0).endsWith("/>");
String altAttribute = (needsSpaceBefore ? " " : "") + "alt=\"\"" + (isSelfClosing ? " " : ""); // NOI18N

document.insertString(altInsertPosition, altAttribute, null);
}
} catch (BadLocationException ex) {
LOGGER.log(Level.WARNING, "Invalid offset: {0}", ex.offsetRequested());
}
});
}

@Override
public boolean isSafe() {
return true;
}

@Override
public boolean isInteractive() {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.modules.html.editor.hints.other;

import java.io.IOException;
import java.util.List;
import org.netbeans.modules.csl.api.Hint;
import org.netbeans.modules.csl.api.HintSeverity;
import org.netbeans.modules.csl.api.RuleContext;
import org.netbeans.modules.html.editor.api.gsf.HtmlParserResult;
import org.netbeans.modules.html.editor.hints.HtmlRule;
import org.netbeans.modules.html.editor.hints.HtmlRuleContext;
import org.netbeans.modules.html.editor.lib.api.elements.ElementType;
import org.netbeans.modules.html.editor.lib.api.elements.ElementUtils;
import org.openide.util.Exceptions;

/**
*
* @author Christian Lenz
*/
public class AddMissingAltAttributeRule extends HtmlRule {

private final static AddMissingAltAttributeRule INSTANCE = new AddMissingAltAttributeRule();

private AddMissingAltAttributeRule() {
}

public static AddMissingAltAttributeRule getInstance() {
return INSTANCE;
}

@Override
public boolean appliesTo(RuleContext context) {
return true;
}

@Override
public boolean showInTasklist() {
return true;
}

@Override
public HintSeverity getDefaultSeverity() {
return HintSeverity.CURRENT_LINE_WARNING;
}

@Override
protected void run(HtmlRuleContext context, List<Hint> result) {
try {
HtmlParserResult parserResult = context.getHtmlParserResult();
AltAttributeVisitor visitor = new AltAttributeVisitor(this, context, result);

ElementUtils.visitChildren(parserResult.root(), visitor, ElementType.OPEN_TAG);
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.modules.html.editor.hints.other;

import java.io.IOException;
import java.util.*;
import org.netbeans.modules.csl.api.Hint;
import org.netbeans.modules.csl.api.OffsetRange;
import org.netbeans.modules.csl.api.Rule;
import org.netbeans.modules.html.editor.hints.HtmlRuleContext;
import org.netbeans.modules.html.editor.lib.api.elements.*;

/**
*
* @author Christian Lenz
*/
public class AltAttributeVisitor implements ElementVisitor {

private static final String ALT_ATTR = "alt"; // NOI18N

private final HtmlRuleContext context;
private final List<Hint> hints;

public AltAttributeVisitor(Rule rule, HtmlRuleContext context, List<Hint> hints) throws IOException {
this.context = context;
this.hints = hints;
}

@Override
public void visit(Element node) {
// We should only be invoked for opening tags
if (!(node instanceof OpenTag)) {
return;
}

// We are only interested in img, area, applet elements
String lowerCaseTag = node.id().toString().toLowerCase();
if (!(lowerCaseTag.equals("img") || lowerCaseTag.equals("area") || lowerCaseTag.equals("applet"))) { // NOI18N
return;
}

OpenTag ot = (OpenTag) node;
if (ot.getAttribute(ALT_ATTR) == null) {
hints.add(new AddMissingAltAttributeHint(context, new OffsetRange(node.from(), node.to())));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@
<file name="org-netbeans-modules-html-editor-hints-NotValidatedContent.instance">
<attr name="position" intvalue="190"/>
</file>
<file name="org-netbeans-modules-html-editor-hints-other-AddMissingAltAttributeRule.instance">
<attr name="position" intvalue="210"/>
</file>
<!-- the following hint 'Other' must be last in the hints list!!! -->
<file name="org-netbeans-modules-html-editor-hints-Other.instance">
<attr name="position" intvalue="99999"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.modules.html.editor.utils;

import java.util.concurrent.atomic.AtomicReference;
import javax.swing.text.Document;
import org.netbeans.api.html.lexer.HTMLTokenId;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.modules.csl.api.OffsetRange;
import org.netbeans.modules.html.editor.api.Utils;

/**
*
* @author Christian Lenz
*/
public final class HtmlTagContextUtils {

private HtmlTagContextUtils() {
}

public static OffsetRange adjustContextRange(final Document doc, final int from, final int to, final boolean beforeClosingToken) {
final AtomicReference<OffsetRange> ret = new AtomicReference<>();
ret.set(new OffsetRange(from, to)); //return the same pair by default
doc.render(() -> {
TokenSequence<HTMLTokenId> ts = Utils.getJoinedHtmlSequence(doc, from);

if (ts == null) {
//no html token sequence at the offset, try to
//TODO possibly try to travese the top level sequence backward
//and try to find an html embedding.
return;
}

Token<HTMLTokenId> openTag = Utils.findTagOpenToken(ts);

if (openTag == null) {
return;
}

int adjustedFrom = ts.offset();

//now try to find the tag's end
ts.move(to);
int adjustedTo = -1;
while (ts.moveNext()) {
Token<HTMLTokenId> t = ts.token();

if (t == null) {
return;
}

if (t.id() == HTMLTokenId.TAG_CLOSE_SYMBOL) {
adjustedTo = beforeClosingToken ? ts.offset() : ts.offset() + t.length();

break;
} else if (t.id() == HTMLTokenId.TEXT) {
//do not go too far - out of the tag
break;
}
}

if (adjustedTo == -1) {
return;
}

//we found the adjusted range
ret.set(new OffsetRange(adjustedFrom, adjustedTo));
});
return ret.get();
}
}
Loading
Loading