Skip to content

Instantly share code, notes, and snippets.

@Luckz
Created September 20, 2021 11:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Luckz/74cdd60a795e72f677c0db5c660a4922 to your computer and use it in GitHub Desktop.
Save Luckz/74cdd60a795e72f677c0db5c660a4922 to your computer and use it in GitHub Desktop.
Tabs Outliner: kill duplicate windows
// ctrl - shift - J on Tabs Outliner to open dev tools,
// then Sources -> Snippets -> New Snippet.
// Rightclick -> Run to execute.
// cyrb53 stolen from https://stackoverflow.com/a/52171480
const cyrb53 = function(str, seed = 0) {
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1>>>0);
};
function nodeterate(currentNode, stringBuilder) {
if (currentNode.type == "separatorline") stringBuilder.push("separatorline");
else if (currentNode.type == "textnote") stringBuilder.push(`textnote ${currentNode?.persistentData?.note}`);
else if (currentNode.type == "win" || currentNode.type == "savedwin") stringBuilder.push("window");
else stringBuilder.push(currentNode.getHref());
for (const sn of currentNode.subnodes) {
nodeterate(sn, stringBuilder);
}
}
function nukeNodeArray(nodeArray) {
const DUMMY = false;
for (const currentNode of nodeArray) {
if (currentNode.type !== "win" && currentNode.type !== "savedwin") {
console.log("this node should not have almost died:");
console.log(currentNode);
continue;
}
if (DUMMY) {
console.log("would now kill:");
console.log(currentNode);
} else {
console.log("removing node:");
console.log(currentNode);
currentNode.removeOwnTreeFromParent();
}
}
}
function killDupes(killActive = false) {
let dupes = {};
for (const nod of treeView.treeModel.currentSession_rootNode.subnodes) { // only check root level nodes, don't do complex recursive checks for "sub-roots"
const strbld = [];
nodeterate(nod, strbld);
const hash = cyrb53(strbld.join());
if (dupes.hasOwnProperty(hash)) dupes[hash].push(nod);
else dupes[hash] = [nod];
}
for (const duperino of Object.values(dupes)) {
if (duperino.length < 2) continue;
const inactiveNodes = duperino.filter(x => x.type !== "win"); // keep loaded window(s) alive
if (inactiveNodes.length < duperino.length) {
if ((duperino.length - inactiveNodes.length) > 1) {
console.log("WARNING: duplicate active windows ->");
for (const loadedWindow of duperino.filter(x => x.type == "win")) console.log(loadedWindow);
}
nukeNodeArray(inactiveNodes);
if (killActive) nukeNodeArray(duperino.filter(x => x.type == "win").slice(1));
}
else { // keep oldest
nukeNodeArray(duperino.slice(1));
}
}
}
killDupes();
// to also prune duplicate *loaded* windows down to a single one, try: killDupes(true);
// note that this will disregard how many subnodes are loaded!
@Luckz
Copy link
Author

Luckz commented Sep 25, 2021

var NodeTypesEnum = {TAB:"tab", SAVEDTAB:"savedtab", WAITINGTAB:"waitingtab", ATTACHWAITINGTAB:"attachwaitingtab", WINDOW:"win", SAVEDWINDOW:"savedwin", WAITINGWINDOW:"waitingwin", SESSION:"session", TEXTNOTE:"textnote", SEPARATORLINE:"separatorline", GROUP:"group"};
relevant types seem to be tab, savedtab, win, savedwin, and perhaps separatorline and textnote. I guess the root node could be session, groups are actually win/savedwin and not group, and IDK what the three waiting ones are.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment