Created
November 27, 2011 19:20
-
-
Save mmalecki/1398015 to your computer and use it in GitHub Desktop.
My finite state machine for parsing ANSI codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ansispan = function (str) { | |
} | |
ansispan.parse = function (str) { | |
// | |
// I'm terrible at writing parsers. | |
// | |
var matchingControl = null, | |
matchingData = null, | |
matchingText = null, | |
ansiState = [], | |
result = [], | |
state = {}; | |
// | |
// General workflow for this thing is: | |
// \033\[33mText | |
// | | | | |
// | | matchingText | |
// | matchingData | |
// matchingControl | |
// | |
// In further steps we hope it's all going to be fine. It usually is. | |
// | |
for (var i = 0; i < str.length; i++) { | |
if (matchingControl != null) { | |
if (matchingControl == '\033' && str[i] == '\[') { | |
// | |
// We've matched full control code. Lets start matching formating data. | |
// | |
matchingControl = null; | |
matchingData = ''; | |
} | |
else { | |
// | |
// We failed to match anything - most likely a bad control code. We | |
// go back to matching regular strings. | |
// | |
matchingControl = null; | |
} | |
continue; | |
} | |
else if (matchingData != null) { | |
if (str[i] == ';') { | |
ansiState.push(matchingData); | |
matchingData = ''; | |
} | |
else if (str[i] == 'm') { | |
ansiState.push(matchingData); | |
matchingData = null; | |
matchingText = ''; | |
// | |
// Convert matched formatting data into user-friendly state object | |
// | |
ansiState.forEach(function (ansiCode) { | |
if ((30 <= ansiCode) && (ansiCode <= 37)) { | |
state.foreground = ansiCode; | |
} | |
else if ((40 <= ansiCode) && (ansiCode <= 47)) { | |
state.background = ansiCode; | |
} | |
else if (ansiCode == 39) { | |
delete state.foreground; | |
} | |
else if (ansiCode == 49) { | |
delete state.background; | |
} | |
else if (ansiCode == 1) { | |
state.bold = true; | |
} | |
else if (ansiCode == 3) { | |
state.italic = true; | |
} | |
else if (ansiCode == 4) { | |
state.underline = true; | |
} | |
else if (ansiCode == 22) { | |
state.bold = false; | |
} | |
else if (ansiCode == 23) { | |
state.italic = false; | |
} | |
else if (ansiCode == 24) { | |
state.underline = false; | |
} | |
}); | |
} | |
else { | |
matchingData += str[i]; | |
} | |
continue; | |
} | |
if (str[i] == '\033') { | |
matchingControl = str[i]; | |
// | |
// "emit" matched text with correct state | |
// | |
if (matchingText) { | |
state.text = matchingText; | |
result.push(state); | |
state = {}; | |
} | |
} | |
else { | |
matchingText += str[i]; | |
} | |
} | |
return result; | |
} | |
ansispan.foregroundColors = { | |
'30': 'black', | |
'31': 'red', | |
'32': 'green', | |
'33': 'yellow', | |
'35': 'purple', | |
'36': 'cyan', | |
'37': 'white' | |
}; | |
ansispan.backgroundColors = { | |
'40': 'black', | |
'41': 'red', | |
'42': 'green', | |
'43': 'yellow', | |
'45': 'purple', | |
'46': 'cyan', | |
'47': 'white' | |
}; | |
ansispan.styles = { | |
'1': 'bold', | |
'3': 'italics', | |
'4': 'underline' | |
}; | |
if (typeof module == "object" && typeof window == "undefined") { | |
module.exports = ansispan; | |
} | |
require('colors'); | |
console.dir(ansispan.parse('red'.red + ' normal ' + 'blue'.blue)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment