需求
写一个项目,有一些文档,文档里有的有待高亮显示,但是md不能让用户直接看见渲染后的结果;html发出去显得太开放了;截图之类的不仅土且空间利用率很差。
提供思路:写自动化程序将其包装进一个可执行文件,可通过命令行参数控制文档的输出,如下面这样
document.exe -exception 124
即输出exception类型的帮助文档,编号为124
思路
我们模仿md提供一个简化版的Markdown,然后利用控制台的彩色字符输出控制码,把要高亮的词汇静态嵌入进去,把整个文档写进另一个语言的函数,函数内调用打印函数输出彩色文档。然后自动化编写解析参数的函数,就能实现如上效果了。分析图如下:
正式实现
写好输出帮助的函数(很低级):
# 显示帮助文档
def show_help():
print("Usage: docgen <type> <filename> <id> <output>")
print("type:\n")
print(" -b\tGenerate document from source file with 'build-time error' mode")
print(" -r\tGenerate document from source file with 'run-time error' mode")
print(" -w\tGenerate document from source file with 'warning' mode")
print("Note: You must give all these arguments or program won't run at all.")
print("Note: Especially, if you use '-v' or '-h' option, you needn't give filename or output name.")
print(" -v\tDisplay version")
print(" -h\tDisplay this help message.")
print("Note: Use '`' to sign words which are wanted to show with highlight.")
包装一下报错函数(应对id无法转换成int,越界,用户输入不正确等情况):
# 输出错误
def raise_error(con):
print("docgen: error:", con)
exit(1)
根据工具的帮助,写出解析命令行参数的主函数
def main():
args = sys.argv
tp = None # 保存文档类型
for idx, v in enumerate(args):
if idx == 0:
continue
elif idx == 1:
# type字段,可能是-h
if v == "-h":
show_help()
exit(0)
else:
if v not in ["-b", "-r", "-w"]:
raise_error("Unknown argument at position 1:%s" % v)
tp = v
elif idx == 2:
# 输入文件字段
try:
input_file = open(v, "r", encoding="utf-8")
except Exception as e:
raise_error("Could not open file '%s':%s" % (v, str(e)))
elif idx == 3:
# id字段
try:
match_id = int(v)
except:
raise_error("Could not convert `id` to int")
elif idx == 4:
# 输出文件字段
try:
output_file = open(v, "w+", encoding="utf-8")
except Exception as e:
raise_error("Could not create file '%s':%s" % (v, str(e)))
else:
raise_error("Too many arguments")
if idx != 4:
raise_error("Too few arguments")
generate(tp, input_file, output_file, match_id)
包括转换参数,检查意义,检查参数充分性,然后调用包装后的生成逻辑.
generate
接受四个参数:
tp
控制文档类型(b/r/w)- input_file接受打开了的IO对象,可读
- output_file接受打开了可写的IO对象。注意,编码要一致。
- match_id 接受文档的标记,即后续要映射的数字id
程序处理主逻辑:生成:
def generate(tp, input_file, output_file, match_id):
content = input_file.read()
# 下面写入函数头部
output_file.write("pub fn doc_%s_print_%d() {\n" %
({"-b": "bte", "-r": "rte", "-w": "wrn"}[tp], match_id))
output_file.write("\tprintln!(\"")
# 正式解析并输出代码
flag = False # 控制未进入高亮模式
for c in content:
if c == "\n":
output_file.write("\");\n\tprintln!(\"")
elif c == "`":
if flag:
# 已经是高亮模式
output_file.write("\\x1b[0m")
flag = False
else:
# 进入高亮模式
output_file.write("\\x1b[1;33m")
flag = True
elif c == "\"":
output_file.write("\\\"")
elif c == "\\":
output_file.write("\\\\")
elif c == "{":
output_file.write("{{")
elif c == "}":
output_file.write("}}")
else:
output_file.write(c)
output_file.write("\");\n}\n")
if flag:
# 还在高亮模式之内,会导致结束的ASCII控制码未输出
raise_error("Still in highlight mode")
output_file.close()
input_file.close()
一开始根据预设的rust函数命名规则生成头部,然后反复调用println!宏,有高亮的就检查下插进去,然后特殊字符特殊转义一下免得rust内部语法出问题。最后写函数尾部,检查一下高亮块是否关闭,最后清理,关文件,逻辑算简单。
实现效果:
(测试数据)
xyz:normal_text
`abc`:`highlight`
muti-line:`xxxxxxx
fdsfdsfdsfsdf
oer;';;'erer;'`
special-chars:
" " " { } } { \ \
Chinese-tests:
这是中文
这是`高亮`的中文
高亮多行中文
`多行的
、 中
文\ 包含特
" 殊 符{}}{号`
处理命令:
python docgen.py -b test.ddoc 124 test.rs
手动加上主函数:
编译运行,得到初步结果:
可见一切正常。下一节将实现整合文档到一个主文件,可实现自动输出需要的文档内容。