Skip to content

adding txt2tags-it: support to txt2tags syntax in addition to md#282

Closed
luginf wants to merge 10 commits intoqownnotes:mainfrom
luginf:main
Closed

adding txt2tags-it: support to txt2tags syntax in addition to md#282
luginf wants to merge 10 commits intoqownnotes:mainfrom
luginf:main

Conversation

@luginf
Copy link
Copy Markdown

@luginf luginf commented Apr 11, 2026

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new QOwnNotes script (txt2tags-it) that extends the existing markdown-it based renderer to also understand a subset of txt2tags syntax in both preview rendering and editor highlighting.

Changes:

  • Introduces a new txt2tags-it renderer script that wires a txt2tags markdown-it plugin and optional editor highlighting rules.
  • Adds a new markdown-it plugin (markdown-it-txt2tags.js) implementing txt2tags-style headings/comments/lists and inline formatting.
  • Bundles required markdown-it-related JS resources and adds script metadata/docs.

Reviewed changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
txt2tags-it/txt2tags-it.qml New renderer script integrating markdown-it + optional deflist/KaTeX + txt2tags plugin + editor highlighting rules.
txt2tags-it/markdown-it-txt2tags.js New markdown-it plugin implementing txt2tags syntax features.
txt2tags-it/markdown-it-deflist.js Bundled definition list plugin dependency for markdown-it.
txt2tags-it/info.json Script metadata/resources list for QOwnNotes script loader.
txt2tags-it/README.md Minimal documentation for the new script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread txt2tags-it/info.json Outdated
Comment on lines +12 to +15
"version": "1.5",
"minAppVersion": "20.6.0",
"description": "This script replaces the default markdown renderer with markdown-it and allows for optional LaTeX rendering support with the Markdown-It KaTeX plugin. (NOTE: LaTeX defaults to rendering with MathML ONLY). \n\n<b>Dependencies</b>\n<a href=\"https://github.com/markdown-it/markdown-it\">markdown-it.js</a> (v8.4.2 bundled with the script)\n<a href=\"https://github.com/mdit-plugins/mdit-plugins/tree/main/packages/katex\">Markdown-It KaTeX plugin</a> (v0.18.0 bundled with the script)\n\n<b>Usage</b>\nFor the possible configuration options check <a href=\"https://github.com/markdown-it/markdown-it/tree/main/lib/presets\">here</a>.\n\n<b>Important</b>\nThis script currently only works with <a href=\"https://github.com/qownnotes/scripts/issues/77\"><b>legacy media links</b></a>. You can turn them on in the <i>General Settings</i>.\n\nImportant note: You need to use legacy image linking with this script, otherwise there will be no images shown in the preview!"
}
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

info.json’s description still describes only the markdown-it + KaTeX renderer and doesn’t mention the new txt2tags syntax support that this script adds. This is inconsistent with the script’s purpose/title and will confuse users browsing available scripts. Update the description to include txt2tags support (and any constraints, e.g. which txt2tags features are implemented).

Copilot uses AI. Check for mistakes.
Comment thread txt2tags-it/txt2tags-it.qml Outdated
finalPath = rawPath.replace(/\\/g, '/');
else
// Relative path → resolve against base
finalPath = resolvePath(basePath, rawPath.replace(/^\.\/+/, ''));
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

resolvePath(basePath, ...) references basePath, but no such variable is defined in this function (the computed base directory is stored in path). This will throw at runtime when a relative src/href is encountered, breaking preview/export rendering. Pass the correct base variable (likely path) into resolvePath (or rename consistently).

Suggested change
finalPath = resolvePath(basePath, rawPath.replace(/^\.\/+/, ''));
finalPath = resolvePath(path, rawPath.replace(/^\.\/+/, ''));

Copilot uses AI. Check for mistakes.
Comment thread txt2tags-it/txt2tags-it.qml Outdated
Comment on lines +131 to +135
mdHtml = mdHtml.replace(/(\b(?:src|href|data-[\w-]+)\s*=\s*["'])([^"']+)["']/gi, (_, prefix, rawPath) => {
// Convert backslashes to forward slashes for URL

if (isProtocolUrl(rawPath))
return `${prefix}${rawPath}"`;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

The URL rewrite returns strings that always end with a double quote (e.g. return `${prefix}${rawPath}"`;). Since the match can start with either ' or ", this can generate malformed HTML when the original attribute used single quotes. Capture/reuse the original quote character in the replacement.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess that needs fixing, @luginf.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@pbek fixed in next commit

Example of the bug:

  • Original HTML: src='image.png'
  • Produced result: src='file:///path/image.png" ← malformed

Fix: capture the quote character in a separate group and reuse it as the closing quote.

What changed:

  • The regex now splits attr (e.g. src=) and quote (the " or ' character) into two separate groups, and \2
    ensures the closing quote matches the opening one.
  • Both return statements use ${quote} to open and close — the HTML stays well-formed.

Comment thread txt2tags-it/txt2tags-it.qml Outdated
Comment on lines +143 to +145
finalPath = resolvePath(basePath, rawPath.replace(/^\.\/+/, ''));
return `${prefix}file://${finalPath}"`;
});
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

Same quoting issue here: return `${prefix}file://${finalPath}"`; always emits a double quote regardless of whether the original attribute used ' or ". Reuse the original quote character (e.g. by capturing it) to avoid producing invalid HTML.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It guess that needs fixing, @luginf.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It guess that needs fixing, @luginf.

done as well

Comment thread txt2tags-it/txt2tags-it.qml Outdated
{
"identifier": "useKatexPlugin",
"name": "LaTeX Support",
"text": "Enable the Markdown-it definition list KaTeX plugin",
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

The useKatexPlugin setting text says "Enable the Markdown-it definition list KaTeX plugin", which is misleading (it’s not related to definition lists). Update the label to accurately describe enabling KaTeX/LaTeX rendering.

Suggested change
"text": "Enable the Markdown-it definition list KaTeX plugin",
"text": "Enable the Markdown-it KaTeX / LaTeX rendering plugin",

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@luginf, what should the correct text be?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@luginf, what should the correct text be?

I've removed it since then (also the option)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@luginf, what should the correct text be?

the option has been removed since then

Comment thread txt2tags-it/markdown-it-txt2tags.js Outdated
Comment thread txt2tags-it/info.json Outdated
Comment thread txt2tags-it/info.json Outdated
Comment thread txt2tags-it/info.json Outdated
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 12, 2026

@pbek

I've worked more on it for better support of some links but it broke elsewhere, I'll post more soon.

I'll also check if it's possible to have it compatible with QT6, because your AppImage doesn't work with this script, while my QT5 build is working correctly.

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 12, 2026

because your AppImage doesn't work with this script, while my QT5 build is working correctly.

What is happening?

@pbek pbek added the wip Work in progress label Apr 12, 2026
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 13, 2026

because your AppImage doesn't work with this script, while my QT5 build is working correctly.

What is happening?

it just shows the txt2tags syntax but without styling it, here is a screenshot, QT5 on the left, QT6 on the right:

image

(numbered list is still wrong at the moment, I'll fix that soon)

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 13, 2026

Could you please post the first block of the settings dump of the Qt6 appimage and the same for your build?

luginf and others added 3 commits April 14, 2026 20:37
- Enable html:true by default so HTML comments (<!-- -->) are passed
  through as-is instead of being escaped as visible text
- Fix --strikethrough-- to use <s> tag instead of <del>, consistent
  with markdown ~~strikethrough~~ rendering
- Remove + item ordered list editor highlighting rule (was applying
  an unwanted heading style to list lines)
- Fix basePath undefined variable → path in relative URL resolution
- Register txt2tags_link before adding autolink/wikilink rules:
  ruler.before("txt2tags_link", ...) threw "Parser rule not found"
  when called before txt2tags_link was itself registered, aborting
  the entire plugin initialisation and breaking all txt2tags rendering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 14, 2026

Could you please post the first block of the settings dump of the Qt6 appimage and the same for your build?

both use the same configuration file and scripts

Qt6:

General Info

Current Date: Tue Apr 14 21:37:32 2026
Version: 26.4.12
Build date: Apr 13 2026
Build number: 1311
Platform: linux (xcb)
Operating System: Linux Mint 22.2
Build architecture: x86_64
Current architecture: x86_64
Release: AppImage
Qt Version (build): 6.10.2
Qt Version (runtime): 6.10.2
Portable mode: no
Settings path / key: /home/eric/.config/PBE/QOwnNotes.conf
Application database path: /home/eric/.local/share/PBE/QOwnNotes/QOwnNotes.sqlite
Application arguments: /tmp/.mount_QOwnNoBUfHWZ/AppRun.wrapped
Qt Debug: no
System Botan: no
Libgit2: no
QLiteHtml: yes
Locale (system): fr_FR
Locale (interface): fr
Primary screen resolution: 1920x1080
Screen resolution(s): 1920x1080, 1280x1024
Icon theme: Adwaita
Notes in current note folder: 97
Calendar items: 0
Enabled scripts: 3
Database drivers: QSQLITE

Server Info

serverUrl: empty
appIsValid: yes
notesPathExists: empty
serverVersion: empty
appVersion: empty

/.../

Script txt2tags-it

id: 2
path: /home/eric/ownCloud/en_cours/qownnotes/txt2tags-it/txt2tags-it.qml

Qt5

General Info

Current Date: mar. avr. 14 21:39:11 2026
Version: 26.4.11
Build date: Apr 12 2026
Build number: 1310
Platform: linux (xcb)
Operating System: Linux Mint 22.2
Build architecture: x86_64
Current architecture: x86_64
Release: Self-build
Qt Version (build): 5.15.13
Qt Version (runtime): 5.15.13
Portable mode: no
Settings path / key: /home/eric/.config/PBE/QOwnNotes.conf
Application database path: /home/eric/.local/share/PBE/QOwnNotes/QOwnNotes.sqlite
Application arguments: QOwnNotes
Qt Debug: no
System Botan: no
Libgit2: no
QLiteHtml: no
Locale (system): fr_FR
Locale (interface): fr
Primary screen resolution: 1920x1080
Screen resolution(s): 1920x1080, 1280x1024
Icon theme: Mint-L-Teal
Notes in current note folder: 97
Calendar items: 0
Enabled scripts: 3
Database drivers: QSQLITE, QMARIADB, QMYSQL, QMYSQL3

/.../

Script txt2tags-it

id: 2
path: /home/eric/ownCloud/en_cours/qownnotes/txt2tags-it/txt2tags-it.qml

It's maybe related to QtQml.

There is an error when starting the appimage:

Warning: file:///home/eric/ownCloud/en_cours/qownnotes/txt2tags-it/txt2tags-it.qml:123: TypeError: Cannot call method 'render' of undefined (file:///home/eric/ownCloud/en_cours/qownnotes/txt2tags-it/txt2tags-it.qml:123, (null))

the code is

var mdHtml = md.render(note.noteText);

and it's also in the markdown-it script, which also raises the same warning:

Warning: file:///home/eric/.local/share/PBE/QOwnNotes/scripts/markdown-it/markdown-it.qml:87: TypeError: Cannot call method 'render' of undefined (file:///home/eric/.local/share/PBE/QOwnNotes/scripts/markdown-it/markdown-it.qml:87, (null))

luginf and others added 4 commits April 15, 2026 01:09
…namespace

In Qt5, importing a JS file in QML binds the module's top-level `this` to
the QML global scope, so UMD modules export their constructors onto the
component via `g = this; g.markdownit = f()`, and `this.markdownit` works
in init().

In Qt6, the module's top-level `this` is the module namespace object
(e.g. MarkdownIt, MarkdownItTxt2tags), not the QML component scope.
So the constructors land on `MarkdownIt.markdownit` etc., and
`this.markdownit` in init() is undefined — causing silent init failure
and a blank preview.

Fix: resolve each constructor with `Namespace.name || this.name` so that
Qt6 uses the module namespace and Qt5 falls back to the component scope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In Qt6 QML, JavaScript files imported via 'import "foo.js" as Foo'
run in strict mode where `this` at the top level is undefined.
The UMD wrappers in markdown-it, markdown-it-deflist, markdown-it-katex
and markdown-it-txt2tags all fell back to `g = this` when window/global/self
were undefined, then threw TypeError setting a property on undefined.

Fix: insert `globalThis` before the `this` fallback in each UMD chain.
globalThis is always the real global object in Qt6's JS engine.

In init(), resolve constructors via `_g = globalThis || this` so that
Qt6 uses globalThis (where the modules now export) and Qt5 falls back
to the component scope (where the modules previously exported via this).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The root cause of Qt6 breakage: UMD modules used `g = this; g.markdownit = f()`
where `this` at module top-level is undefined in Qt6 strict mode, so the
assignment threw and nothing was exported.

Fix: declare `var markdownit` and `var markdownitTxt2tags` at the top level
of each JS file (outside the IIFE). Top-level vars are always accessible via
the QML module qualifier (MarkdownIt.markdownit, MarkdownItTxt2tags.markdownitTxt2tags)
in both Qt5 and Qt6 — no runtime this/globalThis lookup needed.

Also removed the unused deflist and katex plugins to simplify the script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 14, 2026

@pbek it is working now for both Qt5 (my compiled binary) and Qt6 (your AppImage)!

@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 15, 2026

I also needed to have the custom heading syntax detected into the "Headings panel", but it looks like it require to be changed in the source code, so I've used this in a fork:

pbek/QOwnNotes@main...luginf:QOwnNotes-t2t:main

Maybe it's possible to do it differently?

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 15, 2026

@pbek it is working now for both Qt5 (my compiled binary) and Qt6 (your AppImage)!

Awesome. Your Qt5 version of QOwnNotes did not have QLiteHtml, that could explain the difference.

I also needed to have the custom heading syntax detected into the "Headings panel", but it looks like it require to be changed in the source code, so I've used this in a fork:

That looks like something that is just needed for your script. What was it you were trying to achieve? Is there a minimal script custom highlighting you can offer to test it?

@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 15, 2026

That looks like something that is just needed for your script. What was it you were trying to achieve?

Yeah, I don't know. I just wanted to be able to change the heading panel content without modifying the qownnotes code, but the LLM answered:

The scripting API's addHighlightingRule() could already receive a state, but that state was never applied to the block.

recap: We're making txt2tags headings appear in QOwnNotes' navigation panel. The fix is ready as two generic commits in the fork — the next step is to open a PR to pbek/QOwnNotes with the highlightScriptingRules() change.

Is there a minimal script custom highlighting you can offer to test it?

in attachement:
test-addHighlightingRule.zip

it's basically:

QtObject {
    function init() {
        // H1: @ Heading 1 @   (state 12 = MarkdownHighlighter::H1)
        script.addHighlightingRule("^@ +.+? +@\\s*$",     "@",  12);
        // H2: @@ Heading 2 @@ (state 13 = MarkdownHighlighter::H2)
        script.addHighlightingRule("^@@ +.+? +@@\\s*$",   "@@", 13);
        // H3: @@@ Heading 3 @@@ (state 14 = MarkdownHighlighter::H3)
        script.addHighlightingRule("^@@@ +.+? +@@@\\s*$", "@@@", 14);
    }
}

with a fictional syntax like @@ heading level 2 @@ it would work. It would also work for editing mediawiki, dokuwiki or any other lightweight markup langage

image

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 15, 2026

I will implement something in the next release to support the headings from addHighlightingRule in the navigation panel.

@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 15, 2026

I will implement something in the next release to support the headings from addHighlightingRule in the navigation panel.

thank you very much!

@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 15, 2026

the other commit for in-note-text-tagging is appearing in this one as well, I should have done a new branch :/

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 15, 2026

the other commit for in-note-text-tagging is appearing in this one as well, I should have done a new branch :/

Can you please put those changes to another PR?

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 16, 2026

the other commit for in-note-text-tagging is appearing in this one as well, I should have done a new branch :/

Can you please put those changes to another PR?

I've done that, but I'm not sure it worked correctly...

@pbek
Copy link
Copy Markdown
Member

pbek commented Apr 16, 2026

No, you need to cherry-pick the commits you want to get into this PR. Also, you created a PR from your main branch, which is generally a very bad idea, since every time you update your main branch from the upstream one you will also modify your PR. You should create a new branch from a clean upstream main branch and then put your script there and create a clean commit. You need a new PR of course. But I would have squashed your tons of commits anyway in this PR.

@luginf luginf mentioned this pull request Apr 17, 2026
@luginf
Copy link
Copy Markdown
Author

luginf commented Apr 17, 2026

No, you need to cherry-pick the commits you want to get into this PR. Also, you created a PR from your main branch, which is generally a very bad idea, since every time you update your main branch from the upstream one you will also modify your PR. You should create a new branch from a clean upstream main branch and then put your script there and create a clean commit. You need a new PR of course. But I would have squashed your tons of commits anyway in this PR.

ok, sorry, I've created the new branch without the other files (in-note-text-tagging), there are still the other commits but it's probably possible to squash everything during the integration of the PR

@luginf luginf closed this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wip Work in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants