现在的位置: 主页 > 新闻中心 > 文章正文

用Python高亮org-mode代码块

作者:武警河南洛阳红丝带网 来源:www.027fck.com 未知发布时间:2017-09-03 12:17:47
用Python高亮org-mode代码块 1 前言

最近在研究利用org-mode写博客,其他一切都深得我心、甚合吾意,就是代码染色发布html这一点要给差评。org-mode利用htmlize 插件给 src block 中的代码着色,让文章中的代码块输出html后的颜色于你在emacs上看到的相同。可问题在于,我emacs上背景是暗黑系的,而我博客上是浅色系,因此代码高亮风格不相调和,何况高亮主题单一不可定制,输出代码行号丑陋不堪,当然这都可以用elisp解决,可是想必是繁杂晦色无比(要调色啊…)

于是,我又再次投入万能的Python的怀抱,直接利用它的pygments库高亮代码。

2 实现框架

先介绍一下pygments。 pygments 能够将一段原生代码高亮并输出为 html、latex、png 等多种格式,而且还提供各种样式控制。

由于pygments库是原生的python库,因此通过写elisp插件控制org-mode发布并不现实,再三思虑之下,只能从org-mode发布的html文件开始入手,把代码块的html改了。

先来看看org-mode代码块输出html的特征:

src block :

#+begin_src python

import pygments

print "aa"

#+end_src

输出 html :

<div class="org-src-container">

<pre class="src src-python"><span style="color: #66D9EF;">import</span> pygments

<span style="color: #66D9EF;">print</span> <span style="color: #E6DB74;">"aa"</span>

</pre>

</div>

可以看出,站群软件,代码块输出html后总会包含在 <div class="org-src-container">...</div> 内,至于代码语言则由 <pre> 的class 属性指明。

OK,目标很明显,就是要将上面那段 html 代码用 pygments 替换成我们想要的高亮主题。

程序流程:

提取:把包含在 <div class="org-src-container">...</div> 内的html代码提取到数组A

去标记:用 BeautifulSoup 解析数组A中的html代码,把当中 html tags 去掉,等到原生代码

高亮:用 pygments 高亮原生代码,并输出新的 html

替换:用新的html把旧的替换掉,并重新写入文件

样式:为代码块指定或设计 CSS

3 具体实现

完整代码可见我的_pygment-html.py

3.1 虚拟环境

由于在我的 Jekyll 中,需要写多个python脚本处理,因此我先建立一个虚拟环境,然后所由脚本都在这个虚拟环境中开发。

3.1.1 Virtualenv

Virtualenv 用于创建独立的Python环境,多个Python相互独立,互不影响,它能够:

在没有权限的情况下安装新套件

不同应用可以使用不同的套件版本

套件升级不影响其他应用

安装: pip install virtualenv

创建: virtualenv /your/path/of/env ,默认情况下,虚拟环境会依赖系统环境中的 site packages ,就是说系统中已经安装好的第三方 package 也会安装在虚拟环境中,如果不想依赖这些package,那么可以加上参数 --no-site-packages 建立虚拟环境

启动虚拟环境: cd /your/path/of/env , source ./bin/activate ,注意此时命令行会多一个 ENV , ENV 为虚拟环境名称,接下来所有模块都只会安装到该目录中去。

退出虚拟环境: deactivate

3.1.2 VirtualenvWrapper

Virtualenv很有用,但是操作较为麻烦(想想你需要来回切换多个ENV),因此可用 Virtualenvwrapper 简化操作:

将所有虚拟环境整合在一个目录下

管理(新增,删除,复制)虚拟环境

切换虚拟环境

安装: pip install virtualenvwrapper

把下面的代码写入 .bashrc/.zshrc 中:

if [ `id -u` != '0' ]; then

export VIRTUALENV_USE_DISTRIBUTE=1 # <-- Always use pip/distribute

export WORKON_HOME=$HOME/.virtualenvs # <-- Where all virtualenvs will be stored

source /usr/local/bin/virtualenvwrapper.sh

export PIP_VIRTUALENV_BASE=$WORKON_HOME

export PIP_RESPECT_VIRTUALENV=true

fi

创建 $HOME/.virtualenvs 目录,以后可在里面创建新的Virtualenv,如果你的Virtualenv不想放在里面,也可以只建立符号链接。

使用:

列出虚拟环境列表: workon 或者 lsvirtualenv

新建虚拟环境: mkvirtualenv [虚拟环境名称]

启动/切换虚拟环境: workon [虚拟环境名称]

删除虚拟环境: rmvirtualenv [虚拟环境名称]

离开虚拟环境: deactivate

需要注意的是,当你进入ENV后,你所调用的python程序是在 ENV/bin 目录下,因此脚本开头的 #!/usr/bin/python 就没有用了,运行脚本时需要显式调用python解释器。

3.1.3 ENV安装Shell脚本

由于整个ENV目录不适合上传至 github page 的仓库(上传后出现各种 build page error )。 所以我写了个安装ENV的Shell脚本:

mkdir _py_virtualenv

pip2 install virtualenv && virtualenv _py_virtualenv --no-site-packages && source _py_virtualenv/bin/activate && pip2 install pygments && pip2 install beautifulsoup4

切记此脚本只能用 source 运行,不能当成可执行文件运行。因为source是直接在当前shell环境中执行,而可执行文件方式只会在新的子shell下执行(执行到source部份就会出错)

3.2 编码问题

由于我使用的是python2.7 ,而 python2.7 的编码问题一直为人所诟病。python2.7默认的是 ascii编码 ,当程序中出现非ascii编码 时,python的处理常常会报这样的错:

UnicodeEncodeError: 'ascii' codec can't encode characters blalbla

对此有两种办法应对:

一种是涉及非ascii编码的字串后添加 encode("utf8") ,不过这种方法似乎时灵时不灵,而且一旦少写一个地方,将会导致大量的错误报告,不推荐。

另一种是在程序加载之初就将解释器编码改为 utf8 ,这也是我所采用的:

import sys

reload(sys)

sys.setdefaultencoding('utf8')

3.3 命令行交互

本脚本是通过命令行运行的,高亮的文件由用户通过命令行参数指令,利用 sys 模块可以很好地解析 cli参数 ,因此用户可以方便地利用shell的一些特性输入参数,具体代码实现如下:

if len(sys.argv)==1:

print 'No Arguments!'

else:

for file in sys.argv[1:]:

if '.html' in file:

hightlight_instance = Pygments_Html(file)

hightlight_instance.colorize()

sys.argv 是一个 list , sys.argv[0] 是程序名, sys.argv[1:] 才是cli中的各个参数名。

3.4 Pygments_Html

Pygments_Html 是我写的用于高亮代码的类,仅包含两个函数: __init__ 和 colorize 。

3.4.1 __init__

初始化函数

def __init__(self,file):

self.filename = file

self.language_dict = {'sh':'sh','matlab':'matlab','C':'c','C++':'c++','css':'css',

'python':'python','scheme':'scheme','latex':'latex',

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:武汉网站建设 http://www.feimao666.com

上一篇:细说angular Form addControl方法 下一篇:最后一页