diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 0469fc231..4fc37f595 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -11,6 +11,7 @@ This document provides a high-level view of the changes introduced by release. - Update docs and templates to recommend an absolute path for the `pdf-themesdir` (#1750) - When rendering the preview for Antora, automatically switch to highlight.js syntax highlighting (#1736) +- Make wrap-on-typing work for AsciiDoc without chopping an existing line into small chunks (#1653) === 0.43.4 diff --git a/src/main/java/org/asciidoc/intellij/formatting/AsciiDocEnterHandlerDelegate.java b/src/main/java/org/asciidoc/intellij/formatting/AsciiDocEnterHandlerDelegate.java new file mode 100644 index 000000000..c47d01789 --- /dev/null +++ b/src/main/java/org/asciidoc/intellij/formatting/AsciiDocEnterHandlerDelegate.java @@ -0,0 +1,41 @@ +package org.asciidoc.intellij.formatting; + +import com.intellij.codeInsight.editorActions.AutoHardWrapHandler; +import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiFile; +import org.asciidoc.intellij.file.AsciiDocFileType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * This handler copies the auto-wrap-in-progress-flag from the handler-specific data context to the editor's data-content, + * as the handler-specific data context is not available in the {@link AsciiDocLineIndentProvider}. + * + * @author Alexander Schwartz + */ +public class AsciiDocEnterHandlerDelegate implements EnterHandlerDelegate { + @Override + public Result preprocessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull Ref caretOffset, @NotNull Ref caretAdvance, @NotNull DataContext dataContext, @Nullable EditorActionHandler originalHandler) { + if (file.getFileType() == AsciiDocFileType.INSTANCE) { + if (DataManager.getInstance().loadFromDataContext(dataContext, AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY) == Boolean.TRUE) { + editor.putUserData(AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY, true); + } + } + return EnterHandlerDelegate.Result.Continue; + } + + @Override + public Result postProcessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull DataContext dataContext) { + if (file.getFileType() == AsciiDocFileType.INSTANCE) { + if (editor.getUserData(AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY) == Boolean.TRUE) { + editor.putUserData(AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY, null); + } + } + return EnterHandlerDelegate.Result.Continue; + } +} diff --git a/src/main/java/org/asciidoc/intellij/formatting/AsciiDocLineIndentProvider.java b/src/main/java/org/asciidoc/intellij/formatting/AsciiDocLineIndentProvider.java new file mode 100644 index 000000000..81c07fb32 --- /dev/null +++ b/src/main/java/org/asciidoc/intellij/formatting/AsciiDocLineIndentProvider.java @@ -0,0 +1,34 @@ +package org.asciidoc.intellij.formatting; + +import com.intellij.codeInsight.editorActions.AutoHardWrapHandler; +import com.intellij.lang.Language; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; +import com.intellij.psi.impl.source.codeStyle.lineIndent.FormatterBasedLineIndentProvider; +import org.asciidoc.intellij.AsciiDocLanguage; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * When auto-wrapping of lines in in-progress, don't adjust the line's indent to avoid confusing the logic in + * {@link AutoHardWrapHandler#wrapLineIfNecessary}. + * + * @author Alexander Schwartz + */ +public class AsciiDocLineIndentProvider extends FormatterBasedLineIndentProvider { + + @Override + public @Nullable String getLineIndent(@NotNull Project project, @NotNull Editor editor, @Nullable Language language, int offset) { + if (editor.getUserData(AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY) == Boolean.TRUE) { + return LineIndentProvider.DO_NOT_ADJUST; + } else { + return super.getLineIndent(project, editor, language, offset); + } + } + + @Override + public boolean isSuitableFor(@Nullable Language language) { + return language == AsciiDocLanguage.INSTANCE; + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index dd3b7d19e..6a3b7aa96 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -201,6 +201,7 @@ + @@ -221,6 +222,7 @@ + diff --git a/src/test/java/org/asciidoc/intellij/editor/AbstractWrapTest.java b/src/test/java/org/asciidoc/intellij/editor/AbstractWrapTest.java new file mode 100644 index 000000000..1bb42487c --- /dev/null +++ b/src/test/java/org/asciidoc/intellij/editor/AbstractWrapTest.java @@ -0,0 +1,69 @@ +package org.asciidoc.intellij.editor; + +import com.intellij.application.options.CodeStyle; +import com.intellij.openapi.editor.impl.view.FontLayoutService; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.testFramework.LightPlatformCodeInsightTestCase; +import com.intellij.testFramework.MockFontLayoutService; +import com.intellij.util.PathUtil; +import org.jetbrains.annotations.NotNull; + +/** + * This copied parts from by com.intellij.codeInsight.wrap.AbstractWrapTest and its base classes. + * + * @author Alexander Schwartz + */ +public abstract class AbstractWrapTest extends LightPlatformCodeInsightTestCase { + + @SuppressWarnings("checkstyle:VisibilityModifier") + protected CodeStyleSettings mySettings; + + protected void checkWrapOnTyping(@NotNull FileType fileType, + @NotNull String textToType, + @NotNull String initial, + @NotNull String expected) { + String name = "test." + fileType.getDefaultExtension(); + configureFromFileText(name, initial); + assertFileTypeResolved(fileType, name); + for (char c : textToType.toCharArray()) { + type(c); + } + checkResultByText(expected); + } + + public static final int TEST_CHAR_WIDTH = 10; // char width matches the one in EditorTestUtil.configureSoftWraps + public static final int TEST_LINE_HEIGHT = 10; + public static final int TEST_DESCENT = 2; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mySettings = CodeStyle.createTestSettings(CodeStyle.getSettings(getProject())); + mySettings.WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN = true; + + CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(mySettings); + FontLayoutService.setInstance(new MockFontLayoutService(TEST_CHAR_WIDTH, TEST_LINE_HEIGHT, TEST_DESCENT)); + } + + @Override + protected void tearDown() throws Exception { + try { + FontLayoutService.setInstance(null); + } catch (Throwable e) { + addSuppressedException(e); + } finally { + super.tearDown(); + } + } + + protected static void assertFileTypeResolved(@NotNull FileType type, @NotNull String path) { + String name = PathUtil.getFileName(path); + FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(name); + assertEquals(type + " file type must be in this test classpath, but only " + fileType + " was found by '" + + name + "' file name (with default extension '" + fileType.getDefaultExtension() + "')", type, fileType); + } + +} diff --git a/src/test/java/org/asciidoc/intellij/editor/AsciiDocWrapTest.java b/src/test/java/org/asciidoc/intellij/editor/AsciiDocWrapTest.java new file mode 100644 index 000000000..4bdc50e16 --- /dev/null +++ b/src/test/java/org/asciidoc/intellij/editor/AsciiDocWrapTest.java @@ -0,0 +1,24 @@ +package org.asciidoc.intellij.editor; + +import org.asciidoc.intellij.file.AsciiDocFileType; + +/** + * Testing auto-wrapping when typing. + * + * @author Alexander Schwartz + */ +public class AsciiDocWrapTest extends AbstractWrapTest { + + public void testWrapAfterSpaceOnMargin() { + mySettings.setDefaultRightMargin(10); + // this will wrap three additional characters as it is not a plain text editor. + checkWrapOnTyping(AsciiDocFileType.INSTANCE, "a", "text text ", "text \ntext a"); + } + + public void testWrapWithNextLine() { + mySettings.setDefaultRightMargin(20); + // this will wrap three additional characters as it is not a plain text editor. This + checkWrapOnTyping(AsciiDocFileType.INSTANCE, "1234567890", "else if else if else\nold text", "else 1234567890if \nelse if else\nold text"); + } + +}