diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-12-17 14:48:22 +0300 |
---|---|---|
committer | Niedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com> | 2020-12-17 18:14:29 +0300 |
commit | 268c106ce811f38f7281ac760d686d8fb1c31a77 (patch) | |
tree | abd3ed4c39c2f77b2f2b3d8d5c78d7de7dfe01cf | |
parent | c6aff34f2e84c6c49f4b4d5dd2cb24950342deef (diff) |
Only provide option to insert link when no link is selected
Signed-off-by: Stefan Niedermann <info@niedermann.it>
3 files changed, 90 insertions, 26 deletions
diff --git a/markdown/src/androidTest/java/it/niedermann/android/markdown/MarkwonMarkdownUtilTest.java b/markdown/src/androidTest/java/it/niedermann/android/markdown/MarkwonMarkdownUtilTest.java index f09c14134..c0e32ea34 100644 --- a/markdown/src/androidTest/java/it/niedermann/android/markdown/MarkwonMarkdownUtilTest.java +++ b/markdown/src/androidTest/java/it/niedermann/android/markdown/MarkwonMarkdownUtilTest.java @@ -194,6 +194,38 @@ public class MarkwonMarkdownUtilTest extends TestCase { // builder = new StringBuilder("Lorem *ipsum* dolor sit amet."); // assertEquals(17, MarkwonMarkdownUtil.togglePunctuation(builder, 7, 12, "**")); // assertEquals("Lorem ***ipsum*** dolor sit amet.", builder.toString()); + + // Text is not directly surrounded by punctuation but contains it + + // TODO Remove containing punctuation +// builder = new StringBuilder("Lorem *ipsum* dolor sit amet."); +// assertEquals(11, MarkwonMarkdownUtil.togglePunctuation(builder, 6, 13, "*")); +// assertEquals("Lorem ipsum dolor sit amet.", builder.toString()); + + // TODO Remove containing punctuation +// builder = new StringBuilder("Lorem *ipsum* dolor sit amet."); +// assertEquals(27, MarkwonMarkdownUtil.togglePunctuation(builder, 0, 29, "*")); +// assertEquals("Lorem ipsum dolor sit amet.", builder.toString()); + + // TODO Remove multiple containing punctuations +// builder = new StringBuilder("Lorem *ipsum* dolor *sit* amet."); +// assertEquals(27, MarkwonMarkdownUtil.togglePunctuation(builder, 0, 31, "*")); +// assertEquals("Lorem ipsum dolor sit amet.", builder.toString()); + + // TODO Toggle bold to italic +// builder = new StringBuilder("Lorem **ipsum** dolor sit amet."); +// assertEquals(29, MarkwonMarkdownUtil.togglePunctuation(builder, 0, 31, "*")); +// assertEquals("Lorem *ipsum* dolor sit amet.", builder.toString()); + + // TODO Toggle multiple bold parts to italic +// builder = new StringBuilder("Lorem **ipsum** dolor **sit** amet."); +// assertEquals(31, MarkwonMarkdownUtil.togglePunctuation(builder, 0, 35, "*")); +// assertEquals("Lorem *ipsum* dolor *sit* amet.", builder.toString()); + + // TODO Do nothing +// builder = new StringBuilder("Lorem *ipsum dolor sit amet."); +// assertEquals(28, MarkwonMarkdownUtil.togglePunctuation(builder, 0, 28, "*")); +// assertEquals("Lorem *ipsum dolor sit amet.", builder.toString()); } @Test @@ -240,23 +272,40 @@ public class MarkwonMarkdownUtilTest extends TestCase { } @Test - public void testRemoveSurroundingPunctuation() { + @SuppressWarnings("ConstantConditions") + public void testSelectionIsInLink() { try { - final Method m = MarkwonMarkdownUtil.class.getDeclaredMethod("removeSurroundingPunctuation", StringBuilder.class, int.class, int.class, String.class); + final Method m = MarkwonMarkdownUtil.class.getDeclaredMethod("selectionIsInLink", CharSequence.class, int.class, int.class); m.setAccessible(true); - StringBuilder builder; - - builder = new StringBuilder("*Lorem Ipsum*"); - m.invoke(null, builder, 1, 12, "*"); - assertEquals("Lorem Ipsum", builder.toString()); - - builder = new StringBuilder("**Lorem Ipsum**"); - m.invoke(null, builder, 2, 13, "**"); - assertEquals("Lorem Ipsum", builder.toString()); - builder = new StringBuilder("**Lorem Ipsum**"); - m.invoke(null, builder, 2, 13, "*"); - assertEquals("*Lorem Ipsum*", builder.toString()); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 7, 12)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 6, 34)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 14, 33)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 12, 14)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 0, 7)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 33, 34)); + + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 6, 28)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 7, 28)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 8, 28)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 9, 28)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 6, 29)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 7, 29)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 8, 29)); + assertTrue((Boolean) m.invoke(null, "Lorem [](https://example.com) dolor sit amet.", 9, 29)); + + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 6, 12)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 6, 13)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 6, 14)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 6, 15)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 7, 12)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 7, 13)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 7, 14)); + assertTrue((Boolean) m.invoke(null, "Lorem [ipsum]() dolor sit amet.", 7, 15)); + + assertFalse((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 0, 6)); + assertFalse((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 34, 50)); + assertFalse((Boolean) m.invoke(null, "Lorem [ipsum](https://example.com) dolor sit amet.", 41, 44)); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java index d4e388187..fe28ac0b5 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/MarkwonMarkdownUtil.java @@ -8,6 +8,8 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.noties.markwon.Markwon; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; @@ -126,7 +128,8 @@ public class MarkwonMarkdownUtil { case "~~": { final boolean selectionIsSurroundedByPunctuation = selectionIsSurroundedByPunctuation(builder.toString(), selectionStart, selectionEnd, punctuation); if (selectionIsSurroundedByPunctuation) { - removeSurroundingPunctuation(builder, selectionStart, selectionEnd, punctuation); + builder.delete(selectionEnd, selectionEnd + punctuation.length()); + builder.delete(selectionStart - punctuation.length(), selectionStart); } else { builder.insert(selectionEnd, punctuation); builder.insert(selectionStart, punctuation); @@ -184,15 +187,14 @@ public class MarkwonMarkdownUtil { && punctuation.contentEquals(text.subSequence(end, end + punctuation.length())); } - /** - * Mutates the given {@param builder} and removes the text range from {@param start} to - * {@param end} and its surrounding {@param punctuation}. - * Doesn't make any assumptions about the text lengths and will throw a - * {@link StringIndexOutOfBoundsException} if {@param start}, {@param end} or the - * {@param punctuation} is out of range of the given {@param builder}. - */ - private static void removeSurroundingPunctuation(@NonNull StringBuilder builder, int start, int end, @NonNull String punctuation) throws StringIndexOutOfBoundsException { - builder.delete(end, end + punctuation.length()); - builder.delete(start - punctuation.length(), start); + public static boolean selectionIsInLink(@NonNull CharSequence text, int start, int end) { + final Pattern pattern = Pattern.compile("\\[(.+)?]\\(([^ ]+?)?( \"(.+)\")?\\)"); + final Matcher matcher = pattern.matcher(text); + while (matcher.find()) { + if ((start >= matcher.start() && start < matcher.end()) || (end > matcher.start() && end <= matcher.end())) { + return true; + } + } + return false; } } diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/format/ContextBasedRangeFormattingCallback.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/format/ContextBasedRangeFormattingCallback.java index 1519341d8..6cca65e43 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/format/ContextBasedRangeFormattingCallback.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/format/ContextBasedRangeFormattingCallback.java @@ -4,6 +4,7 @@ import android.graphics.Typeface; import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.style.StyleSpan; +import android.util.Log; import android.util.SparseIntArray; import android.view.ActionMode; import android.view.Menu; @@ -49,7 +50,19 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - // TODO hide actions if not available? + final CharSequence text = editText.getText(); + if (text != null) { + final int selectionStart = editText.getSelectionStart(); + final int selectionEnd = editText.getSelectionEnd(); + if (selectionStart >= 0 && selectionStart <= text.length()) { + if (MarkwonMarkdownUtil.selectionIsInLink(text, selectionStart, selectionEnd)) { + menu.findItem(R.id.link).setVisible(false); + Log.i(TAG, "Hide link menu item because the selection is already within a link."); + } + } else { + Log.e(TAG, "SelectionStart is " + selectionStart + ". Expected to be between 0 and " + text.length()); + } + } return false; } |