"use strict";

const prot = atom.emitter.constructor.prototype;
const emit = prot.emit;
const emissions = Object.defineProperty([], "log", {
	get(){return this.map(e => e[0]).join("\n")}
});

/** Crude debugging method to see what events we can hook into */
function traceEmissions(active){
	prot.emit = !active ? emit : function(name){
		if("did-update-state" !== name){
			emissions.push(Array.from(arguments));
			console.trace(arguments);
		}
		emit.apply(this, arguments);
	};
};

/** Update an editor's settings using those found in any embedded modelines */
function readModelines(editor){
	let text    = editor.getText();
	let tabStop = text.match(/(?:^|\s)vi(?:m[<=>]?\d+|m?):.*?(?<=[:\x20])(?:ts|tabstop)\s*=(\d+)/i);
	if(tabStop){
		const {setTabLength} = editor.constructor.prototype;
		setTabLength.call(editor, +tabStop[1]);
	}
}

/** Return a reference to the active text-editor's root element in the Shadow DOM */
function getRootEditorElement(){
	let el = atom.workspace.getActiveTextEditor().getElement();
	return el ? el.shadowRoot.querySelector(".scroll-view") : null;
}

/**
 * Generate a function to switch between two states each time it runs.
 *
 * @param {Function} a - Initial state
 * @param {Function} b - Alternate state
 * @return {Function}
 */
function Switch(a, b){
	let state = 0;
	a();
	return (...args) => ((state = !state)? b:a)(...args);
}

global.cp  = c => hex(chr(c));
global.chr = c => (c + "").codePointAt(0);
global.hex = n => n.toString(16).toUpperCase();
global.Switch = Switch;
global.getRootEditorElement = getRootEditorElement;
global.traceEmissions = traceEmissions;
global.readModelines = readModelines;
global.print = require("print");
global.emissions = emissions;

@@ -1085,16 +1085,642 @@
 ull;%0A%7D%0A%0A
+%0A/** Generate specs when preparing PRs for Atom's grammar packages */%0Afunction specSnap()%7B%0A%09const editor   = atom.workspace.getActiveTextEditor();%0A%09const grammar  = editor.getGrammar();%0A%09const text     = editor.getText();%0A%09const %7Btokens%7D = grammar.tokenizeLine(text);%0A%09%0A%09let output = %22%7Btokens%7D = grammar.tokenizeLine('%22 + text.replace(/'/g, %22%5C%5C'%22) + %22')%5Cn%22;%0A%09tokens.forEach((token, index) =%3E %7B%0A%09%09let %7Bvalue, scopes%7D = token;%0A%09%09value   = value.replace(/'/g, %22%5C%5C'%22);%0A%09%09scopes  = %22%5B'%22 + scopes.join(%22', '%22) + %22'%5D%22;%0A%09%09output += %60expect(tokens%5B$%7Bindex%7D%5D).toEqual value: '$%7Bvalue%7D', scopes: $%7Bscopes%7D%5Cn%60;%0A%09%7D);%0A%09%0A%09return output;%0A%7D%0A%0A%0A
 /**%0A * G
@@ -2329,16 +2329,44 @@
 ns = emissions;%0A
+global.specSnap = specSnap;%0A

Add helper function for writing Atom grammar specs