textalignhelper

helps aligning code

by Laurens Maneschijn

HTML

<body>
	<h1>text align helper</h1>
	<div class="box">
		<h2>pattern: 
		<select id="select_examplepatterns">
			<option value=""                          >pick example pattern...</option>
			<option value="()(=)"                     >align '='</option>
			<option value="()(//)"                    >align '//' comments</option>
			<option value="(\S)\s*(//)"               >align '//' comments behind lines</option>
			<option value="()\s*(\S+)"                >align 1st wordgroup</option>
			<option value="(\S+)\s*(\S+)"             >align 2nd wordgroup</option>
			<option value="(\S+\s+\S+)\s*(\S+)"       >align 3rd wordgroup</option>
			<option value="(\S+\s+\S+\s+\S+)\s*(\S+)" >align 4th wordgroup</option>
		</select> or edit below:<br>
		</h2>
		<h4>current regex pattern: <code><span id="r"></span></code></h4>
		<input id="i1" type="text" value="(\S+)\s*(\S+)"/>
	</div>

	<div class="box">
		<h2>input:</h2>
		<textarea id="ta1"></textarea>
	</div>

	<div class="box">
		<h2>output: <button class="js_output_to_input">move output to input</button></h2>
		<textarea id="ta2"></textarea>
	</div>

	<div class="box">
		<h4>USAGE</h4>
		<div class="notes">
			put a regex with two capturing groups, and past text below.<br/>
			- Whatever matches the 2nd group will be aligned.<br>
			- What matches between the groups will be removed (usually: '\s*' to get rid of extra spaces).<br>
			- First group is just there to prevent matching on wrong things, you can leave it empty, or put something in there that needs to be right before 2nd group (and bit in between groups).<br>
			<br/>
			(internals: replaces all lines with a marker in between the two groups, then pads spaces just before the markers where needed and then removes the markers again)<br/>
			<br/>
			NB: does not work well with (mixed) tabs (yet).<br/>
		</div>
	</div>
	<hr>
	<div class="inlineblock box">
		<h4>RegEx sandboxes</h4>
		<a target="_blank" href="https://regex101.com/" >https://regex101.com/</a><br/>
		<a...

CSS

body{
	margin:0 0 0 0;
	padding:2px;
	font-size: 12px;
	background:#111;
	color:#888;
	line-height:1;
}

a{
	color:#88f;
}
a:visited{
	color:#c8f;
}
a:hover,
a:active{
	color:#ccf;
}

h1,h2,h3,h4,h5,h6{
	margin:1px 0;
}
textarea,
select,
input[type=text]{
	background:#888;
	color:#000;
	font-family: monospace;
	font-size: 12px;
	font-weight: normal;
	line-height:1;
	tab-space: 4;
}
#i1{
	width: 90%;
/* does not work as expected:
	resize: horizontal;
	overflow: auto;
*/
}
#ta1,
#ta2{
	display:block;
	box-sizing: border-box;
	width:100%;
	max-width:100%;
	resize: vertical;
	height:100px;
/* prevent wordwrap: */
	white-space: pre;
	word-wrap: normal;
	overflow: auto;
}
#ta1{}
#ta2{}

.notes{
	font-size:11px;
	color:#666;
}
.inlineblock{
	display:inline-block;
}
.box{
	border: 1px solid #444;
	margin:2px;
	padding:2px;
	vertical-align:top;
}
.examples {}
.examples .example {}
.examples .example:hover {
	background-color:#222;
}
.examples .example a {
	margin: 0px 2px;
	display: inline-block;
}

JavaScript

(function(window, $){
	// requires jQuery 2.1.1 (possibly also before or after, but I know it works with 2.1.1)

	function update(){
		var s,r,p,colbreakmark,cmax,line,lines,pos,d,addspacescnt;
		colbreakmark = '__COLBREAKMARK__'
		p = $('#i1').val();
		s = $('#ta1').val();
		r = new RegExp();
		try {
			r = new RegExp(p);
		}catch(e){
			$('#r').text(e);
			return;
		}
		
		// for all lines:
		//  count max characters before colbreakmark
		// for each line:
		//  pad all lines with spaces just before the colbreakmark so it has a total of that amount of characters before that colbreakmark
		
		cmax = -1;
		lines = s.split('\n');
		for(i=0;i<lines.length;i++){
			line=lines[i];
			line = line.replace(r, '$1'+colbreakmark+'$2');
			pos = line.indexOf(colbreakmark);
			if(pos>=0){
				cmax = Math.max(cmax, pos);
			}
			lines[i] = line;
		}
//		console.log(cmax);
		for(i=0;i<lines.length;i++){
			line = lines[i];
			pos = line.indexOf(colbreakmark);
			d = cmax - pos;
//			console.log(i,pos,d,line);
			if(pos >= 0){
				// if cmax already is first character (pos==0), then do not add extra space:
				addspacescnt = cmax == 0 ? d : d+1;
				line = line.substr(0,pos) + ' '.repeat(addspacescnt) + line.substr(pos);
//				console.log(line);
			}
			lines[i] = line;
		}
		s = lines.join('\n');
		s = s.replace(new RegExp(colbreakmark, 'g'), '');
		
		$('#r').text(r);
		$('#ta2').val(s);
	}

	// http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript/3561711#3561711
	var RegExpEscape_pattern =/ [-\/\\^$*+?.()|[\]{}]/g;
	function RegExpEscape(s){
		return s.replace(RegExpEscape_pattern, '\\$&');
	}
/*
	if(!String.prototype.repeat){
		String.prototype.repeat = function(count) {
			// source http://jsfiddle.net/disfated/gejwv/
			if (count < 1) return '';
			var result = '', pattern = this.valueOf();
			while (count > 1) {
				if (count & 1){result += pattern;}
				count >>= 1, pattern += pattern;
			}
			return result + pattern;
		}
	}
*/
	//...