Hi,
I'm trying to program a Markdown viewer. I would like one that's light and simple. I thought about using an RTF conversion to use its viewer. It's not bad. However, I think I will try using an HTML viewer with HTML conversions of the MD file...
Best regards.
' MD VIEWER by Nicola Piano (12-2025)
'====================================
$ filename "md_viewer.exe"
uses WinUtil
uses FileDialogs
uses ParseUtil
' --- CARICAMENTO LIBRERIE ---
sys hRichLib = LoadLibrary("msftedit.dll")
if hRichLib = 0 then hRichLib = LoadLibrary("riched20.dll")
% ID_RICHEDIT = 101
% ID_MENU_OPEN = 201
sys hRichEdit, hFont
type SETTEXTEX
uint flags
uint codepage
end type
% EM_SETTEXTEX = 0x0461
% ST_RTF = 2
% CP_ACP = 0
function UTF8ToAnsi(string s) as string
sys L = len(s)
if L = 0 then return ""
' 1. Calcoliamo quanti caratteri Wide servono
sys wLen = MultiByteToWideChar(65001, 0, strptr(s), L, 0, 0)
' Allocazione buffer Wide (2 byte per carattere)
string ws = space(wLen * 2)
MultiByteToWideChar(65001, 0, strptr(s), L, strptr(ws), wLen)
' 2. Calcoliamo quanto spazio ANSI serve
sys aLen = WideCharToMultiByte(0, 0, strptr(ws), wLen, 0, 0, 0, 0)
string res = space(aLen)
WideCharToMultiByte(0, 0, strptr(ws), wLen, strptr(res), aLen, 0, 0)
return res
end function
' --- Funzione Parser Markdown ---
function MD_to_RTF(string md) as string
' 0:nero, 1:blu, 4:verde, 5:bordeaux
string rtf = "{\rtf1\ansi\deff0{\fonttbl{\f0 Segoe UI;}{\f1 Courier New;}}"
rtf += "{\colortbl;\red0\green0\blue255;\red255\green0\blue0;\red100\green100\blue100;\red0\green128\blue0;\red128\green0\blue64;}\f0\fs24 "
string ToC = "\b\fs28 INDICE\b0\fs24\line\line "
string contentRTF = ""
string curLine
sys pos = 1, nextPos = 0
bool inCode = false
do
nextPos = instr(pos, md, chr(10))
if nextPos > 0 then
curLine = mid(md, pos, nextPos - pos)
pos = nextPos + 1
else
curLine = mid(md, pos)
pos = 0
end if
if instr(curLine, chr(13)) > 0 then replace(curLine, chr(13), "")
' 1. Protezione RTF
replace(curLine, "\", "\\")
replace(curLine, "{", "\{")
replace(curLine, "}", "\}")
' 2. Pulizia Link [testo](#anchor) -> testo
' Fondamentale per file come Variables.md per ripristinare la leggibilitĂ
do while instr(curLine, "[") > 0 and instr(curLine, "](#") > 0
sys p1 = instr(curLine, "[")
sys p2 = instr(p1, curLine, "]")
sys p3 = instr(p2, curLine, ")")
if p2 > p1 and p3 > p2 then
string linkTxt = mid(curLine, p1 + 1, p2 - p1 - 1)
curLine = left(curLine, p1 - 1) + linkTxt + mid(curLine, p3 + 1)
else
exit do
end if
loop
' 3. Gestione Titoli (Flessibile: cerca il cancelletto anche dopo simboli speciali)
string tLine = ltrim(curLine)
' Cerchiamo la posizione del primo #
sys hashPos = instr(tLine, "#")
if hashPos > 0 and hashPos < 5 then ' Se il cancelletto è all'inizio (max 4 spazi/simboli)
if instr(tLine, "# ") > 0 then
ToC += "\cf1\b\fs32 " + tLine + "\b0\fs24\cf0\line "
curLine = "\b\cf1\fs32 " + curLine + "\fs24\cf0\b0"
elseif instr(tLine, "## ") > 0 then
ToC += "\cf1\b\fs28 " + tLine + "\b0\fs24\cf0\line "
curLine = "\b\cf1\fs28 " + curLine + "\fs24\cf0\b0"
elseif instr(tLine, "### ") > 0 then
ToC += "\cf4\b\fs24 " + tLine + "\b0\cf0\line "
curLine = "\b\cf4 " + curLine + "\cf0\b0"
end if
end if
' 4. Blocchi Codice
if left(ltrim(curLine), 3) = "```" then
inCode = not inCode
if inCode then contentRTF += "\line\f1\fs20 " else contentRTF += "\f0\fs24\line "
continue do
end if
if inCode = false then
' 5. Grassetto (Logica a prova di simboli speciali)
sys b1 = 1
do
b1 = instr(b1, curLine, "**")
if b1 > 0 then
sys b2 = instr(b1 + 2, curLine, "**")
if b2 > b1 then
string boldTxt = mid(curLine, b1 + 2, b2 - b1 - 2)
string rep = "\b " + boldTxt + "\b0 "
curLine = left(curLine, b1 - 1) + rep + mid(curLine, b2 + 2)
b1 += len(rep)
else
exit do
end if
else
exit do
end if
loop
' 6. Tabelle (Pipe |)
if instr(curLine, "|") > 0 and instr(curLine, "---") = 0 then
replace(curLine, "|", "\tab ")
curLine = "\li400 " + curLine
end if
contentRTF += curLine + "\line "
else
contentRTF += " " + curLine + "\line "
end if
if pos = 0 then exit do
loop
return rtf + ToC + "\line\emdash\line\line " + contentRTF + "}"
end function
' --- Procedura Caricamento ---
sub LoadMD(sys hEdit, string f)
if f = "" then exit sub
' --- 1. SVUOTIAMO LA GUI ---
SendMessage(hEdit, WM_SETTEXT, 0, strptr(""))
string raw = getfile(f)
if len(raw) = 0 then exit sub
' --- 2. CORREZIONE CARATTERI (UTF-8 a ANSI) ---
' Applichiamo la conversione prima di passarlo al parser
'raw = UTF8ToAnsi(raw)
static string sRTF
sRTF = MD_to_RTF(raw)
dim st as SETTEXTEX
st.flags = ST_RTF
st.codepage = 0
SendMessage(hEdit, EM_SETTEXTEX, @st, strptr(sRTF))
SetWindowText(GetParent(hEdit), "O2 Viewer - " + f)
end sub
static string sRTF
' --- WndProc ---
function WndProc(sys hwnd, uMsg, wParam, lParam) as long callback
select umsg
case WM_CREATE
' Menu
sys hMenu = CreateMenu()
sys hSub = CreatePopupMenu()
AppendMenu(hSub, MF_STRING, ID_MENU_OPEN, "&Apri...")
AppendMenu(hMenu, MF_POPUP, hSub, "&File")
SetMenu(hwnd, hMenu)
' Creazione RichEdit
hRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RichEdit50W", "", _
WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL | 0x0800, _
0, 0, 0, 0, hwnd, ID_RICHEDIT, hinst, null)
hFont = CreateFont(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Segoe UI")
SendMessage(hRichEdit, WM_SETFONT, hFont, 1)
if hRichEdit <> 0 then
string testo = "# Ciao Charles" + chr(10) + "O2 is GREAT"
static string sRTF
sRTF = MD_to_RTF(testo)
'usa EM_SETTEXTEX:
dim st as SETTEXTEX
st.flags = ST_RTF
st.codepage = 0
SendMessage(hRichEdit, EM_SETTEXTEX, @st, strptr(sRTF))
SetWindowText(hwnd, "O2 Viewer - Pronto")
end if
case WM_COMMAND
if loword(wParam) = ID_MENU_OPEN then
' Filtro corretto per FileDialogs.inc [cite: 9]
string filt = "Markdown" + chr(0) + "*.md" + chr(0) + "All" + chr(0) + "*.*" + chr(0)
string f = GetFileName("", 0, filt)
'mbox f
if f <> "" then LoadMD(hRichEdit, f)
end if
case WM_SIZE
if hRichEdit then
RECT rc : GetClientRect(hwnd, &rc)
MoveWindow(hRichEdit, 5, 5, rc.right-10, rc.bottom-10, TRUE)
end if
case WM_DESTROY
if hRichLib then FreeLibrary(hRichLib)
PostQuitMessage 0
case else
return DefWindowProc(hwnd, uMsg, wParam, lParam)
end select
end function
MainWindow 800, 600, WS_OVERLAPPEDWINDOW
Thanks Nicola.
For Markdown reference:
https://www.markdownguide.org/basic-syntax/