Last active
October 27, 2023 09:55
-
-
Save CRImier/a0c181038ba0aca4298f9a57c86e1f24 to your computer and use it in GitHub Desktop.
Reconstruct a Notepad++ session using an existing session.xml file (without entries or with entries but outdated) and contents of the 'backup' folder with your drafts. named fixshit because I was very displeased when I lost my session and the backup was pretty old. need to set up a cron job fr.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# run this in the Notepad++ profile directory | |
# changing these variables is left as an exercise to the reader | |
# please, do backups of the session.xml | |
# and of the Notepad++ profile directory too | |
# just remember that the backups folder might contain sensitive data cuz it has all your drafts in it | |
# also, install lxml library for this to work | |
backup_dir = 'backup' | |
backup_fp = "C:\\users\\User\\AppData\\Roaming\\Notepad++\\backup\\" | |
session_in = 'session_beforesort.xml' | |
session_out = 'session.xml' | |
import lxml | |
from lxml import etree | |
from copy import copy | |
import os | |
def_itm = [('firstVisibleLine', '0'), | |
('xOffset', '0'), | |
('scrollWidth', '1'), | |
('startPos', '0'), | |
('endPos', '0'), | |
('selMode', '0'), | |
('offset', '0'), | |
('wrapCount', '1'), | |
('lang', 'None (Normal Text)'), | |
('encoding', '-1'), | |
('userReadOnly', 'no'), | |
('filename', ''), | |
('backupFilePath', ''), | |
('originalFileLastModifTimestamp', '0'), | |
('originalFileLastModifTimestampHigh', '0'), | |
('tabColourId', '-1'), | |
('mapFirstVisibleDisplayLine', '-1'), | |
('mapFirstVisibleDocLine', '-1'), | |
('mapLastVisibleDocLine', '-1'), | |
('mapNbLine', '-1'), | |
('mapHigherPos', '-1'), | |
('mapWidth', '-1'), | |
('mapHeight', '-1'), | |
('mapKByteInDoc', '0'), | |
('mapWrapIndentMode', '-1'), | |
('mapIsWrap', 'no') | |
] | |
with open(session_in, 'rb') as f: | |
c = f.read() | |
root = etree.XML(c) | |
# surely unneeded, just cba to rewrite | |
entries = [f for f in root[0][0]] | |
# preexisting_files | |
pexf = [] | |
for entry in entries: | |
fn = entry.get('filename') | |
fp = entry.get('backupFilePath') | |
if fp and '@' in fp: | |
af = fp.rsplit('\\', 1)[-1] | |
afp, aft = af.split('@') | |
else: | |
af = ''; afp = ''; aft = '' | |
# idk if I need all that but I'm fucking using it | |
pexf.append([fn, fp, af, afp, aft]) | |
# o(n^2) woohoo | |
for filename in os.listdir(backup_dir): | |
#print(filename) | |
if '@' not in filename: | |
raise(filename) #lol what | |
fn, ft = filename.rsplit('@', 1) | |
# this might have issues processing things like non-'new NNN' files found in backup dir! | |
for i, el in enumerate(pexf): | |
if el[0] != fn: | |
continue | |
print(filename, 'found in session file', el) | |
elm = root[0][0][i] | |
# I don't seem need this, can just replace everything no matter if it differs or not | |
# mainly because it won't work if the profile folder path changes, and Notepad++ isn't smart enough to use relative paths for at least the 'new NNN' files weh | |
#if el[2] != filename: | |
# print(filename, 'is newer than in session file', el) | |
elm.set('backupFilePath', backup_fp + filename) | |
#print(backup_fp+filename) | |
break | |
else: | |
print(filename, 'not found in session file') | |
el = etree.Element("File") | |
for k, v in def_itm: | |
el.set(k, v) | |
el.set('backupFilePath', backup_fp + filename) | |
el.set('filename', fn) | |
root[0][0].append(el) | |
# for some reason, this might leave the 'new NNN' documents unsorted | |
# and that is infuriating to deal with cuz the sorting is essentially chronological | |
# but given the numbers in names, easy to fix | |
# this sorting procedure is written to preserve the order | |
# of any already-opened documents that are not 'new NNN' | |
# so that it is comfy to use | |
# so, we go through the tree again and sort everything | |
print(len(root[0][0])) | |
unsorted = [] | |
for i, entry in enumerate(root[0][0]): | |
fn = entry.get('filename') | |
if fn.startswith('new '): | |
num = int(fn.rsplit(' ', 1)[-1]) | |
unsorted.append([i, num, entry]) | |
ununsorted = sorted(unsorted, key=lambda x: x[1]) | |
for i, e in enumerate(ununsorted): | |
_, _, entry = e | |
# get the number of the spot that the entry could be taking | |
pos = unsorted[i][0] | |
# occupy that position | |
# apparently, I can't do this: root[0][0][pos] = entry | |
# instead, need to recreate the damn element | |
el = etree.Element("File") | |
for k, v in entry.items(): | |
el.set(k, v) | |
root[0][0][pos] = el | |
print(len(root[0][0])) # sanity check | |
#print(etree.tostring(root)) | |
with open(session_out, 'wb') as f: | |
f.write(etree.tostring(root)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment