void (@NotNull PsiFile file, Results annotationResult, @NotNull AnnotationHolder holder) { if (annotationResult == null || !file.isValid()) return; final String text = file.getText(); Project project = file.getProject(); final Document document = PsiDocumentManager.getInstance(project).getDocument(file); for (Problem problem : annotationResult.problems) { final int line = problem.myLine - 1; final int column = problem.myColumn - 1; int offset; if (document != null) { offset = line >= document.getLineCount() ? document.getTextLength() - 1 : document.getLineStartOffset(line) + column; } else { offset = StringUtil.lineColToOffset(text, line, column); } PsiElement problemElement = file.findElementAt(offset); // E3xx - blank lines warnings if (!(problemElement instanceof PsiWhiteSpace) && problem.myCode.startsWith("E3")) { final PsiElement elementBefore = file.findElementAt(Math.max(0, offset - 1)); if (elementBefore instanceof PsiWhiteSpace) { problemElement = elementBefore; } } // W292 no newline at end of file if (problemElement == null && document != null && offset == document.getTextLength() && problem.myCode.equals("W292")) { problemElement = file.findElementAt(Math.max(0, offset - 1)); } if (ignoreDueToSettings(file, problem, problemElement) || ignoredDueToProblemSuppressors(problem, file, problemElement) || ignoredDueToNoqaComment(problem, file, document)) { continue; } if (problemElement != null) { TextRange problemRange = problemElement.getTextRange(); // Multi-line warnings are shown only in the gutter and it's not the desired behavior from the usability point of view. // So we register it only on that line where pycodestyle.py found the problem originally. if (crossesLineBoundary(document, text, problemRange)) { final int lineEndOffset; if (document != null) { lineEndOffset = line >= document.getLineCount() ? document.getTextLength() - 1 : document.getLineEndOffset(line); } else { lineEndOffset = StringUtil.lineColToOffset(text, line + 1, 0) - 1; } if (offset > lineEndOffset) { // PSI/document don't match, don't try to highlight random places continue; } problemRange = new TextRange(offset, lineEndOffset); } @NonNls final String message = "PEP 8: " + problem.myCode + " " + problem.myDescription; HighlightSeverity severity; if (annotationResult.level == HighlightDisplayLevel.ERROR) { severity = HighlightSeverity.ERROR; } else if (annotationResult.level == HighlightDisplayLevel.WARNING) { severity = HighlightSeverity.WARNING; } else { severity = HighlightSeverity.WEAK_WARNING; } IntentionAction fix; boolean universal; if (problem.myCode.equals("E401")) { fix = new OptimizeImportsQuickFix(); universal = true; } else if (problem.myCode.equals("W391")) { fix = new RemoveTrailingBlankLinesFix(); universal = true; } else if (problem.myCode.equals("E501")) { fix = new PyFillParagraphFix(); universal = false; } else { fix = new ReformatFix(); universal = true; } AnnotationBuilder builder = holder.newAnnotation(severity, message).range(problemRange); if (universal) { builder = builder.newFix(fix).universal().registerFix(); } else { builder = builder.withFix(fix); } builder .withFix(new IgnoreErrorFix(problem.myCode)) .withFix(new CustomEditInspectionToolsSettingsAction(HighlightDisplayKey.find(PyPep8Inspection.INSPECTION_SHORT_NAME), () -> PyBundle.message("QFIX.pep8.edit.inspection.profile.setting"))).create(); } } }