Skip to content

Implement support for big files and Markdown preview#4576

Open
TranceLove wants to merge 3 commits intoTeamAmaze:release/4.0from
TranceLove:feature/text-editor-big-file-markdown
Open

Implement support for big files and Markdown preview#4576
TranceLove wants to merge 3 commits intoTeamAmaze:release/4.0from
TranceLove:feature/text-editor-big-file-markdown

Conversation

@TranceLove
Copy link
Collaborator

@TranceLove TranceLove commented Feb 26, 2026

Description

Implement support for big files and Markdown preview.

With this PR, sliding window is used for buffering big files to prevent OutOfMemory error.

out.mp4

The sliding window currently is set to 102400 characters.

Additionally, using https://github.com/commonmark/commonmark-java support for Markdown preview is also added.

Screenshot_20260226-223920_Amaze Debug Screenshot_20260226-223930_Amaze Debug

Note however, due to the way Commonmark works that it doesn't support dynamically updating output HTML from InputStream, when switching to Markdown preview, it will only render what's inside the sliding window above, if file content is bigger than the sliding window.

Issue tracker

Automatic tests

  • Added test cases

Manual tests

  • Done

Device: Fairphone 5
OS: LineageOS 23.2 (Android 16)

Build tasks success

Successfully running following tasks on local:

  • ./gradlew assembledebug
  • ./gradlew spotlessCheck

@EmmanuelMess
Copy link
Member

EmmanuelMess commented Feb 26, 2026

Probably should add the images as part of the repo or use images with some assurance they won't break in the near future (wikimedia?).

Second video in the description might be broken.

@TranceLove TranceLove force-pushed the feature/text-editor-big-file-markdown branch 3 times, most recently from 6d8b5ef to 41f0f13 Compare February 26, 2026 15:33
@VishnuSanal VishnuSanal self-requested a review February 26, 2026 16:45
@EmmanuelMess
Copy link
Member

Should fix #1275.

Uses Commonmark for Markdown parsing and rendering.

Due to the way Commonmark works, it cannot support content streaming and update in realtime; user needs to let TextEditorActivity to load as much content as wish.
@TranceLove
Copy link
Collaborator Author

Sidenote: when TextEditorActivity sees the file is big or in Markdown preview mode, it will be in readonly mode and you cannot save the file.

Another story... need to think of a way to track the changed area in the big file which is not easy to do.

Same goes to Markdown mode. I was just thinking of a way to conveniently read Markdowns on the move...

Copy link
Member

@EmmanuelMess EmmanuelMess left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on API 21 on emulator.

You can go down a large (~200MB) file but you cannot go back to the start, I think there is a bug in the sliding window.

The Markdown library crashed:

2026-03-01 22:17:27.608  5524-5524  InputEventReceiver      com.amaze.filemanager.debug          E  Exception dispatching input event.
2026-03-01 22:17:27.608  5524-5524  MessageQueue-JNI        com.amaze.filemanager.debug          E  Exception in MessageQueue callback: handleReceiveCallback
2026-03-01 22:17:27.608  5524-5524  MessageQueue-JNI        com.amaze.filemanager.debug          E  java.lang.NoClassDefFoundError: org.commonmark.internal.InlineParserImpl$$ExternalSyntheticLambda2
                                                                                                    	at org.commonmark.internal.InlineParserImpl.createInlineContentParsers(InlineParserImpl.java:142)
                                                                                                    	at org.commonmark.internal.InlineParserImpl.reset(InlineParserImpl.java:180)
                                                                                                    	at org.commonmark.internal.InlineParserImpl.parse(InlineParserImpl.java:158)
                                                                                                    	at org.commonmark.internal.HeadingParser.parseInlines(HeadingParser.java:37)
                                                                                                    	at org.commonmark.internal.DocumentParser.processInlines(DocumentParser.java:482)
                                                                                                    	at org.commonmark.internal.DocumentParser.finalizeAndProcess(DocumentParser.java:528)
                                                                                                    	at org.commonmark.internal.DocumentParser.parse(DocumentParser.java:142)
                                                                                                    	at org.commonmark.parser.Parser.parse(Parser.java:78)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.MarkdownHtmlGenerator.renderToHtml(MarkdownHtmlGenerator.kt:50)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.renderMarkdownToWebView(TextEditorActivity.java:787)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.toggleMarkdownPreview(TextEditorActivity.java:767)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.onOptionsItemSelected(TextEditorActivity.java:385)
                                                                                                    	at android.app.Activity.onMenuItemSelected(Activity.java:2882)
                                                                                                    	at androidx.activity.ComponentActivity.onMenuItemSelected(ComponentActivity.java:529)
                                                                                                    	at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:265)
                                                                                                    	at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:269)
                                                                                                    	at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:110)
                                                                                                    	at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:66)
                                                                                                    	at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:225)
                                                                                                    	at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:781)
                                                                                                    	at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:836)
                                                                                                    	at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:159)
                                                                                                    	at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:987)
                                                                                                    	at androidx.appcompat.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
                                                                                                    	at android.widget.AdapterView.performItemClick(AdapterView.java:300)
                                                                                                    	at android.widget.AbsListView.performItemClick(AbsListView.java:1143)
                                                                                                    	at android.widget.AbsListView$PerformClick.run(AbsListView.java:3044)
                                                                                                    	at android.widget.AbsListView.onTouchUp(AbsListView.java:3845)
                                                                                                    	at android.widget.AbsListView.onTouchEvent(AbsListView.java:3617)
                                                                                                    	at androidx.appcompat.widget.DropDownListView.onTouchEvent(DropDownListView.java:236)
                                                                                                    	at androidx.appcompat.widget.MenuPopupWindow$MenuDropDownListView.onTouchEvent(MenuPopupWindow.java:140)
                                                                                                    	at android.view.View.dispatchTouchEvent(View.java:8388)
                                                                                                    	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2424)
                                                                                                    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2158)
                                                                                                    	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
                                                                                                    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
                                                                                                    	at android.widget.PopupWindow$PopupViewContainer.dispatchTouchEvent(PopupWindow.java:1682)
                                                                                                    	at android.view.View.dispatchPointerEvent(View.java:8578)
                                                                                                    	at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4021)
                                                                                                    	at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3887)
                                                                                                    	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
                                                                                                    	at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
                                                                                                    	at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
                                                                                                    	at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3578)
                                                                                                    	at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
                                                                                                    	at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3635)
                                                                                                    	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
                                                                                                    	at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.jav
2026-03-01 22:17:27.609  5524-5524  AndroidRuntime          com.amaze.filemanager.debug          D  Shutting down VM
2026-03-01 22:17:27.609  5524-5524  ACRA                    com.amaze.filemanager.debug          E  ACRA caught a NoClassDefFoundError for com.amaze.filemanager.debug
                                                                                                    java.lang.NoClassDefFoundError: org.commonmark.internal.InlineParserImpl$$ExternalSyntheticLambda2
                                                                                                    	at org.commonmark.internal.InlineParserImpl.createInlineContentParsers(InlineParserImpl.java:142)
                                                                                                    	at org.commonmark.internal.InlineParserImpl.reset(InlineParserImpl.java:180)
                                                                                                    	at org.commonmark.internal.InlineParserImpl.parse(InlineParserImpl.java:158)
                                                                                                    	at org.commonmark.internal.HeadingParser.parseInlines(HeadingParser.java:37)
                                                                                                    	at org.commonmark.internal.DocumentParser.processInlines(DocumentParser.java:482)
                                                                                                    	at org.commonmark.internal.DocumentParser.finalizeAndProcess(DocumentParser.java:528)
                                                                                                    	at org.commonmark.internal.DocumentParser.parse(DocumentParser.java:142)
                                                                                                    	at org.commonmark.parser.Parser.parse(Parser.java:78)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.MarkdownHtmlGenerator.renderToHtml(MarkdownHtmlGenerator.kt:50)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.renderMarkdownToWebView(TextEditorActivity.java:787)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.toggleMarkdownPreview(TextEditorActivity.java:767)
                                                                                                    	at com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity.onOptionsItemSelected(TextEditorActivity.java:385)
                                                                                                    	at android.app.Activity.onMenuItemSelected(Activity.java:2882)
                                                                                                    	at androidx.activity.ComponentActivity.onMenuItemSelected(ComponentActivity.java:529)
                                                                                                    	at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:265)
                                                                                                    	at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:269)
                                                                                                    	at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:110)
                                                                                                    	at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:66)
                                                                                                    	at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:225)
                                                                                                    	at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:781)
                                                                                                    	at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:836)
                                                                                                    	at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:159)
                                                                                                    	at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:987)
                                                                                                    	at androidx.appcompat.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
                                                                                                    	at android.widget.AdapterView.performItemClick(AdapterView.java:300)
                                                                                                    	at android.widget.AbsListView.performItemClick(AbsListView.java:1143)
                                                                                                    	at android.widget.AbsListView$PerformClick.run(AbsListView.java:3044)
                                                                                                    	at android.widget.AbsListView.onTouchUp(AbsListView.java:3845)
                                                                                                    	at android.widget.AbsListView.onTouchEvent(AbsListView.java:3617)
                                                                                                    	at androidx.appcompat.widget.DropDownListView.onTouchEvent(DropDownListView.java:236)
                                                                                                    	at androidx.appcompat.widget.MenuPopupWindow$MenuDropDownListView.onTouchEvent(MenuPopupWindow.java:140)
                                                                                                    	at android.view.View.dispatchTouchEvent(View.java:8388)
                                                                                                    	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2424)
                                                                                                    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2158)
                                                                                                    	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
                                                                                                    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
                                                                                                    	at android.widget.PopupWindow$PopupViewContainer.dispatchTouchEvent(PopupWindow.java:1682)
                                                                                                    	at android.view.View.dispatchPointerEvent(View.java:8578)
                                                                                                    	at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4021)
                                                                                                    	at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3887)
                                                                                                    	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
                                                                                                    	at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
                                                                                                    	at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
                                                                                                    	at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3578)
                                                                                                    	at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
                                                                                                    	at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3635)
                                                                                                    	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
                                                                                                    	at android.view.V

Added Android Desugaring library for lower Android compatibility

Band-it solution for now - will be removed when minimal version requirements bumped to Android 8
@TranceLove TranceLove force-pushed the feature/text-editor-big-file-markdown branch from 41f0f13 to bc401d9 Compare March 2, 2026 16:07
@TranceLove
Copy link
Collaborator Author

TranceLove commented Mar 2, 2026

Added desugaring library as seen in https://developer.android.com/studio/write/java8-support-table for supporting lower Androids.

Can think as band-it solution, can remove once we move up to Android 8 as minimal requirement.

@EmmanuelMess
Copy link
Member

Is it just me or is the loading of the text file windows glitchy? Sometimes it throws you to the top of the file, and then back to to the position you were in, other times it leaves you on the top of the file, sometimes it skips lines when loading a window (scrolling is not smooth). I think the windows might not be of equal size?
Test file, tested on emulator API 21 (by furiously scrolling 20k lines repeatedly):

Archivo de Texto.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants