From 32905549d910fe9a989329a48c454ebde362febb Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 11:35:49 -0700 Subject: [PATCH 1/9] Many perf and other changes --- .../markor/activity/DocumentEditFragment.java | 14 +- .../net/gsantner/markor/model/Document.java | 8 +- .../markor/ui/hleditor/TextActions.java | 110 +++++------ .../net/gsantner/opoc/util/FileUtils.java | 6 +- .../net/gsantner/opoc/util/NanoProfiler.java | 3 + .../net/gsantner/opoc/util/StringUtils.java | 186 +++++++++++------- .../net/gsantner/markor/StringUtilsTest.java | 2 - .../ZimWikiReplacePatternGeneratorTests.java | 3 +- 8 files changed, 175 insertions(+), 157 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java index e02e530891..f534326d82 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java @@ -53,6 +53,7 @@ import net.gsantner.markor.util.MarkorWebViewClient; import net.gsantner.markor.util.ShareUtil; import net.gsantner.opoc.activity.GsFragmentBase; +import net.gsantner.opoc.android.dummy.TextWatcherDummy; import net.gsantner.opoc.preference.FontPreferenceCompat; import net.gsantner.opoc.ui.FilesystemViewerData; import net.gsantner.opoc.util.ActivityUtils; @@ -213,8 +214,13 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { // Set initial wrap state initDocState(); - } + final Runnable debounced = StringUtils.makeDebounced(500, () -> { + checkTextChangeState(); + updateUndoRedoIconStates(); + }); + _hlEditor.addTextChangedListener(TextWatcherDummy.after(s -> debounced.run())); + } @Override public void onFragmentFirstTimeVisible() { @@ -570,12 +576,6 @@ public void onFsViewerConfig(FilesystemViewerData.Options dopt) { } } - @OnTextChanged(value = R.id.document__fragment__edit__highlighting_editor, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) - public void onContentEditValueChanged(CharSequence text) { - checkTextChangeState(); - updateUndoRedoIconStates(); - } - public void checkTextChangeState() { final boolean isTextChanged = !_document.isContentSame(_hlEditor.getText()); diff --git a/app/src/main/java/net/gsantner/markor/model/Document.java b/app/src/main/java/net/gsantner/markor/model/Document.java index 72c225fe6b..f91e6c56dc 100644 --- a/app/src/main/java/net/gsantner/markor/model/Document.java +++ b/app/src/main/java/net/gsantner/markor/model/Document.java @@ -26,7 +26,6 @@ import net.gsantner.markor.util.AppSettings; import net.gsantner.markor.util.ShareUtil; import net.gsantner.opoc.util.FileUtils; -import net.gsantner.opoc.util.StringUtils; import java.io.File; import java.io.FileInputStream; @@ -233,13 +232,8 @@ public boolean saveContent(final Context context, final CharSequence content) { return saveContent(context, content, null, false); } - // Doing as we don't want to convert to string or copy unless necessary - private static int trimmedLength(final CharSequence c) { - return StringUtils.getLastNonWhitespace(c, c.length()) - StringUtils.getNextNonWhitespace(c, 0); - } - public synchronized boolean saveContent(final Context context, final CharSequence content, ShareUtil shareUtil, boolean isManualSave) { - if (!isManualSave && trimmedLength(content) < ShareUtil.MIN_OVERWRITE_LENGTH) { + if (!isManualSave && TextUtils.getTrimmedLength(content) < ShareUtil.MIN_OVERWRITE_LENGTH) { return false; } diff --git a/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java b/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java index 70ac48e5c8..83101ec63d 100644 --- a/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java +++ b/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java @@ -20,6 +20,7 @@ import android.support.v7.widget.TooltipCompat; import android.text.Editable; import android.text.TextUtils; +import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; @@ -200,11 +201,7 @@ private List loadActionPreference(final String suffix) { String formatKey = _activity.getResources().getString(getFormatActionsKey()) + suffix; SharedPreferences settings = _activity.getSharedPreferences(ACTION_ORDER_PREF_NAME, Context.MODE_PRIVATE); String combinedKeys = settings.getString(formatKey, null); - List values = Collections.emptyList(); - if (combinedKeys != null) { - values = new ArrayList(Arrays.asList(combinedKeys.split(","))); - } - return values; + return combinedKeys != null ? Arrays.asList(combinedKeys.split(",")) : Collections.emptyList(); } /** @@ -330,10 +327,14 @@ protected void runRegularPrefixAction(final String action, final String replaceS } public static class ReplacePattern { - public final Pattern searchPattern; + public final Matcher matcher; public final String replacePattern; public final boolean replaceAll; + public boolean isSameReplace() { + return replacePattern.equals("$0"); + } + /** * Construct a ReplacePattern * @@ -342,11 +343,15 @@ public static class ReplacePattern { * @param replaceAll whether to replace all or just the first */ public ReplacePattern(Pattern searchPattern, String replacePattern, boolean replaceAll) { - this.searchPattern = searchPattern; + this.matcher = searchPattern.matcher(""); this.replacePattern = replacePattern; this.replaceAll = replaceAll; } + public CharSequence replace() { + return replaceAll ? matcher.replaceAll(replacePattern) : matcher.replaceFirst(replacePattern); + } + public ReplacePattern(String searchPattern, String replacePattern, boolean replaceAll) { this(Pattern.compile(searchPattern), replacePattern, replaceAll); } @@ -361,23 +366,19 @@ public ReplacePattern(String searchPattern, String replacePattern) { } public void runRegexReplaceAction(final ReplacePattern... patterns) { - runRegexReplaceAction(Arrays.asList(patterns), false); + runRegexReplaceAction(Arrays.asList(patterns)); } public void runRegexReplaceAction(final List patterns) { - runRegexReplaceAction(patterns, false); + runRegexReplaceAction(_hlEditor, patterns); } public void runRegexReplaceAction(final String pattern, final String replace) { - runRegexReplaceAction(Arrays.asList(new ReplacePattern(pattern, replace)), false); - } - - public void runRegexReplaceAction(final List patterns, final boolean matchAll) { - runRegexReplaceAction(_hlEditor, patterns, matchAll); + runRegexReplaceAction(Collections.singletonList(new ReplacePattern(pattern, replace))); } public static void runRegexReplaceAction(final EditText editor, final ReplacePattern... patterns) { - runRegexReplaceAction(editor, Arrays.asList(patterns), false); + runRegexReplaceAction(editor, Arrays.asList(patterns)); } /** @@ -385,74 +386,57 @@ public static void runRegexReplaceAction(final EditText editor, final ReplacePat * This function wraps _runRegexReplaceAction with a call to disable text trackers * * @param patterns An array of ReplacePattern - * @param matchAll Whether to stop matching subsequent ReplacePatterns after first match+replace */ - public static void runRegexReplaceAction(final EditText editor, final List patterns, final boolean matchAll) { + public static void runRegexReplaceAction(final EditText editor, final List patterns) { + final long start = System.nanoTime(); if (editor instanceof HighlightingEditor) { - ((HighlightingEditor) editor).withAutoFormatDisabled(() -> _runRegexReplaceAction(editor, patterns, matchAll)); + ((HighlightingEditor) editor).withAutoFormatDisabled(() -> _runRegexReplaceAction(editor, patterns)); } else { - _runRegexReplaceAction(editor, patterns, matchAll); + _runRegexReplaceAction(editor, patterns); } + // TODO - remove + Log.i("markor_regex_replace", "" + 0.001 * (System.nanoTime() - start) + " us"); } - private static void _runRegexReplaceAction(final EditText editor, final List patterns, final boolean matchAll) { + private static void _runRegexReplaceAction(final EditText editor, final List patterns) { - Editable text = editor.getText(); - final int[] selection = StringUtils.getSelection(editor); - final int[] lStart = StringUtils.getLineOffsetFromIndex(text, selection[0]); - final int[] lEnd = StringUtils.getLineOffsetFromIndex(text, selection[1]); + final int[] sel = StringUtils.getSelection(editor); + final StringUtils.ChunkedEditable text = StringUtils.ChunkedEditable.wrap(editor.getText()); - // Chunk if more than one line will be acted upon - text = lEnd[0] != lStart[0] ? StringUtils.ChunkedEditable.wrap(text) : text; + // Offset of selection start from text end - used to restore selection + final int selEndOffset = text.length() - sel[1]; + // Offset of selection start from line end - used to restore selection + final int selStartOffset = sel[1] == sel[0] ? selEndOffset : StringUtils.getLineEnd(text, sel[0]) - sel[0]; - int lineStart = StringUtils.getLineStart(text, selection[0]); - int selEnd = StringUtils.getLineEnd(text, selection[1]); + // Start of line on which sel begins + final int selStartStart = StringUtils.getLineStart(text, sel[0]); + // Number of lines we will be modifying + final int lineCount = StringUtils.countChars(text, sel[0], sel[1], '\n')[0] + 1; - while (lineStart <= selEnd && lineStart <= text.length()) { + int lineStart = selStartStart; - final int lineEnd = StringUtils.getLineEnd(text, lineStart, selEnd); - final CharSequence line = text.subSequence(lineStart, lineEnd); + for (int i = 0; i < lineCount; i++) { - for (final ReplacePattern pattern : patterns) { - - final Matcher searcher = pattern.searchPattern.matcher(line); - - // Find matched region - int matchStart = line.length(); - int matchEnd = -1; - while (searcher.find()) { - matchStart = Math.min(matchStart, searcher.start()); - matchEnd = Math.max(matchEnd, searcher.end()); - - if (!pattern.replaceAll) break; // Limit region based on search type - } + int lineEnd = StringUtils.getLineEnd(text, lineStart); + final String line = StringUtils.toString(text, lineStart, lineEnd); - if (matchEnd >= matchStart) { // Will be true iff at least one match has been found - if (!pattern.replacePattern.equals("$0")) { - final CharSequence oldRegion = line.subSequence(matchStart, matchEnd); - // Have to create a new matcher, unfortunately, as replace does not respect region - final Matcher replacer = pattern.searchPattern.matcher(oldRegion); - final String newRegion = pattern.replaceAll ? replacer.replaceAll(pattern.replacePattern) : replacer.replaceFirst(pattern.replacePattern); - text.replace(matchStart + lineStart, matchEnd + lineStart, newRegion); - // Change effective selection based on update - selEnd += newRegion.length() - oldRegion.length(); + for (final ReplacePattern pattern : patterns) { + if (pattern.matcher.reset(line).find()) { + if (!pattern.isSameReplace()) { + text.replace(lineStart, lineEnd, pattern.replace()); } - - if (!matchAll) break; // Exit after first match + break; } } - lineStart = StringUtils.getLineEnd(text, lineStart, selEnd) + 1; + lineStart = StringUtils.getLineEnd(text, lineStart) + 1; } - // Apply changes if chunked - if (text instanceof StringUtils.ChunkedEditable) { - ((StringUtils.ChunkedEditable) text).applyChanges(); - } + text.applyChanges(); - editor.setSelection( - StringUtils.getIndexFromLineOffset(text, lStart), - StringUtils.getIndexFromLineOffset(text, lEnd)); + final int newSelEnd = text.length() - selEndOffset; + final int newSelStart = sel[0] == sel[1] ? newSelEnd : StringUtils.getLineEnd(text, selStartStart) - selStartOffset; + editor.setSelection(newSelStart, newSelEnd); } protected void runInlineAction(String _action) { diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index 96e21d3e40..b84c51fadd 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -13,6 +13,8 @@ import android.text.TextUtils; import android.util.Pair; +import org.w3c.dom.Text; + import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -27,6 +29,8 @@ import java.io.InputStreamReader; import java.io.Serializable; import java.net.URLConnection; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; @@ -50,7 +54,6 @@ public class FileUtils { */ public static class FileInfo implements Serializable { public boolean hasBom = false; - public FileInfo withBom(boolean bom) { hasBom = bom; return this; @@ -65,6 +68,7 @@ public static Pair readTextFileFast(final File file) { final byte[] bomBuffer = new byte[3]; final int bomReadLength = inputStream.read(bomBuffer); + info.withBom(bomReadLength == 3 && bomBuffer[0] == (byte) 0xEF && bomBuffer[1] == (byte) 0xBB && diff --git a/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java b/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java index 41b0a477ab..ee24e6c901 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java +++ b/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java @@ -10,6 +10,8 @@ #########################################################*/ package net.gsantner.opoc.util; +import android.util.Log; + import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; @@ -71,6 +73,7 @@ public void end() { text = "NanoProfiler::: " + _groupCount + text; _debugText += text + "\n"; System.out.println(text); + Log.i("markor_regex_replace", text); } } } diff --git a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java index b7baaaca5a..d4a352c731 100644 --- a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java @@ -10,15 +10,20 @@ package net.gsantner.opoc.util; import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; import android.support.annotation.NonNull; import android.text.Editable; +import android.text.GetChars; import android.text.InputFilter; import android.text.Layout; import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.util.Base64; import android.widget.EditText; import android.widget.TextView; +import java.nio.CharBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -462,30 +467,53 @@ public static String interpolateEscapedDateTime(final String snip) { return interpolated.toString(); } - // Find the smallest single difference region { a, b, c } - // s.t. setting dest[a:b] = source[a:c] makes dest == source - public static int[] findDiff(final CharSequence dest, final CharSequence source) { + /** + * Find the smallest single diff from source -> dest + * + * @param dest Into which we want to apply the diff + * @param source From which we want to apply the diff + * @param startSkip Don't check the first startSkip chars for sameness + * @param endSkip Don't check the first startSkip chars for sameness + * @return { a, b, c } s.t. setting dest[a:b] = source[a:c] makes dest == source + */ + public static int[] findDiff(final CharSequence dest, final CharSequence source, final int startSkip, final int endSkip) { + final int[] diff = findDiff(dest, startSkip, dest.length() - endSkip, source, startSkip, source.length() - endSkip); + return new int[] { diff[0], diff[1], diff[3] }; + } - final int dl = dest.length(), sl = source.length(); + /** + * Find the smallest single diff from source -> dest + * + * @param dest Into which we want to apply the diff + * @param ds Dest start region + * @param dn Dest end region + * @param source From which we want to apply the diff + * @param ss Source start region + * @param sn Dest end region + * + * @return { a, b, c, d } s.t. setting dest[a:b] = source[c:d] will make dest[ds:dn] == source[ss:sn] + */ + public static int[] findDiff(final CharSequence dest, final int ds, final int dn, final CharSequence source, final int ss, final int sn) { + final int dl = Math.max(dn - ds, 0), sl = Math.max(sn - ss, 0); final int minLength = Math.min(dl, sl); int start = 0; - while (start < minLength && source.charAt(start) == dest.charAt(start)) start++; + while (start < minLength && source.charAt(start + ss) == dest.charAt(start + ds)) start++; // Handle several special cases if (sl == dl && start == sl) { // Case where 2 sequences are same - return new int[]{sl, sl, sl}; + return new int[]{dn, dn, sn, sn}; } else if (sl < dl && start == sl) { // Pure crop - return new int[]{sl, dl, sl}; + return new int[]{ds + start, dn, sn, sn}; } else if (dl < sl && start == dl) { // Pure append - return new int[]{dl, dl, sl}; + return new int[]{dn, dn, start + ss, sn}; } int end = 0; final int maxEnd = minLength - start; - while (end < maxEnd && source.charAt(sl - end - 1) == dest.charAt(dl - end - 1)) end++; + while (end < maxEnd && source.charAt(sn - end - 1) == dest.charAt(dn - end - 1)) end++; - return new int[]{start, dl - end, sl - end}; + return new int[]{ds + start, dn - end, ss + start, sn - end}; } // Compute the line indent, counting each tab as tabSize spaces @@ -496,31 +524,6 @@ public static int getLineIndent(final CharSequence text, final int posn, final i return counts[0] + tabSize * counts[1]; } - // Checks if two CharSequences are identical between [start, end) - public static boolean checkSame( - final CharSequence a, final int aStart, final int aEnd, - final CharSequence b, final int bStart, final int bEnd) { - - // Return not same for various pathological cases - if ((aEnd < aStart) || (bEnd < bStart) || !isValidIndex(a, aStart, aEnd - 1) || !isValidIndex(b, bStart, bEnd - 1)) { - return false; - } - - // Not same if lengths not same - if ((aEnd - aStart) != (bStart - bEnd)) { - return false; - } - - final int length = aEnd - aStart; - for (int i = 0; i < length; i++) { - if (a.charAt(aStart + i) != b.charAt(bStart + i)) { - return false; - } - } - - return true; - } - /** * Allows convenient chunking of actions on an editable. * This works by maintaining a _reference_ to an editable to which all operations are passed. @@ -531,7 +534,9 @@ public static boolean checkSame( public static class ChunkedEditable implements Editable { private final Editable original; - private Editable copy; + private StringBuilder copy; + private int _startSkip = 0; + private int _endSkip = 0; public static ChunkedEditable wrap(@NonNull final Editable e) { return (e instanceof ChunkedEditable) ? (ChunkedEditable) e : new ChunkedEditable(e); @@ -547,30 +552,30 @@ public boolean applyChanges() { return false; } - final int[] diff = StringUtils.findDiff(original, copy); - if (diff[0] != diff[1] || diff[0] != diff[2]) { + final int[] diff = StringUtils.findDiff(original, copy, _startSkip, Math.max(_endSkip, 0)); + final boolean hasDiff = diff[0] != diff[1] || diff[0] != diff[2]; + if (hasDiff) { original.replace(diff[0], diff[1], copy.subSequence(diff[0], diff[2])); - copy = null; // Reset as we have applied all changed - return true; } - return false; - } - - private Editable select() { - return copy != null ? copy : original; + copy = null; // Reset as we have applied all changed + return hasDiff; } // All other functions which edit the editable alias this routine @Override public Editable replace(int st, int en, CharSequence source, int start, int end) { - // Don't do extra work if no change is not real - if (!checkSame(this, st, en, source, start, end)) { + // Replace minimal region, only if actually required - replacing is expensive + final int[] diff = findDiff((copy != null ? copy : original), st, en, source, start, end); + if (diff[0] != diff[1] || diff[2] != diff[3]) { if (copy == null) { // All operations will now run on copy // SpannableStringBuilder maintains spans etc - copy = new SpannableStringBuilder(original); + copy = new StringBuilder(original); + _startSkip = _endSkip = copy.length(); } - select().replace(st, en, source, start, end); + _startSkip = Math.min(_startSkip, diff[0]); + _endSkip = Math.min(_endSkip, copy.length() - diff[1] - 1); + copy.replace(diff[0], diff[1], StringUtils.toString(source, diff[2], diff[3])); } return this; } @@ -623,75 +628,106 @@ public void clear() { // Other functions - all just forwarded to copy or original as needed // ------------------------------------------------------------------------------- + @Override - public void clearSpans() { - select().clearSpans(); + public int length() { + return (copy != null ? copy : original).length(); } @Override - public void setFilters(InputFilter[] filters) { - select().setFilters(filters); + public char charAt(int index) { + return (copy != null ? copy : original).charAt(index); } + @NonNull @Override - public InputFilter[] getFilters() { - return select().getFilters(); + public CharSequence subSequence(int start, int end) { + return (copy != null ? copy : original).subSequence(start, end); } @Override public void getChars(int start, int end, char[] dest, int destoff) { - select().getChars(start, end, dest, destoff); + TextUtils.getChars(copy != null ? copy : original, start, end, dest, destoff); + } + + // All spannable things unsupported + // ------------------------------------------------------------------------------- + @Override + public void clearSpans() { + // Do nothing + } + + @Override + public void setFilters(InputFilter[] filters) { + // Do nothing + } + + @Override + public InputFilter[] getFilters() { + return null; } @Override public void setSpan(Object what, int start, int end, int flags) { - select().setSpan(what, start, end, flags); + // Do nothing } @Override public void removeSpan(Object what) { - select().removeSpan(what); + // Do nothing } @Override public T[] getSpans(int start, int end, Class type) { - return select().getSpans(start, end, type); + return null; } @Override public int getSpanStart(Object tag) { - return select().getSpanStart(tag); + return -1; } @Override public int getSpanEnd(Object tag) { - return select().getSpanEnd(tag); + return -1; } @Override public int getSpanFlags(Object tag) { - return select().getSpanFlags(tag); + return 0; } @Override public int nextSpanTransition(int start, int limit, Class type) { - return select().nextSpanTransition(start, limit, type); + return -1; } + } - @Override - public int length() { - return select().length(); - } + public static Runnable makeDebounced(final long delayMs, final Runnable callback) { + return makeDebounced(null, delayMs, callback); + } - @Override - public char charAt(int index) { - return select().charAt(index); - } + // Debounce any callback + public static Runnable makeDebounced(final Handler handler, final long delayMs, final Runnable callback) { + final Handler _handler = handler == null ? new Handler(Looper.getMainLooper()) : handler; + final Object sync = new Object(); + return () -> { + synchronized (sync) { + _handler.removeCallbacks(callback); + _handler.postDelayed(callback, delayMs); + } + }; + } - @NonNull - @Override - public CharSequence subSequence(int start, int end) { - return select().subSequence(start, end); + // Converts region to string with a minimum of work + public static String toString(final CharSequence source, int start, int end) { + if (source instanceof String) { + // Already very fast + return ((String) source).substring(start, end); } + + final char[] buf = new char[end - start]; + TextUtils.getChars(source, start, end, buf, 0); + return new String(buf); } } diff --git a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java index 9d9d539a77..5e28b38e1e 100644 --- a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java +++ b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java @@ -2,8 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import net.gsantner.opoc.util.StringUtils; - import org.junit.Test; public class StringUtilsTest { diff --git a/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java b/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java index eea16db694..54df7ba763 100644 --- a/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java +++ b/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java @@ -15,7 +15,6 @@ import org.junit.Test; -import java.util.List; import java.util.regex.Matcher; public class ZimWikiReplacePatternGeneratorTests { @@ -147,7 +146,7 @@ private void assertCorrectReplacement(String original, String expectedReplacemen private String replaceWithFirstMatchingPattern(List replacePatterns, String input) { for (TextActions.ReplacePattern replacePattern : replacePatterns) { - Matcher matcher = replacePattern.searchPattern.matcher(input); + Matcher matcher = replacePattern.matcher.reset(input); if (matcher.find()) { return matcher.replaceFirst(replacePattern.replacePattern); } From 304c8923f8b4813b312d2b655ddd53459123a5f8 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 11:40:41 -0700 Subject: [PATCH 2/9] Cleaned inputs --- .../java/other/writeily/widget/WrWidgetConfigure.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/thirdparty/java/other/writeily/widget/WrWidgetConfigure.java b/app/thirdparty/java/other/writeily/widget/WrWidgetConfigure.java index 32cf8a71e3..f8fd6ed15f 100644 --- a/app/thirdparty/java/other/writeily/widget/WrWidgetConfigure.java +++ b/app/thirdparty/java/other/writeily/widget/WrWidgetConfigure.java @@ -12,9 +12,7 @@ import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; -import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; @@ -24,7 +22,6 @@ import net.gsantner.markor.util.AppSettings; import net.gsantner.markor.util.PermissionChecker; import net.gsantner.opoc.ui.FilesystemViewerData; -import net.gsantner.opoc.util.StringUtils; import java.io.File; From 6ba07ef74aabb49e72a4300b6d0c29f7ccc2bb9f Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 13:56:19 -0700 Subject: [PATCH 3/9] removed logging --- .../java/net/gsantner/markor/ui/hleditor/TextActions.java | 4 ---- app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java | 3 --- 2 files changed, 7 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java b/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java index 83101ec63d..1f39512e50 100644 --- a/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java +++ b/app/src/main/java/net/gsantner/markor/ui/hleditor/TextActions.java @@ -20,7 +20,6 @@ import android.support.v7.widget.TooltipCompat; import android.text.Editable; import android.text.TextUtils; -import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; @@ -388,14 +387,11 @@ public static void runRegexReplaceAction(final EditText editor, final ReplacePat * @param patterns An array of ReplacePattern */ public static void runRegexReplaceAction(final EditText editor, final List patterns) { - final long start = System.nanoTime(); if (editor instanceof HighlightingEditor) { ((HighlightingEditor) editor).withAutoFormatDisabled(() -> _runRegexReplaceAction(editor, patterns)); } else { _runRegexReplaceAction(editor, patterns); } - // TODO - remove - Log.i("markor_regex_replace", "" + 0.001 * (System.nanoTime() - start) + " us"); } private static void _runRegexReplaceAction(final EditText editor, final List patterns) { diff --git a/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java b/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java index ee24e6c901..41b0a477ab 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java +++ b/app/src/main/java/net/gsantner/opoc/util/NanoProfiler.java @@ -10,8 +10,6 @@ #########################################################*/ package net.gsantner.opoc.util; -import android.util.Log; - import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; @@ -73,7 +71,6 @@ public void end() { text = "NanoProfiler::: " + _groupCount + text; _debugText += text + "\n"; System.out.println(text); - Log.i("markor_regex_replace", text); } } } From 222b3396bfe4484df823c3879deb30426e431588 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 13:58:00 -0700 Subject: [PATCH 4/9] Unused imports --- app/src/main/java/net/gsantner/opoc/util/FileUtils.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index b84c51fadd..d0d2542569 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -13,8 +13,6 @@ import android.text.TextUtils; import android.util.Pair; -import org.w3c.dom.Text; - import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -29,8 +27,6 @@ import java.io.InputStreamReader; import java.io.Serializable; import java.net.URLConnection; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; From fa09373007dd44dc976ed9c815e9315d232b66f9 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 13:58:45 -0700 Subject: [PATCH 5/9] Removed unneeded diff --- app/src/main/java/net/gsantner/opoc/util/FileUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index d0d2542569..96e21d3e40 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -50,6 +50,7 @@ public class FileUtils { */ public static class FileInfo implements Serializable { public boolean hasBom = false; + public FileInfo withBom(boolean bom) { hasBom = bom; return this; @@ -64,7 +65,6 @@ public static Pair readTextFileFast(final File file) { final byte[] bomBuffer = new byte[3]; final int bomReadLength = inputStream.read(bomBuffer); - info.withBom(bomReadLength == 3 && bomBuffer[0] == (byte) 0xEF && bomBuffer[1] == (byte) 0xBB && From 86ca008552fc30560834f90d347afedca37ba960 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 13:59:29 -0700 Subject: [PATCH 6/9] Diffs --- app/src/main/java/net/gsantner/opoc/util/StringUtils.java | 3 --- app/src/test/java/net/gsantner/markor/StringUtilsTest.java | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java index d4a352c731..efacb4ef4f 100644 --- a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java @@ -14,16 +14,13 @@ import android.os.Looper; import android.support.annotation.NonNull; import android.text.Editable; -import android.text.GetChars; import android.text.InputFilter; import android.text.Layout; -import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.Base64; import android.widget.EditText; import android.widget.TextView; -import java.nio.CharBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java index 5e28b38e1e..9d9d539a77 100644 --- a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java +++ b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import net.gsantner.opoc.util.StringUtils; + import org.junit.Test; public class StringUtilsTest { From 1035ba20cdeb593710ca8b54627d1943dfac7576 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 21:32:20 -0700 Subject: [PATCH 7/9] Fixed test --- .../net/gsantner/markor/StringUtilsTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java index 9d9d539a77..310f8494ae 100644 --- a/app/src/test/java/net/gsantner/markor/StringUtilsTest.java +++ b/app/src/test/java/net/gsantner/markor/StringUtilsTest.java @@ -10,20 +10,20 @@ public class StringUtilsTest { @Test public void findDiffTest() { - assertThat(StringUtils.findDiff("", "")).isEqualTo(new int[] {0, 0, 0}); - assertThat(StringUtils.findDiff("abcd", "abcd")).isEqualTo(new int[] {4, 4, 4}); - assertThat(StringUtils.findDiff("ab", "abcd")).isEqualTo(new int[] {2, 2, 4}); - assertThat(StringUtils.findDiff("abcd", "ab")).isEqualTo(new int[] {2, 4, 2}); - assertThat(StringUtils.findDiff("ab1d", "ab2d")).isEqualTo(new int[] {2, 3, 3}); - assertThat(StringUtils.findDiff("ab12d", "ab34d")).isEqualTo(new int[] {2, 4, 4}); - assertThat(StringUtils.findDiff("ab12d", "ab3d")).isEqualTo(new int[] {2, 4, 3}); - assertThat(StringUtils.findDiff("ab12d", "abd")).isEqualTo(new int[] {2, 4, 2}); - assertThat(StringUtils.findDiff("abd", "ab12d")).isEqualTo(new int[] {2, 2, 4}); - assertThat(StringUtils.findDiff("abcd", "")).isEqualTo(new int[] {0, 4, 0}); - assertThat(StringUtils.findDiff("", "abcd")).isEqualTo(new int[] {0, 0, 4}); - assertThat(StringUtils.findDiff("ab11d", "ab1d")).isEqualTo(new int[] {3, 4, 3}); - assertThat(StringUtils.findDiff("aaaaa", "aaa")).isEqualTo(new int[] {3, 5, 3}); - assertThat(StringUtils.findDiff("aaa", "aaaaa")).isEqualTo(new int[] {3, 3, 5}); + assertThat(StringUtils.findDiff("", "", 0, 0)).isEqualTo(new int[] {0, 0, 0}); + assertThat(StringUtils.findDiff("abcd", "abcd", 0, 0)).isEqualTo(new int[] {4, 4, 4}); + assertThat(StringUtils.findDiff("ab", "abcd", 0, 0)).isEqualTo(new int[] {2, 2, 4}); + assertThat(StringUtils.findDiff("abcd", "ab", 0, 0)).isEqualTo(new int[] {2, 4, 2}); + assertThat(StringUtils.findDiff("ab1d", "ab2d", 0, 0)).isEqualTo(new int[] {2, 3, 3}); + assertThat(StringUtils.findDiff("ab12d", "ab34d", 0, 0)).isEqualTo(new int[] {2, 4, 4}); + assertThat(StringUtils.findDiff("ab12d", "ab3d", 0, 0)).isEqualTo(new int[] {2, 4, 3}); + assertThat(StringUtils.findDiff("ab12d", "abd", 0, 0)).isEqualTo(new int[] {2, 4, 2}); + assertThat(StringUtils.findDiff("abd", "ab12d", 0, 0)).isEqualTo(new int[] {2, 2, 4}); + assertThat(StringUtils.findDiff("abcd", "", 0, 0)).isEqualTo(new int[] {0, 4, 0}); + assertThat(StringUtils.findDiff("", "abcd", 0, 0)).isEqualTo(new int[] {0, 0, 4}); + assertThat(StringUtils.findDiff("ab11d", "ab1d", 0, 0)).isEqualTo(new int[] {3, 4, 3}); + assertThat(StringUtils.findDiff("aaaaa", "aaa", 0, 0)).isEqualTo(new int[] {3, 5, 3}); + assertThat(StringUtils.findDiff("aaa", "aaaaa", 0, 0)).isEqualTo(new int[] {3, 3, 5}); } } From bfd01061ffd2c084e0b92043daaf4542adea7b5e Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Sun, 5 Jun 2022 21:33:19 -0700 Subject: [PATCH 8/9] Fixed test --- .../format/zimwiki/ZimWikiReplacePatternGeneratorTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java b/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java index 54df7ba763..67c02fec44 100644 --- a/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java +++ b/app/src/test/java/net/gsantner/markor/format/zimwiki/ZimWikiReplacePatternGeneratorTests.java @@ -15,6 +15,7 @@ import org.junit.Test; +import java.util.List; import java.util.regex.Matcher; public class ZimWikiReplacePatternGeneratorTests { From 2f9c3f89e79c22153d5e9bfb6639355044833b81 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Wed, 8 Jun 2022 09:53:41 -0700 Subject: [PATCH 9/9] Bugfix when ok text == 0 --- .../net/gsantner/opoc/ui/SearchOrCustomTextDialog.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java index 4fbe043964..5e8e782817 100644 --- a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java +++ b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java @@ -342,10 +342,16 @@ public static void showMultiChoiceDialogWithSearchFilterUI(final Activity activi }; // Helper function to append selection count to OK button + final String okString = dopt.okButtonText != 0 ? activity.getString(dopt.okButtonText) : ""; final Button okButton = dialog.getButton(Dialog.BUTTON_POSITIVE); - final String okText = activity.getString(dopt.okButtonText) + (dopt.isMultiSelectEnabled ? " (%d)" : ""); final Callback.a0 setOkButtonState = () -> { - okButton.setText(okText.replace("%d", Integer.toString(listAdapter._selectedItems.size()))); + if (okButton != null) { + if (dopt.isMultiSelectEnabled) { + okButton.setText(okString + String.format(" (%d)", listAdapter._selectedItems.size())); + } else { + okButton.setText(okString); + } + } }; // Set ok button text initially