Skip to content

Instantly share code, notes, and snippets.

@CRImier
Last active October 27, 2023 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CRImier/a0c181038ba0aca4298f9a57c86e1f24 to your computer and use it in GitHub Desktop.
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.
# 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