5from pathlib import Path
6from typing import List, Tuple
9# inspired by weights.sh
11# NOTE: This script does not prevent you from shooting yourself in the foot.
12# If you manually set a bogus value for insert_anchor_links it will not fix it for you
141. get a list of all .md files
17 b. get value of key `insert_anchor_links`, default to none if not present
18 c. output a tuple of (setting, file)
193. accumulate all anchor setting values for all md files
204. write tuple to 'anchors' file, prompt to edit, open in preferred editor
215. once prompt is answered, read back file
226. read edited 'anchors' file, overwrite new setting for each file
25ANCHOR_KEY = "insert_anchor_links = "
26ANCHOR_FILE = "anchors"
28def nth_occurrence(arr, target_value, wanted_idx):
29 return [idx for idx, val in enumerate(arr) if val == target_value][wanted_idx - 1]
31def validate_entry(setting: str, file: str):
32 if not setting in ["left", "right", "none"]:
33 sys.exit(f"Invalid setting '{setting}' provided for file '{file}'")
36def find_all_mds() -> List[str]:
37 # the `insert_anchor_links` is only applicable on `_index.md` files (i.e. sections)
38 return [str(p) for p in Path('./').rglob('**/_index.md')]
40def setting_from_frontmatter(lines: List[str]) -> str:
41 # 'insert_anchor_links = "none"' -> 'none'
43 if line.startswith(ANCHOR_KEY):
44 # 1. 'insert_anchor_links = "none"\n'
45 # 2. ['insert_anchor_links = ' '"none"\n'][1] => '"none"\n'
49 .split(ANCHOR_KEY)[1] \
53 return "none" # default setting if key not present
55def anchors_from_frontmatter(md_files: List[str]) -> List[Tuple[str, str]]:
56 # returns tuple(setting, file)
59 for md_file in md_files:
60 with open(md_file, "r") as f:
62 setting = setting_from_frontmatter(lines)
63 anchor_settings.append((setting, md_file))
65 return anchor_settings
67def write_anchor_file(anchor_settings: List[Tuple[str, str]]):
68 with open(ANCHOR_FILE, "w+") as f:
69 for setting, file in anchor_settings:
70 f.write(f"{setting} {file}\n")
74 editor = os.getenv('EDITOR', 'nano')
75 os.system(f"{editor} {ANCHOR_FILE}")
76 input("Edit the anchor settings and press enter...")
78def read_anchor_file() -> List[Tuple[str, str]]:
81 with open(ANCHOR_FILE, "r") as f:
83 line = line.replace('\n', '')
84 setting, file = line.split(' ')
85 anchor_settings.append((setting, file))
87 return anchor_settings
90def write_entry(setting: str, file: str):
91 validate_entry(setting, file)
95 with open(file, "r+") as f:
97 # lines = list(filter(bool, text.split('\n'))) # split text by lines,
98 fm_end = nth_occurrence(lines, "+++\n", 2) # get index of end of front matter (signaled by second '+++')
100 # remove existing setting if it exists
101 for line in lines[:fm_end]:
102 if line.startswith(ANCHOR_KEY):
104 fm_end -= 1 # correct the index for the removal
106 if setting != "none":
107 # by default, there is no need to specify "none"
108 lines.insert(fm_end, ANCHOR_KEY + f'"{setting}"' + '\n') # insert the setting right before the end of front matter
109 f.seek(0) # go to beginning of file
110 f.writelines(lines) # overwrite with new contents
111 f.truncate() # idk why but necessary for bug-free behviour (otherwise it adds excess newlines and stuff)
115def anchors_to_frontmatter(anchor_settings: List[Tuple[str, str]]):
116 for setting, file in anchor_settings:
117 write_entry(setting, file)
124 files = find_all_mds()
125 print(f'found {len(files)} .md files')
126 write_anchor_file(anchors_from_frontmatter(files))
128 anchors_to_frontmatter(read_anchor_file())
133if __name__ == '__main__':
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list