forked from naokazuterada/MarkdownTOC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMarkdownTOC.py
124 lines (95 loc) · 3.31 KB
/
MarkdownTOC.py
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
import sublime, sublime_plugin, re, os.path
pattern_anchor = re.compile(r'\[.*?\]')
pattern_endspace = re.compile(r' *?\z')
TOCTAG_START = "<!-- MarkdownTOC -->"
TOCTAG_END = "<!-- /MarkdownTOC -->"
class MarkdowntocInsert(sublime_plugin.TextCommand):
def run(self, edit):
if not self.find_tag_and_insert(edit):
sels = self.view.sel()
for sel in sels:
# add TOCTAG
toc = self.get_TOC(sel.end())
toc = TOCTAG_START+"\n"+toc
toc = toc+TOCTAG_END+"\n"
self.view.insert(edit, sel.begin(), toc)
# Search MarkdownTOC comments in document
def find_tag_and_insert(self,edit):
sublime.status_message('fint TOC tags and refresh its content')
toc_starts = self.view.find_all("^"+TOCTAG_START+"\n")
for toc_start in toc_starts:
if 0 < len(toc_start):
toc_end = self.view.find("^"+TOCTAG_END+"\n",toc_start.end())
if toc_end:
toc = self.get_TOC(toc_end.end())
tocRegion = sublime.Region(toc_start.end(),toc_end.begin())
self.view.replace(edit, tocRegion, toc)
sublime.status_message('find TOC-tags and refresh')
return True
# self.view.status_message('no TOC-tags')
return False
# TODO: add "end" parameter
def get_TOC(self, begin=0):
# Search headings in docment
headings = self.view.find_all("^#{1,2}? ")
items = [] # [[headingNum,text],...]
for heading in headings:
if begin < heading.end():
heading_text = self.view.substr(sublime.Region(heading.end(),self.view.line(heading).end()))
heading_num = heading.size()-1
items.append([heading_num,heading_text])
# Shape TOC ------------------
items = format(items)
# Create TOC ------------------
toc = ''
for item in items:
heading_num = item[0] - 1
heading_text = item[1].rstrip()
# add indent by heading_num
for i in range(heading_num):
toc += '\t'
# Handling anchors
matchObj = pattern_anchor.search(heading_text)
if matchObj:
only_text = heading_text[0:matchObj.start()]
only_text = only_text.rstrip()
toc += '- ['+only_text+']'+matchObj.group()+'\n'
else:
toc += '- '+heading_text+'\n'
return toc
def format(items):
headings = []
for item in items:
headings.append(item[0])
# ----------
# set root to 1
min_heading = min(headings)
if 1<min_heading:
for i,item in enumerate(headings):
headings[i] -= min_heading-1
headings[0] = 1 # first item must be 1
# minimize "jump width"
for i,item in enumerate(headings):
if 0<i and 1<item-headings[i-1]:
before = headings[i]
after = headings[i-1]+1
headings[i] = after
for n in range(i+1,len(headings)):
if(headings[n]==before):
headings[n] = after
else:
break
# ----------
for i,item in enumerate(items):
item[0] = headings[i]
return items
# Search and refresh if it's exist
class MarkdowntocUpdate(MarkdowntocInsert):
def run(self, edit):
MarkdowntocInsert.find_tag_and_insert(self,edit)
class AutoRunner(sublime_plugin.EventListener):
def on_pre_save(self, view):
# limit scope
root, ext = os.path.splitext(view.file_name())
if ext == ".md" or ext == ".markdown":
view.run_command('markdowntoc_update')