-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathembed_notes.py
More file actions
221 lines (165 loc) · 6.98 KB
/
embed_notes.py
File metadata and controls
221 lines (165 loc) · 6.98 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
# Include the individual, dated Markdown note files into the Person's profile
# under `## Notes` so you can see the entire communication history with them.
import os
from argparse import ArgumentParser
import datetime
import sys
sys.path.insert(1, '../hal/')
import person
import identity
sys.path.insert(1, './')
import md_lookup
import md_person
import md_frontmatter
import md_body
import md_date
import md_interactions
NEW_LINE = "\n"
HEADING_2 = "##"
HEADING_NOTES = HEADING_2 + " Notes"
WIKILINK_OPEN = "[["
WIKILINK_CLOSE = "]]"
MD_EMBED = "!"
MD_SUFFIX = ".md"
EMBEDDED_WIKILINK = MD_EMBED + WIKILINK_OPEN
def get_arguments():
"""
Parse the command line arguments.
"""
parser = ArgumentParser()
parser.add_argument("-f", "--folder", dest="folder", default=".",
help="The folder where each Person has a subfolder named with their slug")
parser.add_argument("-d", "--debug", dest="debug", action="store_true", default=False,
help="Print extra info as the files processed")
parser.add_argument("-x", "--max", type=int, dest="max", default=99999,
help="Maximum number of people to process")
args = parser.parse_args()
return args
def ensure_h1_title_final(person_file, slug):
"""
Ensure the Person file has an H1 title matching the person's name.
This version works after all sections have been updated.
Parameters:
person_file (PersonFile): The person's file object
slug (str): Person's slug e.g. 'spongebob'
Returns:
bool: True if changes were made, False otherwise
"""
# Get the person's name from the filename (without .md extension)
filename = os.path.basename(person_file.path)
person_name = filename.replace(".md", "")
# Fallback: try to get name from identity fields
if not person_name or person_name == slug:
if person_file.identity and person_file.identity.first_name:
person_name = person_file.identity.first_name
if person_file.identity.last_name:
person_name += " " + person_file.identity.last_name
else:
# Final fallback: use capitalized slug
person_name = slug.replace("-", " ").replace("_", " ").title()
h1_title = "# " + person_name
# Check if first section is an H1 title
if person_file.body.sections and person_file.body.sections[0]['heading'].startswith("# "):
# H1 exists, check if it matches expected name
current_h1 = person_file.body.sections[0]['heading'].strip()
if current_h1 == h1_title:
return False # No changes needed
else:
# Update existing H1 to match person name
person_file.body.sections[0]['heading'] = h1_title
return True
else:
# No H1 title exists, add one at the beginning
new_h1_section = {'heading': h1_title, 'content': '\n'}
person_file.body.sections.insert(0, new_h1_section)
return True
def generate_markdown(slug, the_interactions):
"""
Create a set of lines in Markdown with [[Wikilinks]] to each interaction.
Parameters:
slug (str): Person's slug e.g. 'spongebob'
interactions (list): Collection of Interaction.
Returns:
str: Markdown text
Notes:
Generates a set of lines with embedded link to each communication file,
separated by a blank line
If there are two files `2023-02-01.md` and `2024-03-24.md`
```
![[spongebob/2023-02-01.md]]
![[spongebob/2024-03-24.md]]
```
"""
markdown = ""
# Sort the interactions chronologically from old to new
sorted_interactions = sorted(the_interactions, key=lambda x: x.date)
# Make a Wikilink to each interaction file so it can be embedded
for interaction in sorted_interactions:
markdown += EMBEDDED_WIKILINK
markdown += slug + "/" + interaction.filename # Use the filename from the Interaction object
markdown += WIKILINK_CLOSE + NEW_LINE + NEW_LINE
return markdown.strip() # Remove trailing blank lines
def update_interactions(folder):
"""
Given a folder name, load all of the interactions with that person based
on the existence of dated Markdown files for each date where an interaction
occured.
Parameters:
folder (str): Folder containing sub-folders for each person.
Returns:
int: The number of people processed.
Notes:
1. Go through each folder `folder-name` under `People`
2. Find all files with names `YYYY-MM-DD`
3. Create a list of them like this, ordered oldest to newest
```
![[spongebob/2017-08-13.md]]
![[spongebob/2022-12-06.md]]
```
4. Open the corresponding person file where `slug` = `folder-name`
5. Find the section `## Notes`
6. After any bulleted list items (individual notes), replace what is
there with the new list of embedded files.
"""
count = 0
notes_section = md_person.SECTION_NOTES
# get list of people `slug`s from the folder names
slugs = md_person.get_slugs(folder)
# for each person, find the most recent communication
for slug in slugs:
the_interactions = []
top = ""
# get all of the interactions with the person
the_date = md_interactions.get_interactions(slug, os.path.join(folder, slug), the_interactions)
if args.debug:
print(slug + ": " + str(the_date))
# generate the Notes section of the body
interactions_markdown = generate_markdown(slug, the_interactions)
# get the Person's profile
person_file = md_person.read_person_frontmatter(slug, folder)
if person_file is not None:
# get the part of the section before the embedded notes
top = person_file.section_top(notes_section, EMBEDDED_WIKILINK)
top = top.rstrip() # remove trailing whitespace [#21]
# add the new content after the top, effectively replacing what's after top
new_markdown = top + NEW_LINE + NEW_LINE + interactions_markdown
# update what's in the Person's Notes section of their profile
person_file.update_section(slug, notes_section, new_markdown)
# ensure the person file has an H1 title matching their name (after all other updates)
# We need to do this after update_section since that calls body.read() again
h1_updated = ensure_h1_title_final(person_file, slug)
# write the file with the updated section
result = person_file.save()
count += 1
# stop if we've reached the limit of the passed in `max` argument
if args.max and count >= int(args.max):
return count
return count
# main
args = get_arguments()
folder = args.folder
the_interactions = []
if folder and not os.path.exists(folder):
print('The folder "' + folder + '" could not be found.')
elif folder:
count = update_interactions(folder)