Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
04e57de
fix: stabilize editor layout sizing to prevent large-file open slowdown
lrq3000 Mar 14, 2026
04dc0dc
fix: Refactor speed regression fix duplications into a function syncE…
lrq3000 Mar 16, 2026
8650730
docs: add lrq3000 in CONTRIBUTORS.md
lrq3000 Mar 14, 2026
f68822f
feat(editor): First draft implementation of a RecyclerView EditText e…
lrq3000 Mar 14, 2026
230f8ad
feat(editor): Refactor editor architecture to enable format features …
lrq3000 Mar 14, 2026
f71936f
docs: update lrq3000 contribution's description in CONTRIBUTORS.md
lrq3000 Mar 14, 2026
249cd13
feat: lower threshold from 1 MiB down to 512 KiB to enable large file…
lrq3000 Mar 17, 2026
2b08681
fix: restore format actions and TOC navigation functionalities in Rec…
lrq3000 Mar 17, 2026
5d397a8
fix: cursor jumping or loss of focus after typing for a second in Rec…
lrq3000 Mar 17, 2026
e78017e
fix: implement TodoTxt actions for the RecyclerTextEditor by removing…
lrq3000 Mar 17, 2026
22962ee
fix: todo.txt actions with RecyclerTextEditor (but causes crash)
lrq3000 Mar 17, 2026
f0ba331
fix(todotxt): add MarkorEditor-safe dialog overloads in MarkorDialogF…
lrq3000 Mar 17, 2026
f96c524
fix: build crash because of duplicated code in MarkorDialogFactory.java
lrq3000 Mar 17, 2026
1d97ed3
fix: Fix crash in TodoTxtSyntaxHighlighter when loading todotxt in Re…
lrq3000 Mar 17, 2026
e67575d
fix: Fix cursor erratic jumping and new item creation bugs in Recycle…
google-labs-jules[bot] Mar 17, 2026
077aef4
fix: fix RecyclerTextEditor erratic cursor jump and stuck cursor on n…
google-labs-jules[bot] Mar 19, 2026
ae41638
fix(editor): refresh focused line highlights and harden newline split…
lrq3000 Mar 19, 2026
da6c17d
fix(large-files-editor): fix backspace on empty line not deleting the…
lrq3000 Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ Where:
* **[Matthew White](https://github.com/mehw)**<br>~° Zim-Wiki link/attachment conformance
* **[Markus Paintner](https://github.com/goli4thus)**<br/>~° Added duplicate lines action
* **[Janez Pavel Žebovec](https://janezpavelzebovec.net/)**<br/>~° Slovenian translation
* **[Stephen Karl Larroque](https://github.com/lrq3000/)**<br/>~° Bugfixes and large files speed performance

Large diffs are not rendered by default.

41 changes: 26 additions & 15 deletions app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
Expand All @@ -42,7 +43,7 @@
import net.gsantner.markor.frontend.MarkorDialogFactory;
import net.gsantner.markor.frontend.MarkorDialogFactory.Heading;
import net.gsantner.markor.frontend.textsearch.TextSearchFragment;
import net.gsantner.markor.frontend.textview.HighlightingEditor;
import net.gsantner.markor.frontend.textview.MarkorEditor;
import net.gsantner.markor.frontend.textview.TextViewUtils;
import net.gsantner.markor.model.AppSettings;
import net.gsantner.markor.model.Document;
Expand Down Expand Up @@ -74,7 +75,7 @@ public abstract class ActionButtonBase {
private final int _buttonHorizontalMargin;
private String _lastSnip;

protected HighlightingEditor _hlEditor;
protected MarkorEditor _hlEditor;
protected WebView _webView;
protected Document _document;
protected AppSettings _appSettings;
Expand Down Expand Up @@ -458,7 +459,7 @@ public void runRegexReplaceAction(final String pattern, final String replace) {
runRegexReplaceAction(Collections.singletonList(new ReplacePattern(pattern, replace)));
}

public static void runRegexReplaceAction(final EditText editor, final ReplacePattern... patterns) {
public static void runRegexReplaceAction(final MarkorEditor editor, final ReplacePattern... patterns) {
runRegexReplaceAction(editor, Arrays.asList(patterns));
}

Expand All @@ -468,9 +469,17 @@ public static void runRegexReplaceAction(final EditText editor, final ReplacePat
*
* @param patterns An array of ReplacePattern
*/
public static void runRegexReplaceAction(final MarkorEditor editor, final List<ReplacePattern> patterns) {
editor.withAutoFormatDisabled(() -> runRegexReplaceAction(editor.getText(), patterns));
}

public static void runRegexReplaceAction(final EditText editor, final ReplacePattern... patterns) {
runRegexReplaceAction(editor, Arrays.asList(patterns));
}

public static void runRegexReplaceAction(final EditText editor, final List<ReplacePattern> patterns) {
if (editor instanceof HighlightingEditor) {
((HighlightingEditor) editor).withAutoFormatDisabled(() -> runRegexReplaceAction(editor.getText(), patterns));
if (editor instanceof MarkorEditor) {
runRegexReplaceAction((MarkorEditor) editor, patterns);
} else {
runRegexReplaceAction(editor.getText(), patterns);
}
Expand Down Expand Up @@ -589,7 +598,7 @@ protected void runSurroundAction(final String open, final String close, final bo
_hlEditor.setSelection(ss + ol, se + ol);
}

public ActionButtonBase setUiReferences(@Nullable final Activity activity, @Nullable final HighlightingEditor hlEditor, @Nullable final WebView webview) {
public ActionButtonBase setUiReferences(@Nullable final Activity activity, @Nullable final MarkorEditor hlEditor, @Nullable final WebView webview) {
_activity = activity;
_hlEditor = hlEditor;
_webView = webview;
Expand Down Expand Up @@ -657,7 +666,7 @@ protected final boolean runCommonAction(final @StringRes int action) {
return true;
}
case R.string.abid_common_accordion: {
_hlEditor.insertOrReplaceTextOnCursor("<details markdown='1'><summary>" + rstr(R.string.expand_collapse) + "</summary>\n" + HighlightingEditor.PLACE_CURSOR_HERE_TOKEN + "\n\n</details>");
_hlEditor.insertOrReplaceTextOnCursor("<details markdown='1'><summary>" + rstr(R.string.expand_collapse) + "</summary>\n" + MarkorEditor.PLACE_CURSOR_HERE_TOKEN + "\n\n</details>");
return true;
}
case R.string.abid_common_insert_audio: {
Expand Down Expand Up @@ -690,18 +699,18 @@ protected final boolean runCommonAction(final @StringRes int action) {
}
case R.string.abid_common_insert_snippet: {
MarkorDialogFactory.showInsertSnippetDialog(_activity, (snip) -> {
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolateSnippet(snip, _document.title, TextViewUtils.getSelectedText(_hlEditor)));
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolateSnippet(snip, _document.title, TextViewUtils.getSelectedText(_hlEditor.getText())));
_lastSnip = snip;
});
return true;
}
case R.string.abid_common_open_link_browser: {
final int sel = TextViewUtils.getSelection(_hlEditor)[0];
final int sel = TextViewUtils.getSelection(_hlEditor.getText())[0];
if (sel < 0) {
return true;
}

final String line = TextViewUtils.getSelectedLines(_hlEditor, sel);
final String line = TextViewUtils.getSelectedLines(_hlEditor.getText(), sel);
final int cursor = sel - TextViewUtils.getLineStart(_hlEditor.getText(), sel);

// First try to pull a resource
Expand Down Expand Up @@ -736,7 +745,7 @@ protected final boolean runCommonAction(final @StringRes int action) {
}
case R.string.abid_common_new_line_below: {
// Go to end of line, works with wrapped lines too
final int sel = TextViewUtils.getSelection(_hlEditor)[1];
final int sel = TextViewUtils.getSelection(_hlEditor.getText())[1];
if (sel > 0) {
_hlEditor.setSelection(TextViewUtils.getLineEnd(text, sel));
_hlEditor.simulateKeyPress(KeyEvent.KEYCODE_ENTER);
Expand Down Expand Up @@ -818,12 +827,14 @@ protected final boolean runCommonLongPressAction(@StringRes int action) {
}
case R.string.abid_common_move_text_one_line_up:
case R.string.abid_common_move_text_one_line_down: {
TextViewUtils.showSelection(_hlEditor);
if (_hlEditor.getView() instanceof TextView) {
TextViewUtils.showSelection((TextView) _hlEditor.getView());
}
return true;
}
case R.string.abid_common_insert_snippet: {
if (!TextUtils.isEmpty(_lastSnip)) {
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolateSnippet(_lastSnip, _document.title, TextViewUtils.getSelectedText(_hlEditor)));
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolateSnippet(_lastSnip, _document.title, TextViewUtils.getSelectedText(_hlEditor.getText())));
}
return true;
}
Expand Down Expand Up @@ -886,7 +897,7 @@ public ActionItem setRepeatable(boolean repeatable) {
}
}

public static void moveLineSelectionBy1(final HighlightingEditor hlEditor, final boolean isUp) {
public static void moveLineSelectionBy1(final MarkorEditor hlEditor, final boolean isUp) {
final Editable text = hlEditor.getText();
final int[] sel = TextViewUtils.getSelection(text);
if (text == null || sel[0] < 0) {
Expand Down Expand Up @@ -918,7 +929,7 @@ public static void moveLineSelectionBy1(final HighlightingEditor hlEditor, final
}
}

public static void duplicateLineSelection(final HighlightingEditor hlEditor) {
public static void duplicateLineSelection(final MarkorEditor hlEditor) {
// Duplication is performed downwards, selection is moving alongside it and
// cursor is preserved regarding column position (helpful for editing the
// newly created line at the selected position right away).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.content.Context;
import android.text.Editable;
import android.view.KeyEvent;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
Expand Down Expand Up @@ -165,20 +166,20 @@ public boolean onActionClick(final @StringRes int action) {
* @param delim - Delimiter to surround text with
*/
private void runLineSurroundAction(final Pattern pattern, final String delim) {
final int[] sel = TextViewUtils.getSelection(_hlEditor);
final int[] sel = TextViewUtils.getSelection(_hlEditor.getText());
if (sel[0] < 0) {
return;
}

final String lineBefore = sel[0] == sel[1] ? TextViewUtils.getSelectedLines(_hlEditor, sel[0]) : null;
final String lineBefore = sel[0] == sel[1] ? TextViewUtils.getSelectedLines(_hlEditor.getText(), sel[0]) : null;
runRegexReplaceAction(
new ReplacePattern(pattern, "$1$2$4$6"),
new ReplacePattern(LINE_NONE, "$1$2" + delim + "$3" + delim + "$4")
);

// This logic sets the cursor to the inside of the delimiters if the delimiters were empty
if (lineBefore != null) {
final String lineAfter = TextViewUtils.getSelectedLines(_hlEditor, sel[0]);
final String lineAfter = TextViewUtils.getSelectedLines(_hlEditor.getText(), sel[0]);
final String pair = delim + delim;
if (lineAfter.length() - lineBefore.length() == pair.length() && lineAfter.trim().endsWith(pair)) {
final Editable text = _hlEditor.getText();
Expand Down Expand Up @@ -216,7 +217,14 @@ public boolean onActionLongClick(final @StringRes int action) {
case R.string.abid_common_checkbox_list: {
MarkorDialogFactory.showDocumentChecklistDialog(
getActivity(), _hlEditor.getText(), CHECKED_LIST_LINE, 4, "xX", " ",
pos -> TextViewUtils.setSelectionAndShow(_hlEditor, pos));
pos -> {
if (_hlEditor.getView() instanceof EditText) {
TextViewUtils.setSelectionAndShow((EditText) _hlEditor.getView(), pos);
} else {
_hlEditor.requestFocus();
_hlEditor.setSelection(pos);
}
});
return true;
}
default: {
Expand Down Expand Up @@ -264,7 +272,7 @@ public static Link extract(final CharSequence text, final int pos) {
}

private boolean followLinkUnderCursor() {
final int sel = TextViewUtils.getSelection(_hlEditor)[0];
final int sel = TextViewUtils.getSelection(_hlEditor.getText())[0];
if (sel < 0) {
return false;
}
Expand All @@ -291,7 +299,7 @@ private void insertTableRow(int cols, boolean isHeaderEnabled) {
_hlEditor.requestFocus();

// Append if current line empty
final int[] sel = TextViewUtils.getLineSelection(_hlEditor);
final int[] sel = TextViewUtils.getLineSelection(_hlEditor.getText());
if (sel[0] != -1 && sel[0] == sel[1]) {
sb.append("\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected int getFormatActionsKey() {
@SuppressLint("NonConstantResourceId")
@Override
public boolean onActionClick(final @StringRes int action) {
final List<TodoTxtTask> selTasks = TodoTxtTask.getSelectedTasks(_hlEditor);
final List<TodoTxtTask> selTasks = TodoTxtTask.getSelectedTasks(_hlEditor.getText(), TextViewUtils.getSelection(_hlEditor.getText()));

switch (action) {
case R.string.abid_todotxt_toggle_done: {
Expand Down Expand Up @@ -159,7 +159,7 @@ public boolean onActionLongClick(final @StringRes int action) {
}
case R.string.abid_todotxt_priority: {
final Editable text = _hlEditor.getText();
final int[] sel = TextViewUtils.getSelection(_hlEditor);
final int[] sel = TextViewUtils.getSelection(_hlEditor.getText());
final int lineStart = TextViewUtils.getLineStart(text, sel[0]);
final int lineEnd = TextViewUtils.getLineEnd(text, sel[1]);
final List<TodoTxtTask> tasks = TodoTxtTask.getTasks(text, new int[]{sel[0], sel[1]});
Expand Down Expand Up @@ -245,7 +245,7 @@ public void archiveDoneTasks() {
if (new Document(doneFile).saveContent(getActivity(), doneContents.toString())) {
final String tasksString = TodoTxtTask.tasksToString(keep);
_hlEditor.setText(tasksString);
TextViewUtils.setSelectionFromOffsets(_hlEditor, offsets);
TextViewUtils.setSelectionFromOffsets(_hlEditor.getText(), offsets);
}
}
_appSettings.setLastTodoDoneName(_document.path, doneName);
Expand Down Expand Up @@ -273,7 +273,7 @@ private void addRemoveItems(
final TodoTxtTask additional = new TodoTxtTask(_appSettings.getTodotxtAdditionalContextsAndProjects());
all.addAll(keyGetter.callback(Collections.singletonList(additional)));

final Set<String> current = new HashSet<>(keyGetter.callback(TodoTxtTask.getSelectedTasks(_hlEditor)));
final Set<String> current = new HashSet<>(keyGetter.callback(TodoTxtTask.getSelectedTasks(_hlEditor.getText(), TextViewUtils.getSelection(_hlEditor.getText()))));

final boolean append = _appSettings.isTodoAppendProConOnEndEnabled();

Expand Down Expand Up @@ -396,7 +396,7 @@ private void setDate() {


private void setDueDate(final int offset) {
final String dueString = TodoTxtTask.getSelectedTasks(_hlEditor).get(0).getDueDate();
final String dueString = TodoTxtTask.getSelectedTasks(_hlEditor.getText(), TextViewUtils.getSelection(_hlEditor.getText())).get(0).getDueDate();
Calendar initDate = parseDateString(dueString, Calendar.getInstance());
initDate.add(Calendar.DAY_OF_MONTH, (dueString == null || dueString.isEmpty()) ? offset : 0);

Expand Down Expand Up @@ -514,4 +514,4 @@ public void onCreate(final Bundle savedInstanceState) {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public TodoTxtSyntaxHighlighter(final AppSettings as) {
public SyntaxHighlighterBase configure(Paint paint) {
super.configure(paint);

if (paint == null) {
paint = new Paint();
}

_delay = _appSettings.getHighlightingDelayTodoTxt();
final boolean dark = MarkorContextUtils.instance.isDarkModeEnabled(_appSettings.getContext());
_paragraphSpan = new ParagraphDividerSpan(paint, dark ? 0x44FFFFFF : 0xFFDDDDDD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ public static List<TodoTxtTask> getSelectedTasks(final TextView view) {
return getTasks(view.getText(), TextViewUtils.getSelection(view));
}

public static List<TodoTxtTask> getSelectedTasks(final CharSequence text, final int[] sel) {
return getTasks(text, sel);
}

public static List<TodoTxtTask> getAllTasks(final CharSequence text) {
return getTasks(text, new int[]{0, text.length()});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void openLink() {
}

private String tryExtractWikitextLink() {
int cursorPos = TextViewUtils.getSelection(_hlEditor)[0];
int cursorPos = TextViewUtils.getSelection(_hlEditor.getText())[0];
CharSequence text = _hlEditor.getText();
int lineStart = TextViewUtils.getLineStart(text, cursorPos);
int lineEnd = TextViewUtils.getLineEnd(text, cursorPos);
Expand All @@ -216,11 +216,11 @@ private void toggleHeading(int headingLevel) {
final CharSequence text = _hlEditor.getText();
runRegexReplaceAction(WikitextReplacePatternGenerator.setOrUnsetHeadingWithLevel(headingLevel));

final int[] lineSelection = TextViewUtils.getLineSelection(_hlEditor);
final int[] lineSelection = TextViewUtils.getLineSelection(_hlEditor.getText());
Matcher m = WikitextSyntaxHighlighter.HEADING.matcher(text.subSequence(lineSelection[0], lineSelection[1]));
if (m.find()) {
final int afterHeadingTextOffset = m.end(3);
final int lineStart = TextViewUtils.getLineStart(text, TextViewUtils.getSelection(_hlEditor)[0]);
final int lineStart = TextViewUtils.getLineStart(text, TextViewUtils.getSelection(_hlEditor.getText())[0]);
_hlEditor.setSelection(lineStart + afterHeadingTextOffset);
}
}
Expand Down Expand Up @@ -286,4 +286,4 @@ public boolean onReceiveKeyPress(final int keyCode, final KeyEvent event) {

return super.onReceiveKeyPress(keyCode, event);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import androidx.core.os.ConfigurationCompat;

import net.gsantner.markor.R;
import net.gsantner.markor.frontend.textview.HighlightingEditor;
import net.gsantner.markor.frontend.textview.MarkorEditor;
import net.gsantner.markor.model.AppSettings;
import net.gsantner.opoc.model.GsSharedPreferencesPropertyBackend;
import net.gsantner.opoc.util.GsContextUtils;
Expand Down Expand Up @@ -78,10 +78,10 @@ public class DatetimeFormatDialog {

/**
* @param activity {@link Activity} from which is {@link DatetimeFormatDialog} called
* @param hlEditor {@link HighlightingEditor} which 'll add selected result to cursor position
* @param hlEditor {@link MarkorEditor} which 'll add selected result to cursor position
*/
@SuppressLint({"ClickableViewAccessibility", "SetTextI18n, InflateParams"})
public static void showDatetimeFormatDialog(final Activity activity, final HighlightingEditor hlEditor) {
public static void showDatetimeFormatDialog(final Activity activity, final MarkorEditor hlEditor) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Rounded);
final View viewRoot = activity.getLayoutInflater().inflate(R.layout.time_format_dialog, null);

Expand Down Expand Up @@ -352,4 +352,4 @@ public static String getMostRecentDate(final Context context) {
return "";
}
}
}
}
Loading