mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
extract fill paragraph action
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
package com.intellij.codeInsight.editorActions.fillParagraph;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.actions.BaseCodeInsightAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*
|
||||
* Action to re-flow paragraph to fit right margin.
|
||||
* Glues paragraph and then splits into lines with appropriate length
|
||||
*
|
||||
* The action came from Emacs users // PY-4775
|
||||
*/
|
||||
public class FillParagraphAction extends BaseCodeInsightAction {
|
||||
|
||||
@Override
|
||||
protected CodeInsightActionHandler getHandler() {
|
||||
return new Handler();
|
||||
}
|
||||
private static class Handler implements CodeInsightActionHandler {
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
|
||||
|
||||
ParagraphFillHandler paragraphFillHandler = LanguageFillParagraphExtension.INSTANCE.forLanguage(file.getLanguage());
|
||||
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element != null && paragraphFillHandler != null && paragraphFillHandler.isAvailableForFile(file)
|
||||
&& paragraphFillHandler.isAvailableForElement(element)) {
|
||||
|
||||
paragraphFillHandler.performOnElement(element, editor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidForFile(Project project, Editor editor, PsiFile file) {
|
||||
final ParagraphFillHandler handler =
|
||||
LanguageFillParagraphExtension.INSTANCE.forLanguage(file.getLanguage());
|
||||
return handler != null && handler.isAvailableForFile(file);
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.intellij.codeInsight.editorActions.fillParagraph;
|
||||
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class LanguageFillParagraphExtension extends LanguageExtension<ParagraphFillHandler> {
|
||||
|
||||
public static final String EP_NAME = "com.intellij.codeInsight.fillParagraph";
|
||||
public static final LanguageFillParagraphExtension INSTANCE = new LanguageFillParagraphExtension();
|
||||
|
||||
public LanguageFillParagraphExtension() {
|
||||
super(EP_NAME, new ParagraphFillHandler());
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package com.intellij.codeInsight.editorActions.fillParagraph;
|
||||
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.CharFilter;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines general re-flow paragraph functionality.
|
||||
* Serves plain text files.
|
||||
*
|
||||
* User : ktisha
|
||||
*/
|
||||
public class ParagraphFillHandler {
|
||||
|
||||
protected void performOnElement(@NotNull final PsiElement element, @NotNull final Editor editor) {
|
||||
final Document document = editor.getDocument();
|
||||
|
||||
final TextRange textRange = getTextRange(element, editor);
|
||||
final String text = textRange.substring(element.getContainingFile().getText());
|
||||
|
||||
final List<String> subStrings = StringUtil.split(text, "\n", true);
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String string : subStrings) {
|
||||
stringBuilder.append(StringUtil.trimStart(string.trim(), getPrefix(element))).append(" ");
|
||||
}
|
||||
final String replacementText = stringBuilder.toString();
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(element.getProject(), new Runnable() {
|
||||
public void run() {
|
||||
document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
getPrefix(element) + replacementText);
|
||||
final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(
|
||||
CodeStyleSettingsManager.getSettings(element.getProject()));
|
||||
codeFormatter.doWrapLongLinesIfNecessary(editor, element.getProject(), document,
|
||||
textRange.getStartOffset(),
|
||||
textRange.getStartOffset() + replacementText.length() + 1);
|
||||
}
|
||||
}, null, document);
|
||||
|
||||
}
|
||||
|
||||
private TextRange getTextRange(@NotNull final PsiElement element, @NotNull final Editor editor) {
|
||||
int startOffset = getStartOffset(element, editor);
|
||||
int endOffset = getEndOffset(element, editor);
|
||||
return TextRange.create(startOffset, endOffset);
|
||||
}
|
||||
|
||||
private int getStartOffset(@NotNull final PsiElement element, @NotNull final Editor editor) {
|
||||
if (element instanceof PsiComment) {
|
||||
final PsiElement firstCommentElement = getFirstCommentElement(element);
|
||||
return firstCommentElement != null? firstCommentElement.getTextRange().getStartOffset()
|
||||
: element.getTextRange().getStartOffset();
|
||||
}
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final int elementTextOffset = element.getTextOffset();
|
||||
final Document document = editor.getDocument();
|
||||
int lineNumber = document.getLineNumber(offset);
|
||||
|
||||
while (lineNumber != document.getLineNumber(elementTextOffset)) {
|
||||
final String text = document.getText(TextRange.create(document.getLineStartOffset(lineNumber),
|
||||
document.getLineEndOffset(lineNumber)));
|
||||
if (StringUtil.isEmptyOrSpaces(text)) {
|
||||
break;
|
||||
}
|
||||
lineNumber -= 1;
|
||||
}
|
||||
final int lineStartOffset = document.getLineStartOffset(lineNumber + 1);
|
||||
final String lineText = document
|
||||
.getText(TextRange.create(lineStartOffset, document.getLineEndOffset(lineNumber + 1)));
|
||||
int shift = StringUtil.findFirst(lineText, CharFilter.NOT_WHITESPACE_FILTER);
|
||||
|
||||
return lineStartOffset + shift;
|
||||
}
|
||||
|
||||
private int getEndOffset(@NotNull final PsiElement element, @NotNull final Editor editor) {
|
||||
if (element instanceof PsiComment) {
|
||||
final PsiElement next = getLastCommentElement(element);
|
||||
return next != null? next.getTextRange().getEndOffset()
|
||||
: element.getTextRange().getEndOffset();
|
||||
}
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final int elementTextOffset = element.getTextRange().getEndOffset();
|
||||
final Document document = editor.getDocument();
|
||||
int lineNumber = document.getLineNumber(offset);
|
||||
|
||||
while (lineNumber != document.getLineNumber(elementTextOffset)) {
|
||||
final String text = document.getText(TextRange.create(document.getLineStartOffset(lineNumber),
|
||||
document.getLineEndOffset(lineNumber)));
|
||||
if (StringUtil.isEmptyOrSpaces(text))
|
||||
break;
|
||||
lineNumber += 1;
|
||||
}
|
||||
return document.getLineEndOffset(lineNumber - 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement getFirstCommentElement(@NotNull final PsiElement element) {
|
||||
PsiElement prevSibling = element.getPrevSibling();
|
||||
PsiElement result = element;
|
||||
while (prevSibling instanceof PsiComment || (prevSibling instanceof PsiWhiteSpace &&
|
||||
StringUtil.countChars(prevSibling.getText(), '\n') <= 1)) {
|
||||
final String text = prevSibling.getText();
|
||||
if (prevSibling instanceof PsiComment && StringUtil.isEmptyOrSpaces(
|
||||
StringUtil.trimStart(text.trim(), getPrefix(element)))) {
|
||||
break;
|
||||
}
|
||||
if (prevSibling instanceof PsiComment)
|
||||
result = prevSibling;
|
||||
prevSibling = prevSibling.getPrevSibling();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement getLastCommentElement(@NotNull final PsiElement element) {
|
||||
PsiElement nextSibling = element.getNextSibling();
|
||||
PsiElement result = element;
|
||||
while (nextSibling instanceof PsiComment || (nextSibling instanceof PsiWhiteSpace &&
|
||||
StringUtil.countChars(nextSibling.getText(), '\n') <= 1)) {
|
||||
final String text = nextSibling.getText();
|
||||
if (nextSibling instanceof PsiComment && StringUtil.isEmptyOrSpaces(
|
||||
StringUtil.trimStart(text.trim(), getPrefix(element)))) {
|
||||
break;
|
||||
}
|
||||
if (nextSibling instanceof PsiComment)
|
||||
result = nextSibling;
|
||||
nextSibling = nextSibling.getNextSibling();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean isAvailableForElement(@Nullable final PsiElement element) {
|
||||
return element != null;
|
||||
}
|
||||
|
||||
protected boolean isAvailableForFile(@Nullable final PsiFile psiFile) {
|
||||
return psiFile instanceof PsiPlainTextFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected String getPrefix(@NotNull final PsiElement element) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1354,3 +1354,6 @@ action.Diff.UpdatedFiles.description=Show diff with version before update
|
||||
|
||||
action.TabList.text=Show All Tabs
|
||||
action.TabList.description=Show dropdown with the list of all tabs in single-row tab layout
|
||||
|
||||
action.FillParagraph.text=Fill paragraph...
|
||||
action.FillParagraph.description=Reformat string literal or comment to fit maximum width (usually 80)
|
||||
|
||||
@@ -378,6 +378,7 @@
|
||||
<extensionPoint name="colorAndFontDescriptorProvider" interface="com.intellij.openapi.options.colors.ColorAndFontDescriptorsProvider"/>
|
||||
|
||||
<extensionPoint name="codeInsight.parameterInfo" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
|
||||
<extensionPoint name="codeInsight.fillParagraph" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
|
||||
<extensionPoint name="editorOptionsProvider" beanClass="com.intellij.application.options.editor.EditorOptionsProviderEP"/>
|
||||
<extensionPoint name="fileTypeIndentOptionsProvider" interface="com.intellij.psi.codeStyle.FileTypeIndentOptionsProvider"/>
|
||||
<extensionPoint name="referenceImporter" interface="com.intellij.codeInsight.daemon.ReferenceImporter"/>
|
||||
|
||||
@@ -290,6 +290,7 @@
|
||||
<action id="MembersPullUp" class="com.intellij.refactoring.actions.PullUpAction"/>
|
||||
<action id="MemberPushDown" class="com.intellij.refactoring.actions.PushDownAction"/>
|
||||
<add-to-group group-id="MainMenu" anchor="after" relative-to-action="CodeMenu"/>
|
||||
<action id="FillParagraph" class="com.intellij.codeInsight.editorActions.fillParagraph.FillParagraphAction"/>
|
||||
</group>
|
||||
|
||||
<!-- Run -->
|
||||
|
||||
Reference in New Issue
Block a user