The stuffs that I added to SHJS are:
1. Line numbers (based on SHJS-Linenumbers from https://github.com/F1skr/SHJS-Linenumbers/blob/master/src/sh_main.js)
2. 'Select All' option: Click the option, and the code gets selected. This is so you can copy-paste code quickly :)
3. Word highlighting: Click on a word in the code, and all occurances of the word are highlighted.
4. Brace highlighting: Click on a brace and it's matching brace get highlighted. 'Braces' include curly braces {}, square brackets [] and parenthesis ().
Check the source code of this file for explaination on how to use SHJS-Extended on your site.
/**
* @description Finds all occurances of a word in a pre element and marks/highlights them (using a span element and defined CSS class).
* @param {HTMLPreElement} element
* @param {String} word Word to find
* @param {Boolean} [wholeWord] Optional: When true, matches only whole words. Defaults to true.
*/
function shx_hilitWord(element,word,wholeWord) {
if(!wholeWord) wholeWord=true;
var _nextNode = function(_node) {
return _node.firstChild || _node.nextSibling || (_node.parentNode!==element ? _node.parentNode.nextSibling : false);
}
//Step 0: Unhilit braces and join adjacent text nodes.
shx_unhilitBrace();
element.normalize();
/* Step 1: Get all text nodes and their node value length.
* This is an optimization, rather than traversing the DOM multiple times.
* Also get all text from 'element' node.
*/
var textNodes=[], nodePos=[], text='',len=0;
//Iterate through child nodes
for(var node=element.firstChild; node; node=_nextNode(node) ) {
if(node.nodeType==3) {//Text node
//Remove hilit if hilit'ed
if(_hasClass(node.parentNode,'shx-hilit')) {
var parent=node.parentNode;
parent.parentNode.replaceChild(node,parent);
}
textNodes.push(node);
nodePos.push(len);
text+=node.nodeValue;
len+=node.nodeValue.length;
}
}
nodePos.push(len); //To make calculations easier at step 3.
/*Step 2: Get word match positions*/
var matchPos=[];
len=word.length;
for(var pos=text.indexOf(word); pos!=-1; pos=text.indexOf(word,pos+len)) {
// Match whole words only. Check if character before and after the match is not one of the 'variable name' characters.
if(wholeWord) {
var ok = ((pos-1)<0 || ((pos-1)>=0 && !_isVarNameChar(text[pos-1])));
if(ok && ((pos+len)>=text.length || ((pos+len)<text.length && !_isVarNameChar(text[pos+len]))) ) {
matchPos.push(pos);
}
} else {
matchPos.push(pos); //Not tested so far
}
}
//Private function
var _hilit=function(_node) {
var span=document.createElement('span');
span.setAttribute('class','shx-hilit');
span.setAttribute('title','Count : '+matchPos.length);
_node.parentNode.replaceChild(span,_node);
span.appendChild(_node);
}
/*Step 3: Highlight the text nodes*/
var matchIndex=0, startNode=false, pos=matchPos[matchIndex], newNode;
var hilitQueue=[];
for(var i=0;i<textNodes.length;i++) {
if(pos>=nodePos[i] && pos<nodePos[i+1]) {
startNode=!startNode;
//Split text node if required
var diff=pos-nodePos[i];
if(diff!=0 && diff!=textNodes[i].nodeValue.length) {
newNode=textNodes[i].splitText(diff);
textNodes.splice(i+1,0,newNode);
nodePos.splice(i+1,0,pos);
} else {
newNode=textNodes[i];
i--; //No split has taken place. So make sure we goes through the current i value once again.
}
if(startNode) {
hilitQueue.push(newNode);
}
else {
if(diff!=0 && textNodes[i]!=hilitQueue[hilitQueue.length-1]) {
hilitQueue.push(textNodes[i]);
}
for(var k=0; k<hilitQueue.length; k++) {
_hilit(hilitQueue[k]);
}
hilitQueue=[];
}
pos = startNode? (matchPos[matchIndex]+len) : matchPos[++matchIndex];
} else if(startNode && textNodes[i]!=hilitQueue[hilitQueue.length-1]) {
hilitQueue.push(textNodes[i]);
}
}
//Join adjacent textnodes
element.normalize();
}
/**
* "Enter the Matrix" ASCII Animation with C++ and Windows API
*/
#include <iostream>
#include <ctime>
#include <map>
#include <windows.h>
using namespace std;
int random(int num)
{
return rand()%num;
}
void writeCharAt(int x,int y, char charToWrite) {
if(x<0 || y<0 || x>=80 || y>=50)
return;
char character[1];
character[0]=charToWrite;
DWORD charsWritten=0;
while(charsWritten!=1)
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), character, 1, COORD {static_cast<short>(x),static_cast<short>(y)}, &charsWritten);
}
void setCellColor(int x, int y, WORD color) {
if(x<0 || y<0 || x>=80 || y>=50)
return;
WORD attr[1];
attr[0]=color;
DWORD charsWritten=0;
while(charsWritten!=1 && !WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attr, 1, COORD {static_cast<short>(x),static_cast<short>(y)}, &charsWritten));
}
bool listenForKeyStroke() {
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD InRec;
DWORD NumRead;
PeekConsoleInput(hIn,&InRec,1,&NumRead);
if(NumRead==1)
ReadConsoleInput(hIn,&InRec,1,&NumRead);
return InRec.EventType!=KEY_EVENT;
}
class AnimThread {
public:
short int x,y,speed,length, head_color;
bool initialized;
static map<int,bool> positions;
static UINT frame;
bool initialize() {
if(random(3)==0) {
initialized=true;
do {
x=random(80);
}while(positions[x]);
positions[x]=true;
speed=random(3)+1, length=random(20)+5;
y=(-1*length)-random(80);
head_color=random(2);
return true;
}
return false;
}
AnimThread() {
initialized=false;
initialize();
}
bool runOnce() {
if(!initialized)
initialize();
if(y>=50) {
positions[x]=false;
initialized=false;
}
if(initialized) {
if(frame%speed!=0)
return true;
setCellColor(x,y+length-2, FOREGROUND_GREEN);
setCellColor(x, y+length-1, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
writeCharAt(x,y+length,random(256));
if(head_color==0)
setCellColor(x, y+length, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
else
setCellColor(x, y+length, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
writeCharAt(x,y,' ');
y++;
return true;
}
return false;
}
static void nextFrame() {
frame++;
if(frame==1000)
frame=0;
}
};
map<int,bool> AnimThread::positions;
UINT AnimThread::frame=1;
int main()
{
//80x50 console screen
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT sr={0,0,79,49};
SetConsoleWindowInfo(hOut,true,&sr);
SetConsoleScreenBufferSize(hOut,(COORD){80,50});
srand(time(NULL));
AnimThread test[50];
while(listenForKeyStroke()) {
for(int i=0;i<50;i++)
test[i].runOnce();
Sleep(5);
AnimThread::nextFrame();
}
return 0;
}