將markdown (md)文件轉換成帶側邊欄目錄(toc)的html文件


想用md記一些筆記,特別是一些日常需要快速查閱的命令或者手冊, 因為用有道筆記之類的筆記軟件,感覺過於龐大和笨重,用txt文件記錄,格式上又不夠清晰並且不能快速跳轉。寫成md,然后轉成html似乎是個不錯的選擇。

md轉html的工具遍地都是,但是這些工具轉成的html都沒有側邊欄目錄,除非這個html非常短,這樣的html頁面查閱起來就跟txt也區別不大了。

想找個簡單的工具,竟然很難找到合適的。要么就是可以生成目錄,但是在目錄在頁面頂部,一滾動就看不見了;要么,就是特別笨重和麻煩,比如給你一個模板文件夾,文件夾里還有各種資源文件(圖標,css, js庫之類的),你得把你轉好的html中<body>的內容拷貝到html模板文件里面的指定區域,這樣每次都需要拷貝並且一個md文件竟然還搞出一個目錄來實在讓人崩潰。

其實,我需要的只是一個自動化的工具,能夠生成有很簡陋的側邊欄的html就行。

最后,實在沒辦法了,只能自己來搞,寫了個簡單的Python腳本。 (在Python2.7下運行沒問題,對Python3不熟,沒試過)

 

import argparse
import markdown
import os, os.path
import string, codecs
 
parser = argparse.ArgumentParser(add_help=True)
 
parser.add_argument('files', metavar='mdFile', type=str, nargs='+',
                   help='md files to be converted')
                    
parser.add_argument('--aside-width', dest='asideWidth',type= int, 
                    default=20, help='the width of the aside toc, specified as percents. e.g., 15 means 15 percents')
                    
parser.add_argument('--no-number', dest='noNumber',action='store_true', 
                    default=False, help='do not prepend numbers for headers')                    
 
args = parser.parse_args()
 
htmlTemplate = string.Template('''
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
    <style>
    html, body {width: 100%}
    body {margin: 0px;}
    aside.toc { position:fixed; top:0px; left: 0px; width: ${asideWidth}%; border-right: 2px solid grey; overflow: scroll}
    main { position: relative; width: ${mainWidth}%; left: ${asideWidth}%; margin-left: 25px; }
    ${css_for_header_number}
    </style>
</head>
<body>
<aside class="toc">$toc</aside>
<main>$mainContent</main>
<script>
    var tocElem = document.querySelector("aside.toc");
    tocElem.style.setProperty("height", window.innerHeight+'px');
     
    window.addEventListener("resize", resizeThrottler, false);
     
    var resizeTimeout;
    function resizeThrottler() {
    // ignore resize events as long as an actualResizeHandler execution is in the queue
    if ( !resizeTimeout ) {
        resizeTimeout = setTimeout(function() {
        resizeTimeout = null;
        actualResizeHandler();
       }, 300);
    }
  }
   
  function actualResizeHandler() {
    tocElem.style.setProperty("height", window.innerHeight+'px');
  }
</script>
<body>
''')

css_for_header_number = ''
if not args.noNumber:
    css_for_header_number = '''
body { counter-reset: h1counter}
    h1 { counter-reset: h2counter}  /* cannot use the same counter as h2 is not the child of h1*/
    h1::before {counter-increment: h1counter; content: counter(h1counter) " ";}
    h2 { counter-reset: h3counter}
    h2::before {counter-increment: h2counter; content: counter(h1counter) "." counter(h2counter) " "}
    h3 { counter-reset: h4counter}
    h3::before {counter-increment: h3counter; content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) " "}
    h4::before {counter-increment: h4counter; content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) " "}
    aside ul { counter-reset: section;  list-style-type: none; }
    aside li::before { counter-increment: section; content: counters(section,".") " "; }
    aside ul ul ul ul ul li::before {content: none}   /* number depth : 4 */
'''


if (args.files[0] == '*'):
    files = filter(os.path.isfile, os.listdir(os.getcwd()))
    files = filter(lambda x: x.endswith('.md'), files)
else:
    files = filter(lambda x: x.endswith('.md'), args.files)
     
md = markdown.Markdown(extensions=['markdown.extensions.toc'], output_format="html5") 

if not files:
    print 'Error: File not found!'
else:
    for fname in files:
        # md.convert() accepts only unicode
        infile = codecs.open(fname, mode="r", encoding="utf-8")
        mdtext =infile.read()
         
        # use convert() instead of convertFile() as convertFile() output the result to either a file or stdout.
        mainContent = md.reset().convert(mdtext)
     
        # warning: there should not be a marker such as [TOC] for toc in the converted .md file, 
        # or else md would not have attribute toc
        # 100-3 : 3 percent for margin 
        
        html = htmlTemplate.substitute(asideWidth = args.asideWidth, mainWidth =(100-3-args.asideWidth),  toc= md.toc, mainContent=mainContent, css_for_header_number=css_for_header_number) 
     
        outfile = open(fname[:-2]+'html', 'w')
        outfile.write(html.encode('utf-8'))
         
        infile.close()
        outfile.close()
     

 

很簡陋,腳本很簡陋,生成的頁面也很簡陋,但是對我來說夠用了。

使用前提: 1. md文件必須是utf-8編碼的   2. 安裝python markdown 庫, pip install markdown

使用方式( 假定上面的代碼保存成文件 md_conv.py) :

    python md_conv.py --aside-width 25 someFile.md    

    25 表示側邊欄寬度是 25%,默認是20%; 如果把 someFile.md 改成 * 則轉換當前目錄下所有 .md文件。

    默認會給標題生成編號(編號只到第四級標題;並且md文件里必須有至少一個一級標題,否則編號會有錯誤), 如果不想要編號, 可以指定選項 --no-number  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM