/** * We want to treat comments specially in a way to skip comment prefix on line indent calculation. * * <p>Example: * * <pre> * if (true) { * int i1; * // int i2; * int i3; * } * </pre> * * We want to use 'int i2;' start offset as the third line indent (though it has non-white space * comment prefix (//) at the first column. * * <p>This method tries to parse comment prefix for the language implied by the given comment * type. It uses {@link #NO_COMMENT_INFO_MARKER} as an indicator that that information is * unavailable * * @param commentType target comment type * @return prefix of the comment denoted by the given type if any; {@link #NO_COMMENT_INFO_MARKER} * otherwise */ @NotNull private static String getCommentPrefix(@NotNull IElementType commentType) { Commenter c = LanguageCommenters.INSTANCE.forLanguage(commentType.getLanguage()); if (!(c instanceof CodeDocumentationAwareCommenter)) { COMMENT_PREFIXES.put(commentType, NO_COMMENT_INFO_MARKER); return NO_COMMENT_INFO_MARKER; } CodeDocumentationAwareCommenter commenter = (CodeDocumentationAwareCommenter) c; IElementType lineCommentType = commenter.getLineCommentTokenType(); String lineCommentPrefix = commenter.getLineCommentPrefix(); if (lineCommentType != null) { COMMENT_PREFIXES.put( lineCommentType, lineCommentPrefix == null ? NO_COMMENT_INFO_MARKER : lineCommentPrefix); } IElementType blockCommentType = commenter.getBlockCommentTokenType(); String blockCommentPrefix = commenter.getBlockCommentPrefix(); if (blockCommentType != null) { COMMENT_PREFIXES.put( blockCommentType, blockCommentPrefix == null ? NO_COMMENT_INFO_MARKER : blockCommentPrefix); } IElementType docCommentType = commenter.getDocumentationCommentTokenType(); String docCommentPrefix = commenter.getDocumentationCommentPrefix(); if (docCommentType != null) { COMMENT_PREFIXES.put( docCommentType, docCommentPrefix == null ? NO_COMMENT_INFO_MARKER : docCommentPrefix); } COMMENT_PREFIXES.putIfAbsent(commentType, NO_COMMENT_INFO_MARKER); return COMMENT_PREFIXES.get(commentType); }
public static boolean isCommentTextElement(final PsiElement element) { final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(element.getLanguage()); if (commenter instanceof CodeDocumentationAwareCommenterEx) { final CodeDocumentationAwareCommenterEx commenterEx = (CodeDocumentationAwareCommenterEx) commenter; if (commenterEx.isDocumentationCommentText(element)) return true; if (element instanceof PsiComment && commenterEx.isDocumentationComment((PsiComment) element)) return false; } return isComment(element); }
@Override public Result preprocessEnter( @NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final Ref<Integer> caretOffsetRef, @NotNull final Ref<Integer> caretAdvance, @NotNull final DataContext dataContext, final EditorActionHandler originalHandler) { int caretOffset = caretOffsetRef.get().intValue(); PsiElement psiAtOffset = file.findElementAt(caretOffset); if (psiAtOffset != null && psiAtOffset.getTextOffset() < caretOffset) { ASTNode token = psiAtOffset.getNode(); Document document = editor.getDocument(); CharSequence text = document.getText(); final Language language = psiAtOffset.getLanguage(); final Commenter languageCommenter = LanguageCommenters.INSTANCE.forLanguage(language); final CodeDocumentationAwareCommenter commenter = languageCommenter instanceof CodeDocumentationAwareCommenter ? (CodeDocumentationAwareCommenter) languageCommenter : null; if (commenter != null && token.getElementType() == commenter.getLineCommentTokenType()) { final int offset = CharArrayUtil.shiftForward(text, caretOffset, " \t"); if (offset < document.getTextLength() && text.charAt(offset) != '\n') { String prefix = commenter.getLineCommentPrefix(); assert prefix != null : "Line Comment type is set but Line Comment Prefix is null!"; if (!StringUtil.startsWith(text, offset, prefix)) { if (text.charAt(caretOffset) != ' ' && !prefix.endsWith(" ")) { prefix += " "; } document.insertString(caretOffset, prefix); return Result.Default; } else { int afterPrefix = offset + prefix.length(); if (afterPrefix < document.getTextLength() && text.charAt(afterPrefix) != ' ') { document.insertString(afterPrefix, " "); // caretAdvance.set(0); } caretOffsetRef.set(offset); } return Result.Default; } } } return Result.Continue; }
private static void process( @NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final Project project, int offset) { PsiElement elementAtOffset = file.findElementAt(offset); if (elementAtOffset == null) { return; } Language language = PsiUtilCore.getLanguageAtOffset(file, offset); final CodeDocumentationProvider docProvider; final DocumentationProvider langDocumentationProvider = LanguageDocumentation.INSTANCE.forLanguage(language); if (langDocumentationProvider instanceof CompositeDocumentationProvider) { docProvider = ((CompositeDocumentationProvider) langDocumentationProvider) .getFirstCodeDocumentationProvider(); } else if (langDocumentationProvider instanceof CodeDocumentationProvider) { docProvider = (CodeDocumentationProvider) langDocumentationProvider; } else { docProvider = null; } if (docProvider == null) { return; } final Pair<PsiElement, PsiComment> pair = docProvider.parseContext(elementAtOffset); if (pair == null) { return; } Commenter c = LanguageCommenters.INSTANCE.forLanguage(language); if (!(c instanceof CodeDocumentationAwareCommenter)) { return; } final CodeDocumentationAwareCommenter commenter = (CodeDocumentationAwareCommenter) c; final Runnable task; if (pair.second == null || pair.second.getTextRange().isEmpty()) { task = new Runnable() { @Override public void run() { generateComment(pair.first, editor, docProvider, commenter, project); } }; } else { final DocCommentFixer fixer = DocCommentFixer.EXTENSION.forLanguage(language); if (fixer == null) { return; } else { task = new Runnable() { @Override public void run() { fixer.fixComment(project, editor, pair.second); } }; } } final Runnable command = new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(task); } }; CommandProcessor.getInstance().executeCommand(project, command, "Fix documentation", null); }