用Python高亮org-mode代码块,python高亮org-mode

作者:操作系统

用Python高亮org-mode代码块,python高亮org-mode

小说同期可在自个儿的github blog上读书:

本文完整代码可以看到作者的_pygment-html.py

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">import pygments
print "aa"
</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相互独立,互不影响,它亦可:

  1. 在未曾权限的情状下安装新套件
  2. 不等接受能够利用差别的套件版本
  3. 套件进级不影响其余使用

安装: 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 简化操作:

  1. 将有所设想景况整合在一个索引下
  2. 关押(新扩张,删除,复制)设想情形
  3. 切换虚构情况

安装: 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',
                          'ruby':'ruby','css':'css','html':'html','others':'text'}

filename 为代管理的html文件,而 language_dict 则为 org-mode 扶持的言语名到 pygments 援助的语言名的照射(因为两岸会有细微差别),若org-mode中的语言不为pygments所扶植,则映射至 text ,以纯文本情势出口。

注: org-mode 所扶持的言语可用 ls /usr/share/emacs/site-lisp/org-mode/ob-* 看到,而 pygments 扶持的可在pygments.org/docs/lexers 上观察

3.4.2 colorize

高亮函数,对 filename 文件所饱含的代码块举行高亮。

Read file:

先读入对应文件流至 file_read :

try:
    # open the html file
    file = open( self.filename,'r' )
except IOError:
    print self.filename,'not exists'
    return

file_read = file.read()
print "Opening",self.filename
file.close()

RE:

然后从 file_read 提收取含有在 <div class="org-src-container">...</div> 内的html代码:

import re
src_html_list = re.findall(r'<div class="org-src-container">.*?</div>',file_read,re.S)

领到是运用 re 模块实行,正则表明式中 .*? 代表 惰性匹配 ,之所以说是惰性,是因为它会协作尽大概少的字符,它从第叁个字符开始找起,风姿罗曼蒂克旦切合条件,登时保存到异常集结中,然后继续开展搜寻。与之相反的是不加  的 贪婪匹配 。

re.S 是正则表明式的叁个 flag ,因为要求搜求的文字跨愈来愈多行,若不加那几个falg,python的re就只会黄金年代行生机勃勃行地去匹配,若加了那一个 flag ,表明式中的 .* 就能够合营包涵 n 在内的换行符。

BeautifulSoup:

跟着便要开端对 src_html_list 里的各样成分做拍卖:

import BeautifulSoup4
for src_html in src_html_list:
    soup=BeautifulSoup(src_html)
    src_soup = soup.find("div",class_="org-src-container")
    language = (src_soup.pre['class'][1]).split('-')[1]

此处运用 BeautifulSoup 对 src_html 富含的html举行深入分析,这里 soup.find 使用了多少个参数,前一个是急需寻觅的 tag,后面的 class_ 是 tag 中 class 属性,重回符合那四个原则的三个 soup 对象―― src_soup 。代码块的言语保存在<pre> 的 class 属性中,把它提抽出来存在 language 里。

将 language 映射至 pygments 所帮忙的语言名:

if language in self.language_dict:
    language = self.language_dict[language]
else:
    language = self.language_dict['others']

Pygments:

现行能够用 pygments 高亮代码了:

from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter

lexer = get_lexer_by_name(language, stripall=True)
formatter = HtmlFormatter(linespans='line', cssclass="highlight")
src_colorized = highlight(src_soup.text, lexer, formatter)

Pygments 是 python 二个用以高亮代码的模快

其中第7行中的 src_soup.text 可以将 soup 对象中的 html tags 全部去掉,只剩下纯文本的原生代码。

highlight 函数有八个参数:第一个是用来高亮的代码串;第二个是 lexer ,用于钦赐代码语言;第八个是 formatter ,用于钦赐输出样式。

在这里,指定 formatter 为 HtmlFormatter ,即出口为 html 代码,其中 cssclass 用于钦命 div 的样式名字,linespans 指定为 line ,用于钦定 ` 的id前缀为line` ,能够用来输骑行号 ,输出格式如下:

<div class="highlight">
  <pre>
    ...
    ...
    ...
    ...
  </pre>
</div>

待会作者会为 .hight 设计 CSS ,调节代码及行号样式。

Replace:

src_colorized 未来积攒了pygments高亮html代码,需求替换掉原有的:

file_read = file_read.replace(src_html,src_colorized)

replace 有多个参数,第三个是须要被沟通的旧文本,第二个是新文本。

Rewrite:

for 循环达成后,意味着全数代码已经高亮实现,能够将新的html重写进去:

file = open( self.filename,'w' )
file.write(file_read)
file.close()

3.5 CSS

上面的 pygments 只负担输出html构造,而 CSS 却是还未内定。

首先生成代码颜色的体制:

pygmentize -S default -f html > your/path/pygments.css

改动的体制文件加到我们的网页中:

<link rel="stylesheet" href="/your/path/pygments.css">

由于自个儿利用 jekyll ,所以自个儿将 css 文件发在 assets/themes/havee/css/ 下

接下来便必要钦命行号样式,上面说了行号由 .hightlight pre span 决定的:

.highlight pre {
    counter-reset: linenumbers;
}
.highlight pre > span:before {
  font-size: .9em;
  color: #aaa;
  content: counter(linenumbers);
  counter-increment: linenumbers;
  text-align: center;
  width: 2.5em;
  left: -0.5em;
  position: relative;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  /* No support for these yet, use at own risk */
  -o-user-select: none;
  user-select: none;
}

行号是由 counter 自动生成,14行至21行的 *-user-select 制止行号被选中,如此浏览代码是能够很有利地复制代码。

4 用法

在Shell中运作脚本,shell命令前面跟html文件名

随笔同时可在本人的github blog上阅读:...

本文由金冠53777-金冠娱乐53777-Welcome发布,转载请注明来源

关键词: