From 2d53e7a9924984e699582ad3d88981a40457bbc3 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 28 Nov 2025 21:40:25 +0800 Subject: [PATCH 01/17] Add Prism.js Visual Basic --- app/thirdparty/assets/prism/components/prism-vbnet.min.js | 1 + app/thirdparty/assets/prism/components/prism-visual-basic.min.js | 1 + 2 files changed, 2 insertions(+) create mode 100644 app/thirdparty/assets/prism/components/prism-vbnet.min.js create mode 100644 app/thirdparty/assets/prism/components/prism-visual-basic.min.js diff --git a/app/thirdparty/assets/prism/components/prism-vbnet.min.js b/app/thirdparty/assets/prism/components/prism-vbnet.min.js new file mode 100644 index 0000000000..8a148a86fc --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-vbnet.min.js @@ -0,0 +1 @@ +Prism.languages.vbnet=Prism.languages.extend("basic",{comment:[{pattern:/(?:!|REM\b).+/i,inside:{keyword:/^REM/i}},{pattern:/(^|[^\\:])'.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(^|[^"])"(?:""|[^"])*"(?!")/,lookbehind:!0,greedy:!0},keyword:/(?:\b(?:ADDHANDLER|ADDRESSOF|ALIAS|AND|ANDALSO|AS|BEEP|BLOAD|BOOLEAN|BSAVE|BYREF|BYTE|BYVAL|CALL(?: ABSOLUTE)?|CASE|CATCH|CBOOL|CBYTE|CCHAR|CDATE|CDBL|CDEC|CHAIN|CHAR|CHDIR|CINT|CLASS|CLEAR|CLNG|CLOSE|CLS|COBJ|COM|COMMON|CONST|CONTINUE|CSBYTE|CSHORT|CSNG|CSTR|CTYPE|CUINT|CULNG|CUSHORT|DATA|DATE|DECIMAL|DECLARE|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DEFAULT|DELEGATE|DIM|DIRECTCAST|DO|DOUBLE|ELSE|ELSEIF|END|ENUM|ENVIRON|ERASE|ERROR|EVENT|EXIT|FALSE|FIELD|FILES|FINALLY|FOR(?: EACH)?|FRIEND|FUNCTION|GET|GETTYPE|GETXMLNAMESPACE|GLOBAL|GOSUB|GOTO|HANDLES|IF|IMPLEMENTS|IMPORTS|IN|INHERITS|INPUT|INTEGER|INTERFACE|IOCTL|IS|ISNOT|KEY|KILL|LET|LIB|LIKE|LINE INPUT|LOCATE|LOCK|LONG|LOOP|LSET|ME|MKDIR|MOD|MODULE|MUSTINHERIT|MUSTOVERRIDE|MYBASE|MYCLASS|NAME|NAMESPACE|NARROWING|NEW|NEXT|NOT|NOTHING|NOTINHERITABLE|NOTOVERRIDABLE|OBJECT|OF|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPEN|OPERATOR|OPTION(?: BASE)?|OPTIONAL|OR|ORELSE|OUT|OVERLOADS|OVERRIDABLE|OVERRIDES|PARAMARRAY|PARTIAL|POKE|PRIVATE|PROPERTY|PROTECTED|PUBLIC|PUT|RAISEEVENT|READ|READONLY|REDIM|REM|REMOVEHANDLER|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SBYTE|SELECT(?: CASE)?|SET|SHADOWS|SHARED|SHELL|SHORT|SINGLE|SLEEP|STATIC|STEP|STOP|STRING|STRUCTURE|SUB|SWAP|SYNCLOCK|SYSTEM|THEN|THROW|TIMER|TO|TROFF|TRON|TRUE|TRY|TRYCAST|TYPE|TYPEOF|UINTEGER|ULONG|UNLOCK|UNTIL|USHORT|USING|VIEW PRINT|WAIT|WEND|WHEN|WHILE|WIDENING|WITH|WITHEVENTS|WRITE|WRITEONLY|XOR)|\B(?:#CONST|#ELSE|#ELSEIF|#END|#IF))(?:\$|\b)/i,punctuation:/[,;:(){}]/}); \ No newline at end of file diff --git a/app/thirdparty/assets/prism/components/prism-visual-basic.min.js b/app/thirdparty/assets/prism/components/prism-visual-basic.min.js new file mode 100644 index 0000000000..d18b6fafe6 --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-visual-basic.min.js @@ -0,0 +1 @@ +Prism.languages["visual-basic"]={comment:{pattern:/(?:['‘’]|REM\b)(?:[^\r\n_]|_(?:\r\n?|\n)?)*/i,inside:{keyword:/^REM/i}},directive:{pattern:/#(?:Const|Else|ElseIf|End|ExternalChecksum|ExternalSource|If|Region)(?:\b_[ \t]*(?:\r\n?|\n)|.)+/i,alias:"property",greedy:!0},string:{pattern:/\$?["“”](?:["“”]{2}|[^"“”])*["“”]C?/i,greedy:!0},date:{pattern:/#[ \t]*(?:\d+([/-])\d+\1\d+(?:[ \t]+(?:\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?))?|\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?)[ \t]*#/i,alias:"number"},number:/(?:(?:\b\d+(?:\.\d+)?|\.\d+)(?:E[+-]?\d+)?|&[HO][\dA-F]+)(?:[FRD]|U?[ILS])?/i,boolean:/\b(?:False|Nothing|True)\b/i,keyword:/\b(?:AddHandler|AddressOf|Alias|And(?:Also)?|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|C(?:Bool|Byte|Char|Date|Dbl|Dec|Int|Lng|Obj|SByte|Short|Sng|Str|Type|UInt|ULng|UShort)|Char|Class|Const|Continue|Currency|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else(?:If)?|End(?:If)?|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get(?:Type|XMLNamespace)?|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|Must(?:Inherit|Override)|My(?:Base|Class)|Namespace|Narrowing|New|Next|Not(?:Inheritable|Overridable)?|Object|Of|On|Operator|Option(?:al)?|Or(?:Else)?|Out|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TryCast|Type|TypeOf|U(?:Integer|Long|Short)|Until|Using|Variant|Wend|When|While|Widening|With(?:Events)?|WriteOnly|Xor)\b/i,operator:/[+\-*/\\^<=>&#@$%!]|\b_(?=[ \t]*[\r\n])/,punctuation:/[{}().,:?]/},Prism.languages.vb=Prism.languages["visual-basic"],Prism.languages.vba=Prism.languages["visual-basic"]; \ No newline at end of file From 1a4cf6bb299df36fb509a0ea21211ad01aae1dda Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 28 Nov 2025 23:50:11 +0800 Subject: [PATCH 02/17] Fix line numbers layout error for large wrapping words in view mode --- .../format/markdown/MarkdownTextConverter.java | 13 ++++++------- .../line-numbers/prism-line-numbers-markor.js | 2 +- app/thirdparty/assets/prism/prism-markor.js | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java index 8438db4135..4d11f8f469 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java @@ -281,9 +281,13 @@ public String convertMarkup(String markup, Context context, boolean lightMode, b // Enable View (block) code syntax highlighting if (markup.contains("```")) { head += getViewHlPrismIncludes(GsContextUtils.instance.isDarkModeEnabled(context) ? "-tomorrow" : "", enableLineNumbers); - onLoadJs += "usePrismCodeBlock();"; if (as.getDocumentWrapState(file.getAbsolutePath())) { - onLoadJs += "wrapCodeBlockWords();"; + onLoadJs += "wrapCode();"; + } + onLoadJs += "usePrism();"; + if (enableLineNumbers) { + // For Prism line numbers plugin + onLoadJs += "adjustLayout();enableLineNumbers();"; } } @@ -347,11 +351,6 @@ public String convertMarkup(String markup, Context context, boolean lightMode, b } } - if (enableLineNumbers) { - // For Prism line numbers plugin - onLoadJs += "enableLineNumbers(); adjustLineNumbers();"; - } - // Deliver result return putContentIntoTemplate(context, converted, lightMode, file, onLoadJs, head); } diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index 956dce1fd0..d9dc93bbd8 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -20,7 +20,7 @@ function getNumberDigits(number) { } } -function adjustLineNumbers() { +function adjustLayout() { let fontWidth = -1; const codeElements = document.querySelectorAll("pre > code"); codeElements.forEach((element) => { diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index 9a3b9f4ba5..00f0f20848 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -1,4 +1,4 @@ -function usePrismCodeBlock() { +function usePrism() { let elements = document.querySelectorAll("pre > code"); elements.forEach(function (element) { let attribute = element.getAttribute("class"); @@ -9,7 +9,7 @@ function usePrismCodeBlock() { }); } -function wrapCodeBlockWords() { +function wrapCode() { let preElements = document.querySelectorAll("pre"); preElements.forEach((element) => { element.style.whiteSpace = "pre-wrap"; From c247a57bff1dc554932c943083061c1549cab5ed Mon Sep 17 00:00:00 2001 From: guanglinn Date: Sat, 29 Nov 2025 11:06:08 +0800 Subject: [PATCH 03/17] Remove a duplicate Prism language file --- .../prism/components/prism-visual-basic.js | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 app/thirdparty/assets/prism/components/prism-visual-basic.js diff --git a/app/thirdparty/assets/prism/components/prism-visual-basic.js b/app/thirdparty/assets/prism/components/prism-visual-basic.js deleted file mode 100644 index 0afdb3ecf4..0000000000 --- a/app/thirdparty/assets/prism/components/prism-visual-basic.js +++ /dev/null @@ -1,29 +0,0 @@ -Prism.languages['visual-basic'] = { - 'comment': { - pattern: /(?:['‘’]|REM\b)(?:[^\r\n_]|_(?:\r\n?|\n)?)*/i, - inside: { - 'keyword': /^REM/i - } - }, - 'directive': { - pattern: /#(?:Const|Else|ElseIf|End|ExternalChecksum|ExternalSource|If|Region)(?:\b_[ \t]*(?:\r\n?|\n)|.)+/i, - alias: 'property', - greedy: true - }, - 'string': { - pattern: /\$?["“”](?:["“”]{2}|[^"“”])*["“”]C?/i, - greedy: true - }, - 'date': { - pattern: /#[ \t]*(?:\d+([/-])\d+\1\d+(?:[ \t]+(?:\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?))?|\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?)[ \t]*#/i, - alias: 'number' - }, - 'number': /(?:(?:\b\d+(?:\.\d+)?|\.\d+)(?:E[+-]?\d+)?|&[HO][\dA-F]+)(?:[FRD]|U?[ILS])?/i, - 'boolean': /\b(?:False|Nothing|True)\b/i, - 'keyword': /\b(?:AddHandler|AddressOf|Alias|And(?:Also)?|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|C(?:Bool|Byte|Char|Date|Dbl|Dec|Int|Lng|Obj|SByte|Short|Sng|Str|Type|UInt|ULng|UShort)|Char|Class|Const|Continue|Currency|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else(?:If)?|End(?:If)?|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get(?:Type|XMLNamespace)?|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|Must(?:Inherit|Override)|My(?:Base|Class)|Namespace|Narrowing|New|Next|Not(?:Inheritable|Overridable)?|Object|Of|On|Operator|Option(?:al)?|Or(?:Else)?|Out|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TryCast|Type|TypeOf|U(?:Integer|Long|Short)|Until|Using|Variant|Wend|When|While|Widening|With(?:Events)?|WriteOnly|Xor)\b/i, - 'operator': /[+\-*/\\^<=>&#@$%!]|\b_(?=[ \t]*[\r\n])/, - 'punctuation': /[{}().,:?]/ -}; - -Prism.languages.vb = Prism.languages['visual-basic']; -Prism.languages.vba = Prism.languages['visual-basic']; From ec0b2b4d62adeae64f237ec7d80e6a9a694c8f75 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 4 Dec 2025 20:50:23 +0800 Subject: [PATCH 04/17] Improve the code for using Prism --- .../markdown/MarkdownTextConverter.java | 15 ++------ .../line-numbers/prism-line-numbers-markor.js | 37 +++++++------------ app/thirdparty/assets/prism/prism-markor.js | 35 +++++++++++------- 3 files changed, 38 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java index 4d11f8f469..057681141b 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java @@ -278,17 +278,10 @@ public String convertMarkup(String markup, Context context, boolean lightMode, b } } - // Enable View (block) code syntax highlighting + // Enable code block (view mode) syntax highlighting if (markup.contains("```")) { head += getViewHlPrismIncludes(GsContextUtils.instance.isDarkModeEnabled(context) ? "-tomorrow" : "", enableLineNumbers); - if (as.getDocumentWrapState(file.getAbsolutePath())) { - onLoadJs += "wrapCode();"; - } - onLoadJs += "usePrism();"; - if (enableLineNumbers) { - // For Prism line numbers plugin - onLoadJs += "adjustLayout();enableLineNumbers();"; - } + onLoadJs += "usePrism('" + as.getDocumentWrapState(file.getAbsolutePath()) + "', '" + enableLineNumbers + "');"; } // Enable Mermaid @@ -385,7 +378,7 @@ private String escapeSpacesInLink(final String markup) { } @SuppressWarnings({"StringConcatenationInsideStringBufferAppend"}) - private String getViewHlPrismIncludes(final String theme, final boolean isLineNumbersEnabled) { + private String getViewHlPrismIncludes(final String theme, final boolean lineNumbers) { final StringBuilder sb = new StringBuilder(1000); sb.append(CSS_PREFIX + "prism/themes/prism" + theme + ".min.css" + CSS_POSTFIX); sb.append(CSS_PREFIX + "prism/prism-markor.css" + CSS_POSTFIX); @@ -398,7 +391,7 @@ private String getViewHlPrismIncludes(final String theme, final boolean isLineNu sb.append(JS_PREFIX + "prism/plugins/toolbar/prism-toolbar.min.js" + JS_POSTFIX); sb.append(JS_PREFIX + "prism/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js" + JS_POSTFIX); - if (isLineNumbersEnabled) { + if (lineNumbers) { sb.append(CSS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.css" + CSS_POSTFIX); sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers.min.js" + JS_POSTFIX); sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.js" + JS_POSTFIX); diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index d9dc93bbd8..0c2765736e 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -1,11 +1,3 @@ -function enableLineNumbers() { - let elements = document.querySelectorAll("pre:has(code)"); - elements.forEach(function (element) { - element.classList.add("line-numbers"); - }); - Prism.highlightAll(); -} - function getNumberDigits(number) { if (number < 10) { return 1; @@ -20,22 +12,19 @@ function getNumberDigits(number) { } } -function adjustLayout() { - let fontWidth = -1; - const codeElements = document.querySelectorAll("pre > code"); - codeElements.forEach((element) => { - const maxNumber = element.textContent.split("\n").length - 1; - if (maxNumber == 0) { - return; - } +let codeFontWidth = -1; +function adjustLayout(codeElement) { + const maxNumber = codeElement.textContent.split("\n").length - 1; + if (maxNumber == 0) { + return; + } - if (fontWidth == -1) { - const canvasContext = document.createElement("canvas").getContext("2d"); - canvasContext.font = window.getComputedStyle(element, null).getPropertyValue("font"); - fontWidth = canvasContext.measureText("0").width; - } + if (codeFontWidth == -1) { + const canvasContext = document.createElement("canvas").getContext("2d"); + canvasContext.font = window.getComputedStyle(codeElement, null).getPropertyValue("font"); + codeFontWidth = canvasContext.measureText("0").width; + } - const digits = getNumberDigits(maxNumber); - element.parentNode.style.paddingLeft = 2 * fontWidth + digits * fontWidth - digits + "px"; - }); + const digits = getNumberDigits(maxNumber); + codeElement.parentNode.style.paddingLeft = 2 * codeFontWidth + digits * codeFontWidth - digits + "px"; } diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index 00f0f20848..37c673be36 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -1,18 +1,25 @@ -function usePrism() { - let elements = document.querySelectorAll("pre > code"); - elements.forEach(function (element) { - let attribute = element.getAttribute("class"); - if (attribute == null || attribute.indexOf("language-") == -1) { - element.classList.add("language-text"); - Prism.highlightElement(element); +function usePrism(arg1, arg2) { + const wrapWords = arg1 === "true"; + const lineNumbers = arg2 === "true"; + const codeElements = document.querySelectorAll("pre > code"); + + codeElements.forEach((codeElement) => { + if (wrapWords) { + codeElement.parentNode.style.whiteSpace = "pre-wrap"; + codeElement.parentNode.style.overflowWrap = "break-word"; } - }); -} -function wrapCode() { - let preElements = document.querySelectorAll("pre"); - preElements.forEach((element) => { - element.style.whiteSpace = "pre-wrap"; - element.style.overflowWrap = "break-word"; + if (codeElement.getAttribute("class") == null) { + codeElement.classList.add("language-text"); + if (!lineNumbers) { + Prism.highlightElement(codeElement); + } + } + + if (lineNumbers) { + adjustLayout(codeElement); + codeElement.parentNode.classList.add("line-numbers"); + Prism.highlightElement(codeElement); + } }); } From bee0f7b1be6e2e067f1b07e6e85bff1b50baa0a6 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 4 Dec 2025 21:20:23 +0800 Subject: [PATCH 05/17] Tweaks --- CONTRIBUTORS.md | 2 +- .../textview/LineNumbersTextView.java | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f774bc57ce..36b1160c20 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -49,7 +49,7 @@ Where: * **[Frederic Jacob](https://github.com/fredericjacob)**
~° Added Zim-Wiki highlighting, text actions, view mode, page creation * **[Winston Feng](https://github.com/tifish)**
~° Support spaces in URL * **[k3b](https://github.com/k3b)**
~° Added CSV-Support -* **[Li Guanglin](https://github.com/guanglinn)**
~° Added line numbers support +* **[Li Guanglin](https://github.com/guanglinn)**
~° Added support for line numbers * **[bigger124](https://github.com/bigger124)**
~° Added OrgMode-Support * **[Ayowel](https://github.com/ayowel)**
~° Mermaid update * **[Matthew White](https://github.com/mehw)**
~° Zim-Wiki link/attachment conformance diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index e89c6465ba..a3bd2a6dc6 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -96,8 +96,8 @@ static class LineNumbersDrawer { private static final int EDITOR_PADDING_LEFT = 8; private final int ORIGINAL_PADDING_LEFT; - private final Rect visibleArea = new Rect(); - private final Rect lineNumbersArea = new Rect(); + private final Rect visibleRect = new Rect(); + private final Rect lineNumbersRect = new Rect(); private int fenceX; private int numberX; @@ -154,15 +154,15 @@ public EditText getEditText() { } private boolean isOutOfLineNumbersArea() { - final int margin = (int) (visibleArea.height() * 0.5f); - final int top = visibleArea.top - margin; - final int bottom = visibleArea.bottom + margin; + final int margin = (int) (visibleRect.height() * 0.5f); + final int top = visibleRect.top - margin; + final int bottom = visibleRect.bottom + margin; - if (top < lineNumbersArea.top || bottom > lineNumbersArea.bottom) { + if (top < lineNumbersRect.top || bottom > lineNumbersRect.bottom) { // Set line numbers area // height of line numbers area = (1.5 + 1 + 1.5) * height of visible area - lineNumbersArea.top = top - visibleArea.height(); - lineNumbersArea.bottom = bottom + visibleArea.height(); + lineNumbersRect.top = top - visibleRect.height(); + lineNumbersRect.bottom = bottom + visibleRect.height(); return true; } else { return false; @@ -272,7 +272,7 @@ public void prepare() { * @param canvas The canvas on which the line numbers will be drawn. */ public void draw(final Canvas canvas) { - if (!editText.getLocalVisibleRect(visibleArea)) { + if (!editText.getLocalVisibleRect(visibleRect)) { return; } @@ -299,7 +299,7 @@ public void draw(final Canvas canvas) { } // Draw right border of the fence - canvas.drawLine(fenceX, lineNumbersArea.top, fenceX, lineNumbersArea.bottom, paint); + canvas.drawLine(fenceX, lineNumbersRect.top, fenceX, lineNumbersRect.bottom, paint); // Draw line numbers int i = startLine[0]; @@ -308,7 +308,7 @@ public void draw(final Canvas canvas) { final int count = layout.getLineCount(); final int offsetY = editText.getPaddingTop(); - if (y > lineNumbersArea.top) { + if (y > lineNumbersRect.top) { if (invalid) { invalid = false; startLine[0] = i; @@ -322,14 +322,14 @@ public void draw(final Canvas canvas) { for (; i < count; i++) { if (text.charAt(layout.getLineStart(i) - 1) == '\n') { y = layout.getLineBaseline(i); - if (y > lineNumbersArea.top) { + if (y > lineNumbersRect.top) { if (invalid) { invalid = false; startLine[0] = i; startLine[1] = number; } canvas.drawText(String.valueOf(number), numberX, y + offsetY, paint); - if (y > lineNumbersArea.bottom) { + if (y > lineNumbersRect.bottom) { break; } } From b2634f522196e921ce7bafe425480955f3d79cab Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 11 Dec 2025 18:27:00 +0800 Subject: [PATCH 06/17] Auto-refresh Prism line numbers when font size changed in view mode --- .../activity/DocumentEditAndViewFragment.java | 3 +++ .../markdown/MarkdownTextConverter.java | 8 +++----- .../line-numbers/prism-line-numbers-markor.js | 19 +++++++++--------- app/thirdparty/assets/prism/prism-markor.js | 20 +++++++++++++++++-- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index a48245843a..e85ac97d7f 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -649,6 +649,9 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { MarkorDialogFactory.showFontSizeDialog(activity, current, (newSize) -> { if (_isPreviewVisible) { _webView.getSettings().setTextZoom((int) (newSize * VIEW_FONT_SCALE)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + _webView.evaluateJavascript("refreshPrism();", null); + } _appSettings.setDocumentViewFontSize(_document.path, newSize); } else { _hlEditor.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) newSize); diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java index 057681141b..36a597b383 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java @@ -391,11 +391,9 @@ private String getViewHlPrismIncludes(final String theme, final boolean lineNumb sb.append(JS_PREFIX + "prism/plugins/toolbar/prism-toolbar.min.js" + JS_POSTFIX); sb.append(JS_PREFIX + "prism/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js" + JS_POSTFIX); - if (lineNumbers) { - sb.append(CSS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.css" + CSS_POSTFIX); - sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers.min.js" + JS_POSTFIX); - sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.js" + JS_POSTFIX); - } + sb.append(CSS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.css" + CSS_POSTFIX); + sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers.min.js" + JS_POSTFIX); + sb.append(JS_PREFIX + "prism/plugins/line-numbers/prism-line-numbers-markor.js" + JS_POSTFIX); return sb.toString(); } diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index 0c2765736e..646681de59 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -12,19 +12,20 @@ function getNumberDigits(number) { } } -let codeFontWidth = -1; -function adjustLayout(codeElement) { +function getFontWidth(codeElement) { + const canvasContext = document.createElement("canvas").getContext("2d"); + canvasContext.font = window.getComputedStyle(codeElement, null).getPropertyValue("font"); + return canvasContext.measureText("0").width; +} + +function adjustLayout(codeElement, codeFontWidth) { const maxNumber = codeElement.textContent.split("\n").length - 1; if (maxNumber == 0) { return; } - if (codeFontWidth == -1) { - const canvasContext = document.createElement("canvas").getContext("2d"); - canvasContext.font = window.getComputedStyle(codeElement, null).getPropertyValue("font"); - codeFontWidth = canvasContext.measureText("0").width; - } - const digits = getNumberDigits(maxNumber); - codeElement.parentNode.style.paddingLeft = 2 * codeFontWidth + digits * codeFontWidth - digits + "px"; + const padding = 12 + (digits * codeFontWidth); + console.log(padding); + codeElement.parentNode.style.paddingLeft = padding + "px"; } diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index 37c673be36..f90699596a 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -1,7 +1,11 @@ function usePrism(arg1, arg2) { + const codeElements = document.querySelectorAll("pre > code"); + if (codeElements.length == 0) { + return; + } const wrapWords = arg1 === "true"; const lineNumbers = arg2 === "true"; - const codeElements = document.querySelectorAll("pre > code"); + const codeFontWidth = getFontWidth(codeElements[0]); codeElements.forEach((codeElement) => { if (wrapWords) { @@ -17,9 +21,21 @@ function usePrism(arg1, arg2) { } if (lineNumbers) { - adjustLayout(codeElement); + adjustLayout(codeElement, codeFontWidth); codeElement.parentNode.classList.add("line-numbers"); Prism.highlightElement(codeElement); } }); } + +function refreshPrism() { + const codeElements = document.querySelectorAll("pre > code"); + if (codeElements.length == 0) { + return; + } + const codeFontWidth = getFontWidth(codeElements[0]); + codeElements.forEach((codeElement) => { + adjustLayout(codeElement, codeFontWidth); + Prism.highlightElement(codeElement); + }); +} From 4de68286e4b080f31d41ec56b58672f57eace38b Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 11 Dec 2025 18:56:02 +0800 Subject: [PATCH 07/17] Switch line numbers is available in view mode --- .../activity/DocumentEditAndViewFragment.java | 7 ++++-- .../line-numbers/prism-line-numbers-markor.js | 1 - app/thirdparty/assets/prism/prism-markor.js | 25 ++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index e85ac97d7f..61abc87bfe 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -621,6 +621,9 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { final boolean newState = !_lineNumbersView.isLineNumbersEnabled(); _appSettings.setDocumentLineNumbersEnabled(_document.path, newState); _lineNumbersView.setLineNumbersEnabled(newState); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + _webView.evaluateJavascript("setLineNumbers('" + newState + "');", null); + } updateMenuToggleStates(0); return true; } @@ -649,8 +652,8 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { MarkorDialogFactory.showFontSizeDialog(activity, current, (newSize) -> { if (_isPreviewVisible) { _webView.getSettings().setTextZoom((int) (newSize * VIEW_FONT_SCALE)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - _webView.evaluateJavascript("refreshPrism();", null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && _lineNumbersView.isLineNumbersEnabled()) { + _webView.evaluateJavascript("refreshLineNumbers();", null); } _appSettings.setDocumentViewFontSize(_document.path, newSize); } else { diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index 646681de59..8281a4f1ca 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -26,6 +26,5 @@ function adjustLayout(codeElement, codeFontWidth) { const digits = getNumberDigits(maxNumber); const padding = 12 + (digits * codeFontWidth); - console.log(padding); codeElement.parentNode.style.paddingLeft = padding + "px"; } diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index f90699596a..44a5c51769 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -28,7 +28,7 @@ function usePrism(arg1, arg2) { }); } -function refreshPrism() { +function refreshLineNumbers() { const codeElements = document.querySelectorAll("pre > code"); if (codeElements.length == 0) { return; @@ -39,3 +39,26 @@ function refreshPrism() { Prism.highlightElement(codeElement); }); } + +function setLineNumbers(enabled) { + const codeElements = document.querySelectorAll("pre > code"); + if (codeElements.length == 0) { + return; + } + const lineNumbers = enabled === "true"; + + if (lineNumbers) { + const codeFontWidth = getFontWidth(codeElements[0]); + codeElements.forEach((codeElement) => { + adjustLayout(codeElement, codeFontWidth); + codeElement.parentNode.classList.add("line-numbers"); + Prism.highlightElement(codeElement); + }); + } else { + codeElements.forEach((codeElement) => { + codeElement.parentNode.classList.remove("line-numbers"); + codeElement.parentNode.style.paddingLeft = "12px"; + Prism.highlightElement(codeElement); + }); + } +} From 0b76fee0477b09bc1701d7838d80b6c29b83e431 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 11 Dec 2025 19:52:39 +0800 Subject: [PATCH 08/17] Switch wrap words of code blocks is available in view mode --- .../activity/DocumentEditAndViewFragment.java | 3 +++ app/thirdparty/assets/prism/prism-markor.js | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 61abc87bfe..a525952b52 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -614,6 +614,9 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { final boolean newState = !isWrapped(); _appSettings.setDocumentWrapState(_document.path, newState); setWrapState(newState); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + _webView.evaluateJavascript("setWrapWords('" + newState + "');", null); + } updateMenuToggleStates(0); return true; } diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index 44a5c51769..545b277056 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -62,3 +62,25 @@ function setLineNumbers(enabled) { }); } } + +function setWrapWords(enabled) { + const codeElements = document.querySelectorAll("pre > code"); + if (codeElements.length == 0) { + return; + } + const wrapWords = enabled === "true"; + + if (wrapWords) { + codeElements.forEach((codeElement) => { + codeElement.parentNode.style.whiteSpace = "pre-wrap"; + codeElement.parentNode.style.overflowWrap = "break-word"; + Prism.highlightElement(codeElement); + }); + } else { + codeElements.forEach((codeElement) => { + codeElement.parentNode.style.whiteSpace = null; + codeElement.parentNode.style.overflowWrap = null; + Prism.highlightElement(codeElement); + }); + } +} From aff075b48d54927fea0580137d55a367a8895339 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 11 Dec 2025 20:25:47 +0800 Subject: [PATCH 09/17] Tweak paddings of Prism --- .../plugins/line-numbers/prism-line-numbers-markor.js | 4 ++-- app/thirdparty/assets/prism/prism-markor.js | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index 8281a4f1ca..ecaa671db9 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -18,13 +18,13 @@ function getFontWidth(codeElement) { return canvasContext.measureText("0").width; } -function adjustLayout(codeElement, codeFontWidth) { +function preparePaddings(codeElement, codeFontWidth) { const maxNumber = codeElement.textContent.split("\n").length - 1; if (maxNumber == 0) { return; } const digits = getNumberDigits(maxNumber); - const padding = 12 + (digits * codeFontWidth); + const padding = 12 + digits * codeFontWidth; codeElement.parentNode.style.paddingLeft = padding + "px"; } diff --git a/app/thirdparty/assets/prism/prism-markor.js b/app/thirdparty/assets/prism/prism-markor.js index 545b277056..5abe2ca50f 100644 --- a/app/thirdparty/assets/prism/prism-markor.js +++ b/app/thirdparty/assets/prism/prism-markor.js @@ -8,6 +8,8 @@ function usePrism(arg1, arg2) { const codeFontWidth = getFontWidth(codeElements[0]); codeElements.forEach((codeElement) => { + codeElement.parentNode.style.paddingLeft = "8px"; + codeElement.parentNode.style.paddingRight = "8px"; if (wrapWords) { codeElement.parentNode.style.whiteSpace = "pre-wrap"; codeElement.parentNode.style.overflowWrap = "break-word"; @@ -21,7 +23,7 @@ function usePrism(arg1, arg2) { } if (lineNumbers) { - adjustLayout(codeElement, codeFontWidth); + preparePaddings(codeElement, codeFontWidth); codeElement.parentNode.classList.add("line-numbers"); Prism.highlightElement(codeElement); } @@ -35,7 +37,7 @@ function refreshLineNumbers() { } const codeFontWidth = getFontWidth(codeElements[0]); codeElements.forEach((codeElement) => { - adjustLayout(codeElement, codeFontWidth); + preparePaddings(codeElement, codeFontWidth); Prism.highlightElement(codeElement); }); } @@ -50,14 +52,14 @@ function setLineNumbers(enabled) { if (lineNumbers) { const codeFontWidth = getFontWidth(codeElements[0]); codeElements.forEach((codeElement) => { - adjustLayout(codeElement, codeFontWidth); + preparePaddings(codeElement, codeFontWidth); codeElement.parentNode.classList.add("line-numbers"); Prism.highlightElement(codeElement); }); } else { codeElements.forEach((codeElement) => { codeElement.parentNode.classList.remove("line-numbers"); - codeElement.parentNode.style.paddingLeft = "12px"; + codeElement.parentNode.style.paddingLeft = "8px"; Prism.highlightElement(codeElement); }); } From abaa935f221a0818e812b98e06740c601e13f556 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Thu, 11 Dec 2025 22:05:36 +0800 Subject: [PATCH 10/17] Minor improvements --- .../assets/prism/plugins/toolbar/prism-toolbar.css | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css b/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css index 503b89134d..700872d093 100644 --- a/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css +++ b/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css @@ -44,18 +44,19 @@ div.code-toolbar > .toolbar > .toolbar-item > a, div.code-toolbar > .toolbar > .toolbar-item > button, div.code-toolbar > .toolbar > .toolbar-item > span { color: #aaa; - font-size: 0.8em; + font-size: 0.9em; text-transform: none; background: rgba(215, 215, 215, 0.4); box-shadow: 0 2px 0 0 rgba(150, 150, 150, 0.8); border-radius: 0.5em; display: inline-block; min-width: 80%; - max-height: 1.75em; - padding-left: 0.45em; - padding-right: 0.45em; + min-height: 1.75em; + height: 90%; + padding-left: 0.4em; + padding-right: 0.4em; padding-top: 0.1em; - padding-bottom: 0.1em; + padding-bottom: 0.15em; } div.code-toolbar > .toolbar > .toolbar-item > a:hover, From c5afa71855c5f8d42bbfb362be072800ac0393b6 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 12 Dec 2025 09:02:03 +0800 Subject: [PATCH 11/17] Tweaks --- .../prism/plugins/line-numbers/prism-line-numbers-markor.js | 2 +- .../assets/prism/plugins/toolbar/prism-toolbar.css | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js index ecaa671db9..058814c92e 100644 --- a/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js +++ b/app/thirdparty/assets/prism/plugins/line-numbers/prism-line-numbers-markor.js @@ -25,6 +25,6 @@ function preparePaddings(codeElement, codeFontWidth) { } const digits = getNumberDigits(maxNumber); - const padding = 12 + digits * codeFontWidth; + const padding = 14 + digits * codeFontWidth; codeElement.parentNode.style.paddingLeft = padding + "px"; } diff --git a/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css b/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css index 700872d093..9399a56f37 100644 --- a/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css +++ b/app/thirdparty/assets/prism/plugins/toolbar/prism-toolbar.css @@ -48,11 +48,11 @@ div.code-toolbar > .toolbar > .toolbar-item > span { text-transform: none; background: rgba(215, 215, 215, 0.4); box-shadow: 0 2px 0 0 rgba(150, 150, 150, 0.8); - border-radius: 0.5em; + border-radius: 0.4em; display: inline-block; min-width: 80%; - min-height: 1.75em; - height: 90%; + min-height: 1.7em; + height: 80%; padding-left: 0.4em; padding-right: 0.4em; padding-top: 0.1em; From 89759594e688d2701a3cff533ddca7c4267d16cb Mon Sep 17 00:00:00 2001 From: guanglinn Date: Wed, 24 Dec 2025 19:35:05 +0800 Subject: [PATCH 12/17] Add Zig --- app/thirdparty/assets/prism/components/prism-zig.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/thirdparty/assets/prism/components/prism-zig.min.js diff --git a/app/thirdparty/assets/prism/components/prism-zig.min.js b/app/thirdparty/assets/prism/components/prism-zig.min.js new file mode 100644 index 0000000000..26316b4604 --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-zig.min.js @@ -0,0 +1 @@ +!function(e){function n(e){return function(){return e}}var r=/\b(?:align|allowzero|and|anyframe|anytype|asm|async|await|break|cancel|catch|comptime|const|continue|defer|else|enum|errdefer|error|export|extern|fn|for|if|inline|linksection|nakedcc|noalias|nosuspend|null|or|orelse|packed|promise|pub|resume|return|stdcallcc|struct|suspend|switch|test|threadlocal|try|undefined|union|unreachable|usingnamespace|var|volatile|while)\b/,a="\\b(?!"+r.source+")(?!\\d)\\w+\\b",o="align\\s*\\((?:[^()]|\\([^()]*\\))*\\)",s="(?!\\s)(?:!?\\s*(?:"+"(?:\\?|\\bpromise->|(?:\\[[^[\\]]*\\]|\\*(?!\\*)|\\*\\*)(?:\\s*|\\s*const\\b|\\s*volatile\\b|\\s*allowzero\\b)*)".replace(//g,n(o))+"\\s*)*"+"(?:\\bpromise\\b|(?:\\berror\\.)?(?:\\.)*(?!\\s+))".replace(//g,n(a))+")+";e.languages.zig={comment:[{pattern:/\/\/[/!].*/,alias:"doc-comment"},/\/{2}.*/],string:[{pattern:/(^|[^\\@])c?"(?:[^"\\\r\n]|\\.)*"/,lookbehind:!0,greedy:!0},{pattern:/([\r\n])([ \t]+c?\\{2}).*(?:(?:\r\n?|\n)\2.*)*/,lookbehind:!0,greedy:!0}],char:{pattern:/(^|[^\\])'(?:[^'\\\r\n]|[\uD800-\uDFFF]{2}|\\(?:.|x[a-fA-F\d]{2}|u\{[a-fA-F\d]{1,6}\}))'/,lookbehind:!0,greedy:!0},builtin:/\B@(?!\d)\w+(?=\s*\()/,label:{pattern:/(\b(?:break|continue)\s*:\s*)\w+\b|\b(?!\d)\w+\b(?=\s*:\s*(?:\{|while\b))/,lookbehind:!0},"class-name":[/\b(?!\d)\w+(?=\s*=\s*(?:(?:extern|packed)\s+)?(?:enum|struct|union)\s*[({])/,{pattern:RegExp("(:\\s*)(?=\\s*(?:\\s*)?[=;,)])|(?=\\s*(?:\\s*)?\\{)".replace(//g,n(s)).replace(//g,n(o))),lookbehind:!0,inside:null},{pattern:RegExp("(\\)\\s*)(?=\\s*(?:\\s*)?;)".replace(//g,n(s)).replace(//g,n(o))),lookbehind:!0,inside:null}],"builtin-type":{pattern:/\b(?:anyerror|bool|c_u?(?:int|long|longlong|short)|c_longdouble|c_void|comptime_(?:float|int)|f(?:16|32|64|128)|[iu](?:8|16|32|64|128|size)|noreturn|type|void)\b/,alias:"keyword"},keyword:r,function:/\b(?!\d)\w+(?=\s*\()/,number:/\b(?:0b[01]+|0o[0-7]+|0x[a-fA-F\d]+(?:\.[a-fA-F\d]*)?(?:[pP][+-]?[a-fA-F\d]+)?|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)\b/,boolean:/\b(?:false|true)\b/,operator:/\.[*?]|\.{2,3}|[-=]>|\*\*|\+\+|\|\||(?:<<|>>|[-+*]%|[-+*/%^&|<>!=])=?|[?~]/,punctuation:/[.:,;(){}[\]]/},e.languages.zig["class-name"].forEach((function(n){null===n.inside&&(n.inside=e.languages.zig)}))}(Prism); \ No newline at end of file From 5f7c9f943bae555a88a66f25b8d1aced95550d3f Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 2 Jan 2026 13:27:13 +0800 Subject: [PATCH 13/17] Add Nginx --- app/thirdparty/assets/prism/components/prism-nginx.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/thirdparty/assets/prism/components/prism-nginx.min.js diff --git a/app/thirdparty/assets/prism/components/prism-nginx.min.js b/app/thirdparty/assets/prism/components/prism-nginx.min.js new file mode 100644 index 0000000000..ac2b6559e2 --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-nginx.min.js @@ -0,0 +1 @@ +!function(e){var n=/\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;e.languages.nginx={comment:{pattern:/(^|[\s{};])#.*/,lookbehind:!0,greedy:!0},directive:{pattern:/(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:{string:{pattern:/((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,lookbehind:!0,greedy:!0,inside:{escape:{pattern:/\\["'\\nrt]/,alias:"entity"},variable:n}},comment:{pattern:/(\s)#.*/,lookbehind:!0,greedy:!0},keyword:{pattern:/^\S+/,greedy:!0},boolean:{pattern:/(\s)(?:off|on)(?!\S)/,lookbehind:!0},number:{pattern:/(\s)\d+[a-z]*(?!\S)/i,lookbehind:!0},variable:n}},punctuation:/[{};]/}}(Prism); \ No newline at end of file From bec13ed75ddd99b75c2f09975ae48c5313936647 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 2 Jan 2026 13:28:06 +0800 Subject: [PATCH 14/17] Add Less --- app/thirdparty/assets/prism/components/prism-less.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/thirdparty/assets/prism/components/prism-less.min.js diff --git a/app/thirdparty/assets/prism/components/prism-less.min.js b/app/thirdparty/assets/prism/components/prism-less.min.js new file mode 100644 index 0000000000..f4a10f66a1 --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-less.min.js @@ -0,0 +1 @@ +Prism.languages.less=Prism.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),Prism.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}); \ No newline at end of file From 353d7719e5012a62faf63518a8927e178305d029 Mon Sep 17 00:00:00 2001 From: guanglinn Date: Fri, 2 Jan 2026 13:40:14 +0800 Subject: [PATCH 15/17] Add Properties --- app/thirdparty/assets/prism/components/prism-properties.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/thirdparty/assets/prism/components/prism-properties.min.js diff --git a/app/thirdparty/assets/prism/components/prism-properties.min.js b/app/thirdparty/assets/prism/components/prism-properties.min.js new file mode 100644 index 0000000000..5976d47656 --- /dev/null +++ b/app/thirdparty/assets/prism/components/prism-properties.min.js @@ -0,0 +1 @@ +Prism.languages.properties={comment:/^[ \t]*[#!].*$/m,value:{pattern:/(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?: *[=:] *(?! )| ))(?:\\(?:\r\n|[\s\S])|[^\\\r\n])+/m,lookbehind:!0,alias:"attr-value"},key:{pattern:/^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?= *[=:]| )/m,alias:"attr-name"},punctuation:/[=:]/}; \ No newline at end of file From 7a0bd8656c8c54b2dc96b88e15f184d9750f079b Mon Sep 17 00:00:00 2001 From: guanglinn Date: Wed, 7 Jan 2026 23:40:55 +0800 Subject: [PATCH 16/17] Improve LineNumbersView --- .../activity/DocumentEditAndViewFragment.java | 9 ++-- ...bersTextView.java => LineNumbersView.java} | 51 ++++++++++++------- .../res/layout/document__fragment__edit.xml | 18 +++---- 3 files changed, 45 insertions(+), 33 deletions(-) rename app/src/main/java/net/gsantner/markor/frontend/textview/{LineNumbersTextView.java => LineNumbersView.java} (89%) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 62b3d2cb2e..e2b4efca7f 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -53,7 +53,7 @@ import net.gsantner.markor.frontend.MarkorDialogFactory; import net.gsantner.markor.frontend.filebrowser.MarkorFileBrowserFactory; import net.gsantner.markor.frontend.textview.HighlightingEditor; -import net.gsantner.markor.frontend.textview.LineNumbersTextView; +import net.gsantner.markor.frontend.textview.LineNumbersView; import net.gsantner.markor.frontend.textview.TextViewUtils; import net.gsantner.markor.model.AppSettings; import net.gsantner.markor.model.Document; @@ -102,7 +102,7 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do private DraggableScrollbarScrollView _verticalScrollView; private HorizontalScrollView _horizontalScrollView; - private LineNumbersTextView _lineNumbersView; + private LineNumbersView _lineNumbersView; private SearchView _menuSearchViewForViewMode; private Document _document; private FormatRegistry _format; @@ -598,7 +598,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { final boolean newState = !isWrapped(); _appSettings.setDocumentWrapState(_document.path, newState); setWrapState(newState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (_isPreviewVisible && _webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { _webView.evaluateJavascript("setWrapWords('" + newState + "');", null); } updateMenuToggleStates(0); @@ -608,7 +608,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { final boolean newState = !_lineNumbersView.isLineNumbersEnabled(); _appSettings.setDocumentLineNumbersEnabled(_document.path, newState); _lineNumbersView.setLineNumbersEnabled(newState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (_isPreviewVisible && _webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { _webView.evaluateJavascript("setLineNumbers('" + newState + "');", null); } updateMenuToggleStates(0); @@ -662,6 +662,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { } } } + public void checkTextChangeState() { final boolean isTextChanged = !_document.isContentSame(_hlEditor.getText()); Drawable d; diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersView.java similarity index 89% rename from app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java rename to app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersView.java index a3bd2a6dc6..164e74bcfa 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersView.java @@ -13,28 +13,33 @@ import android.widget.EditText; import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatTextView; @SuppressWarnings("UnusedReturnValue") -public class LineNumbersTextView extends AppCompatTextView { +public class LineNumbersView extends View { private EditText editText; private LineNumbersDrawer lineNumbersDrawer; private boolean lineNumbersEnabled; - public LineNumbersTextView(Context context) { + public LineNumbersView(Context context) { super(context); } - public LineNumbersTextView(Context context, AttributeSet attrs) { + public LineNumbersView(Context context, AttributeSet attrs) { super(context, attrs); } - public LineNumbersTextView(Context context, AttributeSet attrs, int defStyleAttr) { + public LineNumbersView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override - protected void onVisibilityChanged(View changedView, int visibility) { + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + setWidth(0); // Initial width + } + + @Override + protected void onVisibilityChanged(@NonNull View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (isLineNumbersEnabled() && visibility == View.VISIBLE) { refresh(); @@ -42,15 +47,18 @@ protected void onVisibilityChanged(View changedView, int visibility) { } @Override - protected void onDraw(Canvas canvas) { + protected void onDraw(@NonNull Canvas canvas) { super.onDraw(canvas); if (lineNumbersEnabled) { lineNumbersDrawer.draw(canvas); } } + /** + * Refresh LineNumbersView. + */ public void refresh() { - setText(""); // To activate LineNumbersTextView refresh + invalidate(); if (getWidth() == 0) { lineNumbersDrawer.getEditText().postInvalidate(); } @@ -64,6 +72,11 @@ public void setup(final @NonNull EditText editText) { this.lineNumbersDrawer = null; } + public void setWidth(int width) { + getLayoutParams().width = width; + requestLayout(); + } + public void setLineNumbersEnabled(final boolean enabled) { lineNumbersEnabled = enabled; @@ -76,7 +89,7 @@ public void setLineNumbersEnabled(final boolean enabled) { if (lineNumbersDrawer == null) { return; } - lineNumbersDrawer.done(); + lineNumbersDrawer.cleanup(); } refresh(); } @@ -87,7 +100,7 @@ public boolean isLineNumbersEnabled() { static class LineNumbersDrawer { private final EditText editText; - private final LineNumbersTextView textView; + private final LineNumbersView lineNumbersView; private final Paint paint = new Paint(); @@ -123,7 +136,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { @Override public void afterTextChanged(Editable editable) { if (isLayoutLineCountChanged() || isMaxNumberChanged()) { - textView.refresh(); + lineNumbersView.refresh(); } } }; @@ -136,14 +149,14 @@ public void onScrollChanged() { final long time = System.currentTimeMillis(); if (time - lastTime > 125) { lastTime = time; - textView.refresh(); + lineNumbersView.refresh(); } } }; - public LineNumbersDrawer(final @NonNull EditText editText, final @NonNull LineNumbersTextView textView) { + public LineNumbersDrawer(final @NonNull EditText editText, final @NonNull LineNumbersView lineNumbersView) { this.editText = editText; - this.textView = textView; + this.lineNumbersView = lineNumbersView; ORIGINAL_PADDING_LEFT = editText.getPaddingLeft(); paint.setColor(0xFF999999); paint.setTextAlign(Paint.Align.RIGHT); @@ -262,7 +275,8 @@ private void setRefreshOnScrollChanged(final boolean enabled) { public void prepare() { setLineTracking(true); setRefreshOnScrollChanged(true); - textView.setVisibility(VISIBLE); + lineNumbersView.setWidth(0); + lineNumbersView.setVisibility(VISIBLE); editText.setPadding(EDITOR_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } @@ -286,7 +300,7 @@ public void draw(final Canvas canvas) { if (isTextSizeChanged() || isMaxNumberDigitsChanged()) { numberX = NUMBER_PADDING_LEFT + (int) paint.measureText(String.valueOf(maxNumber)); fenceX = numberX + NUMBER_PADDING_RIGHT; - textView.setWidth(fenceX + 1); + lineNumbersView.setWidth(fenceX + 1); } // If current visible area is out of current line numbers area, @@ -341,12 +355,11 @@ public void draw(final Canvas canvas) { /** * Reset some states related line numbers. */ - public void done() { + public void cleanup() { setLineTracking(false); setRefreshOnScrollChanged(false); maxNumberDigits = 0; - textView.setWidth(0); - textView.setVisibility(GONE); + lineNumbersView.setVisibility(GONE); editText.setPadding(ORIGINAL_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } } diff --git a/app/src/main/res/layout/document__fragment__edit.xml b/app/src/main/res/layout/document__fragment__edit.xml index a258093aa1..9a25bfe26a 100644 --- a/app/src/main/res/layout/document__fragment__edit.xml +++ b/app/src/main/res/layout/document__fragment__edit.xml @@ -30,32 +30,30 @@ android:layout_height="wrap_content" android:orientation="horizontal"> - + android:layout_height="match_parent" /> @@ -79,10 +77,10 @@ + android:layout_marginBottom="@dimen/textactions_bar_height" + android:layout="@layout/document__fragment_view" /> Date: Thu, 8 Jan 2026 04:22:06 +0100 Subject: [PATCH 17/17] fix --- .../gsantner/markor/activity/DocumentEditAndViewFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index d50584a98b..8fc63ddb43 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -104,7 +104,7 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do private DraggableScrollbarScrollView _verticalScrollView; private HorizontalScrollView _horizontalScrollView; - private LineNumbersTextView _lineNumbersView; + private LineNumbersView _lineNumbersView; private SearchView _menuSearchViewForViewMode; private Document _document; private FormatRegistry _format;