forked from urbit/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
anchors.py
executable file
·135 lines (100 loc) · 3.89 KB
/
anchors.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
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
import os
import sys
from pathlib import Path
from typing import List, Tuple
# inspired by weights.sh
# NOTE: This script does not prevent you from shooting yourself in the foot.
# If you manually set a bogus value for insert_anchor_links it will not fix it for you
"""
1. get a list of all .md files
2. for each md file
a. get front matter
b. get value of key `insert_anchor_links`, default to none if not present
c. output a tuple of (setting, file)
3. accumulate all anchor setting values for all md files
4. write tuple to 'anchors' file, prompt to edit, open in preferred editor
5. once prompt is answered, read back file
6. read edited 'anchors' file, overwrite new setting for each file
"""
ANCHOR_KEY = "insert_anchor_links = "
ANCHOR_FILE = "anchors"
def nth_occurrence(arr, target_value, wanted_idx):
return [idx for idx, val in enumerate(arr) if val == target_value][wanted_idx - 1]
def validate_entry(setting: str, file: str):
if not setting in ["left", "right", "none"]:
sys.exit(f"Invalid setting '{setting}' provided for file '{file}'")
def find_all_mds() -> List[str]:
# the `insert_anchor_links` is only applicable on `_index.md` files (i.e. sections)
return [str(p) for p in Path('./').rglob('**/_index.md')]
def setting_from_frontmatter(lines: List[str]) -> str:
# 'insert_anchor_links = "none"' -> 'none'
for line in lines:
if line.startswith(ANCHOR_KEY):
# 1. 'insert_anchor_links = "none"\n'
# 2. ['insert_anchor_links = ' '"none"\n'][1] => '"none"\n'
# 3. "none\n"
# 4. "none"
return line \
.split(ANCHOR_KEY)[1] \
.replace('\"', '') \
.replace('\n', '')
return "none" # default setting if key not present
def anchors_from_frontmatter(md_files: List[str]) -> List[Tuple[str, str]]:
# returns tuple(setting, file)
anchor_settings = []
for md_file in md_files:
with open(md_file, "r") as f:
lines = f.readlines()
setting = setting_from_frontmatter(lines)
anchor_settings.append((setting, md_file))
return anchor_settings
def write_anchor_file(anchor_settings: List[Tuple[str, str]]):
with open(ANCHOR_FILE, "w+") as f:
for setting, file in anchor_settings:
f.write(f"{setting} {file}\n")
def prompt_editor():
editor = os.getenv('EDITOR', 'nano')
os.system(f"{editor} {ANCHOR_FILE}")
input("Edit the anchor settings and press enter...")
def read_anchor_file() -> List[Tuple[str, str]]:
anchor_settings = []
with open(ANCHOR_FILE, "r") as f:
for line in f:
line = line.replace('\n', '')
setting, file = line.split(' ')
anchor_settings.append((setting, file))
return anchor_settings
def write_entry(setting: str, file: str):
validate_entry(setting, file)
# not optimized
with open(file, "r+") as f:
lines = f.readlines()
# lines = list(filter(bool, text.split('\n'))) # split text by lines,
fm_end = nth_occurrence(lines, "+++\n", 2) # get index of end of front matter (signaled by second '+++')
# remove existing setting if it exists
for line in lines[:fm_end]:
if line.startswith(ANCHOR_KEY):
lines.remove(line)
fm_end -= 1 # correct the index for the removal
if setting != "none":
# by default, there is no need to specify "none"
lines.insert(fm_end, ANCHOR_KEY + f'"{setting}"' + '\n') # insert the setting right before the end of front matter
f.seek(0) # go to beginning of file
f.writelines(lines) # overwrite with new contents
f.truncate() # idk why but necessary for bug-free behviour (otherwise it adds excess newlines and stuff)
def anchors_to_frontmatter(anchor_settings: List[Tuple[str, str]]):
for setting, file in anchor_settings:
write_entry(setting, file)
def cleanup():
os.remove("anchors")
def main():
files = find_all_mds()
print(f'found {len(files)} .md files')
write_anchor_file(anchors_from_frontmatter(files))
prompt_editor()
anchors_to_frontmatter(read_anchor_file())
cleanup()
print('done')
if __name__ == '__main__':
main()