diff --git a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownUtil.java b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownUtil.java index 08234c83..a434c38d 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/MarkdownUtil.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/MarkdownUtil.java @@ -184,19 +184,26 @@ public class MarkdownUtil { return s.length(); } - public static String getListItemIfIsEmpty(@NonNull String line) { + public static Optional getListItemIfIsEmpty(@NonNull String line) { + final String trimmedLine = line.trim(); + // TODO use Java 11 String::repeat + final StringBuilder builder = new StringBuilder(); + final int indention = line.indexOf(trimmedLine); + for (int i = 0; i < indention; i++) { + builder.append(" "); + } for (EListType listType : EListType.values()) { - if (line.equals(listType.checkboxUncheckedWithTrailingSpace)) { - return listType.checkboxUncheckedWithTrailingSpace; - } else if (line.equals(listType.listSymbolWithTrailingSpace)) { - return listType.listSymbolWithTrailingSpace; + if (trimmedLine.equals(listType.checkboxUnchecked)) { + return Optional.of(builder.append(listType.checkboxUncheckedWithTrailingSpace).toString()); + } else if (trimmedLine.equals(listType.listSymbol)) { + return Optional.of(builder.append(listType.listSymbolWithTrailingSpace).toString()); } } - final Matcher matcher = PATTERN_ORDERED_LIST_ITEM_EMPTY.matcher(line); + final Matcher matcher = PATTERN_ORDERED_LIST_ITEM_EMPTY.matcher(line.substring(indention)); if (matcher.find()) { - return matcher.group(); + return Optional.of(builder.append(matcher.group()).toString()); } - return null; + return Optional.empty(); } public static CharSequence setCheckboxStatus(@NonNull String markdownString, int targetCheckboxIndex, boolean newCheckedState) { diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java index a30f8e43..474a0ada 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcher.java @@ -85,9 +85,9 @@ public class AutoContinuationTextWatcher extends InterceptorTextWatcher { final int startOfLine = getStartOfLine(s, start); final String line = s.subSequence(startOfLine, getEndOfLine(s, start)).toString(); - final String emptyListString = getListItemIfIsEmpty(line); - if (emptyListString != null) { - customText = emptyListString; + final Optional emptyListString = getListItemIfIsEmpty(line); + if (emptyListString.isPresent()) { + customText = emptyListString.get(); isInsert = false; sequenceStart = startOfLine; } else { @@ -96,9 +96,10 @@ public class AutoContinuationTextWatcher extends InterceptorTextWatcher { for (int i = 0; i < line.indexOf(line.trim()); i++) { builder.append(" "); } + final String trimmedLine = line.trim(); for (EListType listType : EListType.values()) { - final boolean isCheckboxList = lineStartsWithCheckbox(line, listType); - final boolean isPlainList = !isCheckboxList && line.startsWith(listType.listSymbolWithTrailingSpace); + final boolean isCheckboxList = lineStartsWithCheckbox(trimmedLine, listType); + final boolean isPlainList = !isCheckboxList && trimmedLine.startsWith(listType.listSymbolWithTrailingSpace); if (isPlainList || isCheckboxList) { builder.append(isPlainList ? listType.listSymbolWithTrailingSpace : listType.checkboxUncheckedWithTrailingSpace); customText = builder; diff --git a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcher.java b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcher.java index 365c1bd1..eac1350d 100644 --- a/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcher.java +++ b/markdown/src/main/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcher.java @@ -12,7 +12,7 @@ import static it.niedermann.android.markdown.MarkdownUtil.getEndOfLine; import static it.niedermann.android.markdown.MarkdownUtil.getStartOfLine; /** - * Automatically continues lists and checkbox lists when pressing enter + * Automatically lowers indention when pressing Backspace on lists and check lists */ public class LowerIndentionTextWatcher extends InterceptorTextWatcher { @@ -41,7 +41,7 @@ public class LowerIndentionTextWatcher extends InterceptorTextWatcher { @Override public void afterTextChanged(Editable editable) { if (backspacePressed) { - if(!handleBackspace(editable, cursor)) { + if (!handleBackspace(editable, cursor)) { originalWatcher.afterTextChanged(editable); } backspacePressed = false; @@ -54,11 +54,20 @@ public class LowerIndentionTextWatcher extends InterceptorTextWatcher { private boolean handleBackspace(@NonNull Editable editable, int cursor) { final int lineStart = getStartOfLine(editable, cursor); final int lineEnd = getEndOfLine(editable, cursor); + + // The cursor must be at the end of the line to automatically continue if (cursor != lineEnd) { return false; } + final String line = editable.subSequence(lineStart, lineEnd).toString(); final String trimmedLine = line.trim(); + + // There must be no content in this list item to automatically continue + if ((line.indexOf(trimmedLine) + trimmedLine.length()) < line.length()) { + return false; + } + for (EListType listType : EListType.values()) { if (listType.listSymbol.equals(trimmedLine)) { if (trimmedLine.length() == EListType.DASH.listSymbol.length()) { diff --git a/markdown/src/test/java/it/niedermann/android/markdown/MarkdownUtilTest.java b/markdown/src/test/java/it/niedermann/android/markdown/MarkdownUtilTest.java index 11f0ff90..18063ba2 100644 --- a/markdown/src/test/java/it/niedermann/android/markdown/MarkdownUtilTest.java +++ b/markdown/src/test/java/it/niedermann/android/markdown/MarkdownUtilTest.java @@ -586,18 +586,37 @@ public class MarkdownUtilTest extends TestCase { } } + @SuppressWarnings("OptionalGetWithoutIsPresent") @Test public void testGetListItemIfIsEmpty() { - assertEquals("- ", MarkdownUtil.getListItemIfIsEmpty("- ")); - assertEquals("+ ", MarkdownUtil.getListItemIfIsEmpty("+ ")); - assertEquals("* ", MarkdownUtil.getListItemIfIsEmpty("* ")); - assertEquals("1. ", MarkdownUtil.getListItemIfIsEmpty("1. ")); + assertEquals("- ", MarkdownUtil.getListItemIfIsEmpty("- ").get()); + assertEquals("+ ", MarkdownUtil.getListItemIfIsEmpty("+ ").get()); + assertEquals("* ", MarkdownUtil.getListItemIfIsEmpty("* ").get()); + assertEquals("1. ", MarkdownUtil.getListItemIfIsEmpty("1. ").get()); + assertEquals(" - ", MarkdownUtil.getListItemIfIsEmpty(" - ").get()); + assertEquals(" + ", MarkdownUtil.getListItemIfIsEmpty(" + ").get()); + assertEquals(" * ", MarkdownUtil.getListItemIfIsEmpty(" * ").get()); + assertEquals(" 1. ", MarkdownUtil.getListItemIfIsEmpty(" 1. ").get()); + assertEquals(" - ", MarkdownUtil.getListItemIfIsEmpty(" - ").get()); + assertEquals(" + ", MarkdownUtil.getListItemIfIsEmpty(" + ").get()); + assertEquals(" * ", MarkdownUtil.getListItemIfIsEmpty(" * ").get()); + assertEquals(" 1. ", MarkdownUtil.getListItemIfIsEmpty(" 1. ").get()); - assertNull(MarkdownUtil.getListItemIfIsEmpty("- Test")); - assertNull(MarkdownUtil.getListItemIfIsEmpty("+ Test")); - assertNull(MarkdownUtil.getListItemIfIsEmpty("* Test")); - assertNull(MarkdownUtil.getListItemIfIsEmpty("1. s")); - assertNull(MarkdownUtil.getListItemIfIsEmpty("1. ")); + assertFalse(MarkdownUtil.getListItemIfIsEmpty("- Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty("+ Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty("* Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty("1. s").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty("1. ").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" - Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" + Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" * Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" 1. s").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" 1. ").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" - Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" + Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" * Test").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" 1. s").isPresent()); + assertFalse(MarkdownUtil.getListItemIfIsEmpty(" 1. ").isPresent()); } @SuppressWarnings("OptionalGetWithoutIsPresent") diff --git a/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcherTest.java b/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcherTest.java index 4069d224..8eda9243 100644 --- a/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcherTest.java +++ b/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/AutoContinuationTextWatcherTest.java @@ -101,6 +101,14 @@ public class AutoContinuationTextWatcherTest extends TestCase { assertText("- Foo\n\n", 7); pressEnter(7); assertText("- Foo\n\n\n", 8); + + this.editText.setText("- Foo\n - Bar"); + pressEnter(13); + assertText("- Foo\n - Bar\n - ", 18); + pressEnter(18); + assertText("- Foo\n - Bar\n\n", 15); + pressEnter(15); + assertText("- Foo\n - Bar\n\n\n", 16); } @Test diff --git a/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcherTest.java b/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcherTest.java index dd28102c..87375a90 100644 --- a/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcherTest.java +++ b/markdown/src/test/java/it/niedermann/android/markdown/markwon/textwatcher/LowerIndentionTextWatcherTest.java @@ -71,6 +71,24 @@ public class LowerIndentionTextWatcherTest extends TestCase { assertText("- Foo\n ", 8); } + @Test + public void shouldNotLowerIndentionIfThereIsAnyContentAfterTheList() { + this.editText.setText(" - "); + pressBackspace(4); + assertText(" - ", 3); + + this.editText.setText(" - "); + pressBackspace(5); + assertText(" - ", 4); + } + + @Test + public void shouldNotLowerIndentionIfBackspaceWasPressedInTheNextLine() { + this.editText.setText(" - \nFoo"); + pressBackspace(5); + assertText(" - Foo", 4); + } + @Test public void shouldDeleteLastCharacterWhenPressingBackspace() { this.editText.setText("");