Jeswang's Blog

盲目跟随还是独立去做,To be or not to be?

使用 Marked 预览 Octopress/Jekyll 中的文章

| Comments

一年多以前写过一篇文章(Octopress 新建博客脚本)描述了我简化之后新建博客的流程,很简洁。但是在使用 Mou、Marked 等软件实时预览 Octopress 中的文章时,存在一些缺陷:

  • 不支持文章头部的 YAML 属性对
  • 不支持 codeblock```等 Octopress 中特有的插入代码的语法
  • 因为 Markdown 里输入的图片链接是相对于网站而言的,不是本地地址,因此不能在预览中看到本地的图片

因此,想要预览 Octopress 里的文章,必须要在命令行执行 rake preview 开一个本地的静态服务器,开一个浏览器,自己手动去刷新页面(当然,也可以自己加一行 javascript),对于预览一篇文章来说,这显然有点太重了。

一种解决方案就是换一个生成静态博客的工具,比如说最近在 V2EX 上看到的 MWeb,支持用户拖拽图片到文章里,实时预览,并可以生成干净的 HTML 代码。但是这样做有一个问题就是,导入导出肯定需要一些人工的工作,如果文章挺多的,而且文章里还有一些黑魔法的话,可能工作量还挺大。

由于我的文章也挺多的,也用了点黑魔法(懒得改了好么),所以暂时我也不想更换博客系统。

用 Marked 进行预览

昨天在搜相关的解决方案的时候,看到了一篇 Marked 作者的文章 Previewing Jekyll posts with Marked - BrettTerpstra.com,介绍了一种预览的方法:利用 Marked 自定义解析器的选项,自己写一段代码,在生成 HTML 之前解析一下 Octopress/Jekyll 的 Markdown 代码,把想要预览图片的地址以及代码直接转换为正确HTML,这样就可以直接预览 Octopress/Jekyll 的文章了。

Marked 第一版我买过,第二版还没有买,好在第一版也支持自定义解析器。原文提供了转换的代码,但是直接使用文章里的代码对于中文并不友好,而且对于代码的替换也不完整,所以我修改了一个版本供大家使用。

因为用到了 multimarkdown,所以先要安装一下。

1
brew install multimarkdown

然后新建一个 Ruby 文件,内容如下:

[] (jekyllpre.rb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/ruby
# encoding: utf-8
# Example custom processor for use with Marked <http://markedapp.com> and Jekyll _posts
# It's geared toward my personal set of plugins and tags, but you'll get the idea.
#   It turns
# {% img alignright /images/heythere.jpg 100 100 "Hey there" "hi" %}
#   into
# <img src="../images/heythere.jpg" alt="Hey there" class="alignright" title="hi" />
#
# replaces alignleft and alignright classes with appropriate style attribute
# ---
# Replaces {% gist XXXXX filename.rb %} with appropriate script tag
#
# Replace various other OctoPress, Jekyll and custom tags
#
# Processes final output with /usr/bin/kramdown (install kramdown as system gem: `sudo gem install kramdown`)
#
# Be sure to run *without* stripping YAML headers in Marked Behavior preferences.

Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::UTF_8

# full path to image folder
full_image_path = "/Users/jeswang/Dropbox/projects/Blog/octopress/source/"

require "CGI"
require "rubygems"

content = STDIN.read

parts = content.split(/^---\s*$/)

# Read YAML headers as needed before cutting them out
post_title = parts[1].match(/^title:\s+(\!\s*)?["']?(.*?)["']?\s*$/i)[2].strip

# Remove YAML
# content.sub!(/^---.*?---\s*$/m,'')
content = parts[2]

# Fenced code
content.gsub!(/^```(\w+)?\s*\n(.*?)\n```/m) {
  %Q"<pre><code class=\"#{$1}\">#{CGI.escapeHTML($2)}</code></pre>"
}

content.gsub!(/\{%(\s+)?codeblock (lang:)?(\S+)?(\s+)?%\}\n?([\W\w]*?)\{%(\s+)?endcodeblock(\s+)?%\}/m) {
  %Q"<pre><code class=\"#{$3}\">#{CGI.escapeHTML($5)}</code></pre>"
}


# Process image Liquid tags
content.gsub!(/\{% img (.*?\s*)%\}/) {|img|
  if img =~ /\{% img\s+(\S+\s)?(https?:\/\/\S+|\/\S+)\s+(\d+\s+)?(\d+\s+)?(\S.*\s*)?%\}/i
    classes = $1.strip if $1
    src = $2
    width = $3
    height = $4
    title = $5

    if /(?:"|')([^"']+)?(?:"|')\s+(?:"|')([^"']+)?(?:"|')/ =~ title
      title  = $1
      alt    = $2
    else
      alt    = title.gsub!(/"/, '&#34;') if title
    end
    classes.gsub!(/"/, '') if classes
  end

  style = %Q{ style="float:right;margin:0 0 10px 10px"} if classes =~ /left/
  style = %Q{ style="float:left;margin:0 10px 10px 0"} if classes =~ /right/

  %Q{<img src="#{File.join(full_image_path,src)}" alt="#{alt}" class="#{classes}" title="#{title}"#{style} />}
}

content = "## #{post_title}\n\n#{content}"

File.open("/tmp/markdown", 'w:utf-8') { |file| file.write(content) }

puts %x{multimarkdown /tmp/markdown }

并把这个文件作为 Custom Markdown Processor。

这样就可以直接在 Marked 里可以直接预览 Octopress/Jekyll 中的文章了。

配上喜欢的编辑器

使用 Marked 进行实时预览需要和编辑器进行配合。使用 Sublime Text 3 进行编辑的话,可以在 Build System (Tools/Build System/New Build System…)里加入对于 Marked 的支持。Build 脚本如下:

1
2
3
4
5
{  
  "shell": "true",  
  "cmd": ["open -a marked \"$file\""],
  "selector": "text.html.markdown"
}  

配上喜欢的 CSS 样式

最后,你可以为 Marked 配上你喜欢的 CSS 样式。我的样式是基于 sofish/typo.css 修改的,字体改小了一点,给页面加上了左右的留白。代码在这里

完成了这些步骤之后,就能实现文章最开始图片上的效果了,oh yeah。

PS:

  • 用 Sublime Text 3 来写中文有一个问题(BUG):ST3 不认识中文的汉字和字符,认为连续的中文汉字和字符就是一个词,导致的结果就是在 ST 3 里中文断行很不科学。还好问题不是很大,可以忍受。(ST2 找到了解决方案,但是 ST3 好像还没有人解决这个问题)
  • 这段代码用 Ruby 来写真简洁,我心里默默用 Python 写了一遍,发现好像写不了这么简洁
  • 代码还有可供修改的地方,比如说支持插入代码的展示(Ruby 不熟,学一学再来改一下)
  • Marked 具有有这么贴心的功能,开始犹豫要不要入手一个 Marked 2 了(这个月买软件的开销有点多,亲,你打打折,让我入了你吧)

- EOF -

Comments