diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorHeadingSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorHeadingSample.java index 915343f5..492d6a80 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorHeadingSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorHeadingSample.java @@ -5,7 +5,7 @@ import java.util.concurrent.Executors; import io.noties.markwon.Markwon; import io.noties.markwon.app.sample.Tags; import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample; -import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler; +import io.noties.markwon.editor.handler.HeadingEditHandler; import io.noties.markwon.editor.MarkwonEditor; import io.noties.markwon.editor.MarkwonEditorTextWatcher; import io.noties.markwon.sample.annotations.MarkwonArtifact; diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorMultipleEditSpansSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorMultipleEditSpansSample.java index 91e36ad1..b402c8d4 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorMultipleEditSpansSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/EditorMultipleEditSpansSample.java @@ -22,6 +22,7 @@ import io.noties.markwon.editor.MarkwonEditor; import io.noties.markwon.editor.MarkwonEditorTextWatcher; import io.noties.markwon.editor.handler.EmphasisEditHandler; import io.noties.markwon.editor.handler.StrongEmphasisEditHandler; +import io.noties.markwon.editor.handler.CodeBlockEditHandler; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.inlineparser.BangInlineProcessor; import io.noties.markwon.inlineparser.EntityInlineProcessor; @@ -76,6 +77,7 @@ public class EditorMultipleEditSpansSample extends MarkwonEditTextSample { .useEditHandler(new EmphasisEditHandler()) .useEditHandler(new StrongEmphasisEditHandler()) .useEditHandler(new StrikethroughEditHandler()) + .useEditHandler(new CodeBlockEditHandler()) .useEditHandler(new CodeEditHandler()) .useEditHandler(new BlockQuoteEditHandler()) .useEditHandler(new LinkEditHandler(onClick)) diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/WYSIWYGEditorSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/WYSIWYGEditorSample.java index 01f916d8..0c36c870 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/WYSIWYGEditorSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/WYSIWYGEditorSample.java @@ -15,7 +15,6 @@ import io.noties.markwon.SoftBreakAddsNewLinePlugin; import io.noties.markwon.app.sample.Tags; import io.noties.markwon.app.samples.editor.shared.BlockQuoteEditHandler; import io.noties.markwon.app.samples.editor.shared.CodeEditHandler; -import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler; import io.noties.markwon.app.samples.editor.shared.LinkEditHandler; import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample; import io.noties.markwon.app.samples.editor.shared.StrikethroughEditHandler; @@ -23,6 +22,7 @@ import io.noties.markwon.editor.MarkwonEditor; import io.noties.markwon.editor.MarkwonEditorTextWatcher; import io.noties.markwon.editor.PersistedSpans; import io.noties.markwon.editor.handler.EmphasisEditHandler; +import io.noties.markwon.editor.handler.HeadingEditHandler; import io.noties.markwon.editor.handler.StrongEmphasisEditHandler; import io.noties.markwon.sample.annotations.MarkwonArtifact; import io.noties.markwon.sample.annotations.MarkwonSampleInfo; diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/HeadingEditHandler.java b/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/HeadingEditHandler.java deleted file mode 100644 index 990d3995..00000000 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/HeadingEditHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.noties.markwon.app.samples.editor.shared; - -import android.text.Editable; -import android.text.Spanned; - -import androidx.annotation.NonNull; - -import io.noties.markwon.Markwon; -import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.core.spans.HeadingSpan; -import io.noties.markwon.editor.EditHandler; -import io.noties.markwon.editor.PersistedSpans; - -public class HeadingEditHandler implements EditHandler { - - private MarkwonTheme theme; - - @Override - public void init(@NonNull Markwon markwon) { - this.theme = markwon.configuration().theme(); - } - - @Override - public void configurePersistedSpans(@NonNull PersistedSpans.Builder builder) { - builder - .persistSpan(Head1.class, () -> new Head1(theme)) - .persistSpan(Head2.class, () -> new Head2(theme)); - } - - @Override - public void handleMarkdownSpan( - @NonNull PersistedSpans persistedSpans, - @NonNull Editable editable, - @NonNull String input, - @NonNull HeadingSpan span, - int spanStart, - int spanTextLength - ) { - final Class type; - switch (span.getLevel()) { - case 1: - type = Head1.class; - break; - case 2: - type = Head2.class; - break; - default: - type = null; - } - - if (type != null) { - final int index = input.indexOf('\n', spanStart + spanTextLength); - final int end = index < 0 - ? input.length() - : index; - editable.setSpan( - persistedSpans.get(type), - spanStart, - end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - } - - @NonNull - @Override - public Class markdownSpanType() { - return HeadingSpan.class; - } - - private static class Head1 extends HeadingSpan { - Head1(@NonNull MarkwonTheme theme) { - super(theme, 1); - } - } - - private static class Head2 extends HeadingSpan { - Head2(@NonNull MarkwonTheme theme) { - super(theme, 2); - } - } -} diff --git a/markwon-editor/build.gradle b/markwon-editor/build.gradle index 884f6fb6..393759ba 100644 --- a/markwon-editor/build.gradle +++ b/markwon-editor/build.gradle @@ -11,6 +11,11 @@ android { versionCode 1 versionName version } + + compileOptions { + targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_1_8 + } } dependencies { diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/BlockQuoteEditHandler.java b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/BlockQuoteEditHandler.java similarity index 100% rename from app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/BlockQuoteEditHandler.java rename to markwon-editor/src/main/java/io/noties/markwon/editor/handler/BlockQuoteEditHandler.java diff --git a/markwon-editor/src/main/java/io/noties/markwon/editor/handler/CodeBlockEditHandler.java b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/CodeBlockEditHandler.java new file mode 100644 index 00000000..3c88ee5b --- /dev/null +++ b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/CodeBlockEditHandler.java @@ -0,0 +1,47 @@ +package io.noties.markwon.editor.handler; + +import android.text.Editable; +import android.text.Spanned; + +import androidx.annotation.NonNull; + +import io.noties.markwon.Markwon; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.spans.CodeBlockSpan; +import io.noties.markwon.editor.EditHandler; +import io.noties.markwon.editor.MarkwonEditorUtils; +import io.noties.markwon.editor.PersistedSpans; + +public class CodeBlockEditHandler implements EditHandler { + private MarkwonTheme theme; + + @Override + public void init(@NonNull Markwon markwon) { + theme = markwon.configuration().theme(); + } + + @Override + public void configurePersistedSpans(@NonNull PersistedSpans.Builder builder) { + builder.persistSpan(CodeBlockSpan.class, () -> new CodeBlockSpan(theme)); + } + + @Override + public void handleMarkdownSpan(@NonNull PersistedSpans persistedSpans, @NonNull Editable editable, @NonNull String input, @NonNull CodeBlockSpan span, int spanStart, int spanTextLength) { + MarkwonEditorUtils.Match delimited = MarkwonEditorUtils.findDelimited(input, spanStart, "```"); + if (delimited != null) { + editable.setSpan( + persistedSpans.get(markdownSpanType()), + delimited.start(), + delimited.end(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + + ); + } + } + + @NonNull + @Override + public Class markdownSpanType() { + return CodeBlockSpan.class; + } +} diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/CodeEditHandler.java b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/CodeEditHandler.java similarity index 100% rename from app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/CodeEditHandler.java rename to markwon-editor/src/main/java/io/noties/markwon/editor/handler/CodeEditHandler.java diff --git a/markwon-editor/src/main/java/io/noties/markwon/editor/handler/HeadingEditHandler.java b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/HeadingEditHandler.java new file mode 100644 index 00000000..ce4b5b25 --- /dev/null +++ b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/HeadingEditHandler.java @@ -0,0 +1,142 @@ +package io.noties.markwon.editor.handler; + +import android.text.Editable; +import android.text.Spanned; + +import androidx.annotation.NonNull; + +import io.noties.markwon.Markwon; +import io.noties.markwon.core.MarkwonTheme; +import io.noties.markwon.core.spans.HeadingSpan; +import io.noties.markwon.editor.EditHandler; +import io.noties.markwon.editor.PersistedSpans; + +public class HeadingEditHandler implements EditHandler { + + private MarkwonTheme theme; + + @Override + public void init(@NonNull Markwon markwon) { + this.theme = markwon.configuration().theme(); + } + + @Override + public void configurePersistedSpans(@NonNull PersistedSpans.Builder builder) { + builder.persistSpan(Heading1Span.class, () -> new Heading1Span(theme)); + builder.persistSpan(Heading2Span.class, () -> new Heading2Span(theme)); + builder.persistSpan(Heading3Span.class, () -> new Heading3Span(theme)); + builder.persistSpan(Heading4Span.class, () -> new Heading4Span(theme)); + builder.persistSpan(Heading5Span.class, () -> new Heading5Span(theme)); + builder.persistSpan(Heading6Span.class, () -> new Heading6Span(theme)); + } + + @Override + public void handleMarkdownSpan( + @NonNull PersistedSpans persistedSpans, + @NonNull Editable editable, + @NonNull String input, + @NonNull HeadingSpan span, + int spanStart, + int spanTextLength) { + final HeadingSpan newSpan; + + switch (span.getLevel()) { + case 1: + newSpan = persistedSpans.get(Heading1Span.class); + break; + case 2: + newSpan = persistedSpans.get(Heading2Span.class); + break; + case 3: + newSpan = persistedSpans.get(Heading3Span.class); + break; + case 4: + newSpan = persistedSpans.get(Heading4Span.class); + break; + case 5: + newSpan = persistedSpans.get(Heading5Span.class); + break; + case 6: + newSpan = persistedSpans.get(Heading6Span.class); + break; + default: + return; + + } + final int newStart = getNewSpanStart(input, spanStart); + final int newEnd = findEnd(input, newStart, newSpan.getLevel()); + + editable.setSpan( + newSpan, + newStart, + newEnd, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + } + + private int findEnd(String input, int searchFrom, int spanLevel) { + int end = searchFrom + spanLevel; + final int strLength = input.length(); + while (end < strLength - 1) { + end++; + if (input.charAt(end) == '\n') { + break; + } + } + return end + 1; + } + + private int getNewSpanStart(String input, int spanStart) { + int start = spanStart; + + while (start >= 0 && input.charAt(start) != '\n') { + start--; + } + start += 1; + + return start; + } + + + @NonNull + @Override + public Class markdownSpanType() { + return HeadingSpan.class; + } + + private static class Heading1Span extends HeadingSpan { + public Heading1Span(@NonNull MarkwonTheme theme) { + super(theme, 1); + } + } + + private static class Heading2Span extends HeadingSpan { + public Heading2Span(@NonNull MarkwonTheme theme) { + super(theme, 2); + } + } + + private static class Heading3Span extends HeadingSpan { + public Heading3Span(@NonNull MarkwonTheme theme) { + super(theme, 3); + } + } + + private static class Heading4Span extends HeadingSpan { + public Heading4Span(@NonNull MarkwonTheme theme) { + super(theme, 4); + } + } + + private static class Heading5Span extends HeadingSpan { + public Heading5Span(@NonNull MarkwonTheme theme) { + super(theme, 5); + } + } + + private static class Heading6Span extends HeadingSpan { + public Heading6Span(@NonNull MarkwonTheme theme) { + super(theme, 6); + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/StrikethroughEditHandler.java b/markwon-editor/src/main/java/io/noties/markwon/editor/handler/StrikethroughEditHandler.java similarity index 100% rename from app-sample/src/main/java/io/noties/markwon/app/samples/editor/shared/StrikethroughEditHandler.java rename to markwon-editor/src/main/java/io/noties/markwon/editor/handler/StrikethroughEditHandler.java