-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmd.py
More file actions
294 lines (248 loc) · 9.9 KB
/
md.py
File metadata and controls
294 lines (248 loc) · 9.9 KB
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
import os
import re
import sys
from urllib import parse
class Catalo:
"""
生成md文件目录的脚本,需要传入两个命令行参数:
python Catalo.py [filepath] [options]
:param: filepath: 要生成目录的文件或文件夹路径,不传或传入 -h 直接打印帮助信息
如果传入文件夹路径,会为该文件夹下所有 .md 类型文件添加目录;
允许传入绝对路径或相对路径。
:param: [options]: 可选参数,有五种选项,-r,-w,-wr或-wr,-d,-h不区分大小写。
-r: 只在终端打印目录,手动复制添加。
-w: 在文件开头自动写入目录。
-rw/-wr: 自动写入目录,同时打印在终端。
-d: 删除由脚本添加的目录,区分标准是两个MD5字符串注释 ,所以如果修改了这两部分,使用该参数可能会删除整篇文章。
-h: 打印帮助信息。
"""
# TODO: 在特定位置添加目录
# TODO:改变参数传递顺序,第一个参数不传或传入 -h 直接打印帮助信息
def __init__(self, args: list):
self._code = False # 标记代码块
# TODO: 构造函数太乱了
self._is_Delete = False
if len(args) < 2:
print(help(self))
sys.exit()
else:
if args[1].lower() == '-h':
print(help(self))
sys.exit()
else:
self._filepath = args[1]
try:
second = args[2]
except IndexError:
second = '-RW'
if second.lower() == '-r':
self._is_read = True
self._is_write = False
self._is_Delete = False
if second.lower() == '-w':
self._is_read = False
self._is_write = True
self._is_Delete = False
if second.lower() == '-rw' or second.lower() == '-wr':
self._is_read = True
self._is_write = True
self._is_Delete = False
if second.lower() == '-d':
self._is_read = False
self._is_write = False
self._is_Delete = True
if second.lower() == '-h':
print('\033[32m')
print(help(self))
print('\033[0m')
sys.exit()
@staticmethod
def _build_swop_file(source_path):
"""
建立交换文件
"""
swop_file_path = source_path + '.swop.md'
os.system(f'copy "{source_path}" "{swop_file_path}"')
if os.path.exists(swop_file_path):
print(f"\n 交换文件{swop_file_path}已建立\n")
else:
build_error = Exception("交换文件建立失败,请检查路径是否正确,并确保路径不含有特殊字符")
raise build_error
return swop_file_path
def _read_and_creat_catalo(self, swop_file_path):
"""
读交换文件,并且生成文章目录
"""
with open(swop_file_path, 'r', encoding='utf-8') as fp:
lines = fp.readlines()
for line in lines:
# 避免代码块中python风格的注释被当作一级标题
r = r'^```.+'
res = re.match(r, line)
if res is not None:
self._code = True
r2 = r'^```$'
res2 = re.match(r2, line)
if res2 is not None:
self._code = False # 代码块结束
# 找到标题行
r = r'^(#*# ).+'
resault = re.match(r, line)
if resault is not None and self._code is False:
resault = resault.group()
title = resault
r3 = r'^(#*)'
r4 = r'^(#* )'
# 判断有几个#
resault = re.match(r3, resault).group()
title_size = len(resault)
# 根据#数量计算空格数
space_num = (title_size - 1) * 2
# 得到标题内容
content = re.sub(r4, '', title)
# 标题中的特殊字符需要被删除再编码
special_chars = ['#', '@', '!', '$', '^', '&', '*', ')', '(', '+', '-', '{', '}', '[', ']', '=', '/', ':', ':', '。']
for special_char in special_chars:
content.replace(special_char, '')
space = ' '
url = parse.quote(content) # url编码
repl = f'{space * space_num}* [{content}](#{url})'
yield repl
def _write_in_source_file(self, source_file_path: str):
"""
把文章目录写入到源文件
"""
swop_file_path = source_file_path + '.swop.md'
is_first_write = True
for repl in self._read_and_creat_catalo(swop_file_path):
if self._is_write:
# 第一次直接写入,以后追加写入
if is_first_write:
write_type = 'w'
else:
write_type = 'a'
with open(source_file_path, write_type, encoding='utf-8') as fp:
if is_first_write:
fp.write(
'<!--961032830987546d0e6d54829fc886f6-->\n\n目录(Catalo)\n\n')
fp.write(repl + '\n')
is_first_write = False
if self._is_read:
print(repl)
if self._is_write:
# 最后再添加一行,用来与原文件区分
with open(source_file_path, 'a', encoding='utf-8') as fp:
# TODO: 通过该行与原文件内容进行区分,文章更新时便于删除通过脚本创建的目录,添加新目录
fp.write('\n<!--a46263f7a69f33f39fc26f907cdb773a-->\n')
if self._is_read:
print()
@staticmethod
def _merge_file(source_file_path):
"""
合并源文件和交换文件
"""
swop_file_path = source_file_path + '.swop.md'
with open(source_file_path, 'a', encoding='utf-8') as source_fp:
with open(swop_file_path, 'r', encoding='utf-8') as swop_fp:
lines = swop_fp.readlines()
for line in lines:
source_fp.write(line)
@staticmethod
def _dele_swop_file(source_file_path):
"""
删除交换文件
"""
swop_file_path = source_file_path + '.swop.md'
os.remove(swop_file_path)
def _delete(self, filepath):
"""
删除由本脚本添加的目录
"""
source_file_path = filepath
swop_file_path = source_file_path + '.swop.md'
with open(swop_file_path, 'r', encoding='utf-8') as fp:
lines = fp.readlines()
isdelete = False
is_first_write = True
for line in lines:
r = r'^(<!--961032830987546d0e6d54829fc886f6-->)'
res = re.match(r, line)
if res is not None:
isdelete = True
if is_first_write:
write_type = 'w'
else:
write_type = 'a'
flag = '<!--a46263f7a69f33f39fc26f907cdb773a-->'
if line != flag:
if isdelete is False:
with open(source_file_path, write_type, encoding='utf-8') as sour_fp:
sour_fp.write(line)
is_first_write = False
r2 = r'^(<!--a46263f7a69f33f39fc26f907cdb773a-->)$'
res2 = re.match(r2, line)
if res2 is not None:
# TODO:
isdelete = False
def _file(self, filepath: str):
"""
文件,执行这个函数
"""
source_file_path = os.path.abspath(filepath)
file_name = filepath.split('\\')[-1]
self._build_swop_file(source_file_path)
if self._is_write :
self._write_in_source_file(source_file_path)
self._merge_file(source_file_path)
print('\033[33m')
print(f'{file_name} 目录已添加')
print('\033[0m')
if self._is_Delete:
self._delete(source_file_path)
print('\033[33m')
print(f'{file_name} 目录已删除')
print('\033[0m')
self._dele_swop_file(source_file_path)
def _folder(self, filepath):
"""
文件夹,执行这个函数
"""
# 得到该目录下的所有文件
list_dir = os.listdir(filepath)
path_save = filepath
for dir in list_dir:
if filepath[-1] == '\\':
filepath = f'{path_save}{dir}'
else:
filepath = f'{path_save}\\{dir}'
abs_root_dir = os.path.abspath(filepath)
if os.path.isfile(abs_root_dir):
filetype = abs_root_dir.split('.')[-1]
if filetype.lower() == 'md':
absdir = os.path.abspath(abs_root_dir)
self._file(absdir)
else:
absdir = os.path.abspath(abs_root_dir)
self._folder(absdir)
def run(self):
"""
程序入口,判断是文件夹还是文件
"""
path = os.path.abspath(self._filepath)
if os.path.isfile(path):
try :
self._file(path)
except AttributeError:
print('\033[31m 参数错误')
print('\033[32m')
print(help(self))
print('\033[0m')
sys.exit(1)
else:
self._folder(path)
if __name__ == '__main__':
argv = sys.argv
print(argv)
catalo = Catalo(argv)
print()
catalo.run()