Markdown to PHPbb Converter, leveraging Pandoc.
Convert from within the app or use a predefined hotkey.
Features
- Compile via app
Spoiler
- Compile clipboard contents via hotkey
Spoiler
- Rebind Hotkeys
Spoiler
- Always On Top
Spoiler
- Named / Unnamed Spoilers
SpoilerType 3 or more carets (^^^) at the beginning of a line to indicate the opening tag of an unnamed spoiler.
If any characters follow on the same line until end of line, the spoiler will be converted to a named one with the characters comprising its name.
The next occurence of ^^^ will result in a closing tag.
^^^
unnamed spoiler contents
^^^^^
^^^^^^MyNamedSpoiler
named spoiler contents
^^^ - Copy to clipboard
- Unsaved changes indicator
- Resizable
- AutoHotkey_L v2.0-a099-ca386dc (or newer)
- pandoc.exe (in PATH or script dir)
- pclip.exe (in PATH or script dir)
- ahk.lua (in script dir)
- AutoHotkey_L v2.0
- Pandoc v2.4
- PClip, from UnxUtils
- ahk.lua, modified from sample.lua - see next post or download zip
- MarkdownConverter.ahkSpoiler
Code: Select all
#SingleInstance Force Path := checkAllDependenciesExist() Create_MainGui: Gui_Main := GuiCreate("+AlwaysOnTop +Resize", GUI_TITLE := "Markdown to PHPbb") Gui_Main.MarginX := Gui_Main.MarginY := 6 minEditW := 200, minEditH := 100, minBtnW := 100, minBtnH := 24 Gui_Main.Options(Format("+MinSize{}x{}", 4 * Gui_Main.MarginX + 2 * minEditW + minBtnW, 4 * Gui_Main.MarginY + minEditH + 3 * minBtnH)) Label_MD := Gui_Main.Add("Text", "", "Markdown") Label_BB := Gui_Main.Add("Text", "yp", "PHPbb") Edit_MD := Gui_Main.Add("Edit", "xm R10 w" minEditW, LAST_TEXT_MD := "") Edit_MD.OnEvent("Change", () => UncompiledChanges()) Btn_Recompile := Gui_Main.Add("Button", "yp w" minBtnW " h" minBtnH, "Recompile >") Btn_Recompile.OnEvent("Click", () => Recompile()) Edit_BB := Gui_Main.Add("Edit", "yp R10 w" minEditW, "") Btn_CopyMD := Gui_Main.Add("Button", "xm w" minBtnW " h" minBtnH " vmd", "Copy to Clipboard") Btn_CopyMD.OnEvent("Click", () => CopyToClipboard(Btn_CopyMD, Edit_MD)) Btn_CopyBB := Gui_Main.Add("Button", "yp w" minBtnW " h" minBtnH " vbb", "Copy to Clipboard") Btn_CopyBB.OnEvent("Click", () => CopyToClipboard(Btn_CopyBB, Edit_BB)) Btn_FocusSink := Gui_Main.Add("Button", "xm") SB := Gui_Main.Add("StatusBar") SB.OnEvent("Click", Func("ShowSettings")) Gui_Main.OnEvent("Size", Func("GuiResized")) Gui_Main.OnEvent("Close", () => ExitApp()) Gui_Main.Show() statusBarText("Ready...") Btn_FocusSink.Focus() Create_HotkeyGui: compileHotkey := IniRead("config.ini", "Hotkeys", "compile", "^1") compileHotkeyEnabled := IniRead("config.ini", "Hotkeys", "compileEnabled", "1") exitHotkey := IniRead("config.ini", "Hotkeys", "exit", "Esc") exitHotkeyEnabled := IniRead("config.ini", "Hotkeys", "exitEnabled", "1") Gui_Hotkey := GuiCreate("+ToolWindow +Owner" Gui_Main.Hwnd, "Redefine Hotkeys") Gui_Hotkey.MarginX := Gui_Hotkey.MarginY := Gui_Main.MarginX Gui_HotkeyW := 360 CB_Compile := Gui_Hotkey.Add("Checkbox", "xm ym+4", "Compile Clipboard (overwrites contents)") CB_Compile.Value := compileHotkeyEnabled HK_Compile := Gui_Hotkey.Add("Hotkey", "x" Gui_HotkeyW - Gui_Hotkey.MarginX - minBtnW " yp-4 w" minBtnW, compileHotkey) CB_Exit := Gui_Hotkey.Add("Checkbox", "xm y" HK_Compile.Pos.y + HK_Compile.Pos.h + Gui_Hotkey.MarginY + 4, "Terminate App") CB_Exit.Value := exitHotkeyEnabled HK_Exit := Gui_Hotkey.Add("Hotkey", "x" Gui_HotkeyW - Gui_Hotkey.MarginX - minBtnW " yp-4 w" minBtnW, exitHotkey) Gui_Hotkey.Add("GroupBox", "xm h7 w" Gui_HotkeyW - 2 * Gui_Hotkey.MarginX, "") Gui_Hotkey.Add("Button", "x" Gui_HotkeyW - 2 * Gui_Hotkey.MarginX - 2 * minBtnW + 1 " w" minBtnW, "Cancel").OnEvent("Click", () => HideHotkeyGui()) Gui_Hotkey.Add("Button", "x+m yp w" minBtnW, "Save Hotkey").OnEvent("Click", () => SaveHotkey()) Gui_Hotkey.OnEvent("Close", () => HideHotkeyGui()) Gui_Hotkey.Show("Hide w" Gui_HotkeyW) SaveHotkey() Create_SettingsMenu: MenuItems := [] Menu_Settings := MenuCreate() alwaysOnTopEnabled := IniRead("config.ini", "General", "alwaysOnTopEnabled", "1") MenuItems.Push(Menu_Settings.Add("Always On Top", () => ( alwaysOnTopEnabled := !alwaysOnTopEnabled, toggleAlwaysOnTop() ))) toggleAlwaysOnTop() compilationMsgboxEnabled := IniRead("config.ini", "General", "compilationMsgboxEnabled", "1") MenuItems.Push(Menu_Settings.Add("Show Hotkey Compilation MsgBox", () => ( ((compilationMsgboxEnabled := !compilationMsgboxEnabled) ? Menu_Settings.Check("2&") : Menu_Settings.Uncheck("2&")) IniWrite(compilationMsgboxEnabled, "config.ini", "General", "compilationMsgboxEnabled") ))) compilationMsgboxEnabled ? Menu_Settings.Check("2&") : Menu_Settings.Uncheck("2&") MenuItems.Push(Menu_Settings.Add("Redefine Hotkeys", () => ShowHotkeyGui())) menuItemsCount := MenuItems.Count() Return toggleAlwaysOnTop() { global alwaysOnTopEnabled, Gui_Main, Menu_Settings if (alwaysOnTopEnabled) { Menu_Settings.Check("1&") Gui_Main.Options("+AlwaysOnTop") } else { Menu_Settings.Uncheck("1&") Gui_Main.Options("-AlwaysOnTop") } IniWrite(alwaysOnTopEnabled, "config.ini", "General", "alwaysOnTopEnabled") } compileViaHotkey() { global compilationMsgboxEnabled Clipboard := runPandoc(Clipboard) if compilationMsgboxEnabled MsgBox(Clipboard, "Compilation via Hotkey", "T3 262144") } SaveHotkey() { global HK_Compile, CB_Compile, HK_Exit, CB_Exit IniWrite(Format(" ( compile={} compileEnabled={} exit={} exitEnabled={} )", HK_Compile.Value, CB_Compile.Value, HK_Exit.Value, CB_Exit.Value ), "config.ini", "Hotkeys") #If CB_Compile.Value #If CB_Exit.Value #If Hotkey("If", "CB_Compile.Value") Hotkey(HK_Compile.Value, () => compileViaHotkey()) Hotkey("If") Hotkey("If", "CB_Exit.Value") Hotkey(HK_Exit.Value, () => ExitApp()) Hotkey("If") HideHotkeyGui() statusBarText("Hotkey(s) reloaded.") } HideHotkeyGui() { global Gui_Main, Gui_Hotkey Gui_Main.Options("-Disabled") Gui_Hotkey.Hide() statusBarText("Hotkey redefinition aborted.") } ShowHotkeyGui() { global Gui_Main, Gui_Hotkey pos := Gui_Main.Pos Gui_Main.Options("+Disabled") Gui_Hotkey.Show(Format("x{} y{}", pos.x + (pos.w - Gui_Hotkey.Pos.w) // 2, pos.y + (pos.h - Gui_Hotkey.Pos.h) // 2)) } ShowSettings(GuiCtrl, info) { global Gui_Main, SB, Menu_Settings, menuItemsCount, minBtnH if (info == 2) Menu_Settings.Show(Gui_Main.MarginX, SB.Pos.y - minBtnH * menuItemsCount - 4) } where(program) { clipSaved := ClipboardAll() Clipboard := "" cmd := Format("cmd /c cd /d `"{}`" & where `"{}`" | clip", A_ScriptDir, program) runHiddenShell(cmd) if (ClipWait(0.5)) firstPath := StrSplit(Clipboard, "`n", "`r")[1] Clipboard := clipSaved return firstPath } runHiddenShell(cmd) { ComObjCreate("WScript.Shell").Run(cmd, 0, false) } runPandoc(markdown) { global Path clipSaved := ClipboardAll() Clipboard := convertSpoilers(markdown) cmd := Format("cmd /c `"`"{}`" | `"{}`" -t `"{}`" -f markdown-smart | clip`"", Path.pclip, Path.pandoc, Path.template) runHiddenShell(cmd) Sleep(200) phpbb := Clipboard Clipboard := clipSaved return phpbb } checkAllDependenciesExist() { return { "pandoc": checkDependency("pandoc.exe"), "pclip": checkDependency("pclip.exe"), "template": checkDependency("ahk.lua"), } } checkDependency(d) { if (path := where(d)) return path errorDependencyNotFound(d) } errorDependencyNotFound(d) { title := Format("'{}' could not be found!", d) content := Format("'{}' not on PATH or in script dir.`n`nExiting.", d) MsgBox(content, title, "Iconx") ExitApp() } convertSpoilers(markdown) { static SPOILER := "^\^{3,}$" , NAMED_SPOILER := "i)^\^{3,}(.*)$" Result := [] expectOpenTag := true expectCloseTagSpoiler2 := false replacedSpoilers := 0 for i, line in StrSplit(markdown, "`n", "`r") { if expectOpenTag { if (line ~= SPOILER) { Result.Push("[spoiler]") expectOpenTag := false Last := {"index": i, "replacement": line} ++replacedSpoilers } else if RegExMatch(line, NAMED_SPOILER, M) { Result.Push(Format("[spoiler2={}]", M[1])) expectOpenTag := false expectCloseTagSpoiler2 := true Last := {"index": i, "replacement": line} ++replacedSpoilers } else Result.Push(line) } else { if (line ~= SPOILER) { if expectCloseTagSpoiler2 { Result.Push("[/spoiler2]") expectCloseTagSpoiler2 := false } else { Result.Push("[/spoiler]") } expectOpenTag := true Last := {"index": i, "replacement": line} ++replacedSpoilers } else Result.Push(line) } } if isOdd(replacedSpoilers) Result[Last.index] := Last.replacement return join(Result) } isOdd(n) { return n & 1 } join(Array, delim := "`n") { for each, line in Array result .= line delim return SubStr(result, 1, -StrLen(delim)) } timestamp() { return FormatTime(A_Now, "HH:mm:ss") "." A_MSec } statusBarText(msg := "") { global SB SB.SetText("Configure...", 2) SB.SetText(timestamp(), 4) SB.SetText(msg, 5) } Recompile() { global Gui_Main, Edit_MD, Edit_BB, Btn_Recompile, GUI_TITLE, LAST_TEXT_MD clickButton(Btn_Recompile, () => ( Edit_BB.Text := runPandoc(Edit_MD.Text), statusBarText("Compilation successful.") Gui_Main.Title := GUI_TITLE, LAST_TEXT_MD := Edit_MD.Text )) } clickButton(BtnCtrl, fn) { global Btn_FocusSink Btn_FocusSink.Focus() BtnCtrl.Enabled := false fn.Call() BtnCtrl.Enabled := true BtnCtrl.Focus() } CopyToClipboard(BtnCtrl, EditCtrl) { global Gui_Main, Label_MD, Label_BB sbOldText := StatusBarGetText(5, "ahk_id " Gui_Main.Hwnd) clickButton(BtnCtrl, () => ( Clipboard := EditCtrl.Text, statusBarText(Format("{} copied to clipboard.", BtnCtrl.Name == "md" ? Label_MD.Text : Label_BB.Text)) Sleep(500) statusBarText(sbOldText) )) } UncompiledChanges() { global Gui_Main, Edit_MD, GUI_TITLE, LAST_TEXT_MD diffChars := StrLen(Edit_MD.Text) - StrLen(LAST_TEXT_MD) statusBarText(Format("Uncompiled changes! ({} chars)", diffChars > 0 ? "+" diffChars : diffChars)) Gui_Main.Title := GUI_TITLE "*" } GuiResized(Gui, minMax, guiW, guiH) { global Gui_Main, Edit_MD, Edit_BB, Label_MD, Label_BB , Btn_Recompile, Btn_CopyMD, Btn_CopyBB, Btn_Recompile, Btn_FocusSink, SB w := (guiW - 4 * Gui_Main.MarginX - Btn_Recompile.Pos.w) // 2 h := (guiH - 4 * Gui_Main.MarginY - Label_MD.Pos.h - Btn_CopyMD.Pos.h - SB.Pos.h) Edit_MD.Move("h" h "w" w, true) Edit_BB.Move("x" 3 * Gui_Main.MarginX + Edit_MD.Pos.w + Btn_Recompile.Pos.w " h" Edit_MD.Pos.h " w" w, true) Label_MD.Move("x" Edit_MD.Pos.x + Edit_MD.Pos.w - Label_MD.Pos.w, true) Label_BB.Move("x" Edit_BB.Pos.x, true) Btn_Recompile.Move("x" Edit_MD.Pos.w + 2 * Gui_Main.MarginX " y" Edit_MD.Pos.y + (Edit_MD.Pos.h // 2) - (Btn_Recompile.Pos.h // 2), true) Btn_CopyMD.Move("x" Edit_MD.Pos.x + Edit_MD.Pos.w - Btn_CopyMD.Pos.w + 1 " y" 3 * Gui_Main.MarginY + Label_MD.Pos.h + Edit_MD.Pos.h, true) Btn_CopyBB.Move("x" Edit_BB.Pos.x - 1 " y" Btn_CopyMD.Pos.y, true) Btn_FocusSink.Move("x" guiW) SB.SetParts( Gui_Main.MarginX, Btn_CopyMD.Pos.w, Edit_MD.Pos.w - 2 * Btn_CopyMD.Pos.w + 3, Btn_CopyMD.Pos.w - 3, Btn_Recompile.Pos.w + Btn_CopyBB.Pos.w + 2 * Gui_Main.MarginX - 2 ) }
- testfile.md
Spoiler
Code: Select all
# big header some text some text some text ``` some code ``` ## med header - list 1 - list 2 - nested 1 - nested 2 - list 3 ---- _italic_ __bold__ ___italicbold___ `inline code` ^^^ unnamed spoiler ^^^ ^^^named spoiler spoiler content ^^^ ### normal header [Link](www.autohotkey.com) Image: ![](https://autohotkey.com/boards/styles/simplicity/theme/images/logo.png) #### tiny header(same as bold) > quoted text > > > nested quoted text > > nested quoted text > > quoted text ##### tinier header still how much more? ###### tiniest of headers
- [Optional] Zip, includes:
- ahk.lua
- testfile.md
- MarkdownConverter.ahk
- Compiled MarkdownConverter.exe for v2
- pandoc.exe not included, download separately
- pclip.exe not included, download separately
- MarkdownConverter.zip
- (493.17 KiB) Downloaded 73 times