@ -1,203 +1,563 @@
( function ( exports ) { // http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings
/ * *
* WeeChat protocol handling .
*
* This object parses messages and formats commands for the WeeChat
* protocol . It ' s independent from the communication layer and thus
* may be used with any network mechanism .
* /
( function ( ) {
// http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings
var part , fg , bg , attrs ;
// XTerm 8-bit pallete
var colors = [
'#666666' , '#AA0000' , '#00AA00' , '#AA5500' , '#0000AA' ,
'#AA00AA' , '#00AAAA' , '#AAAAAA' , '#555555' , '#FF5555' ,
'#55FF55' , '#FFFF55' , '#5555FF' , '#FF55FF' , '#55FFFF' ,
'#FFFFFF' , '#666666' , '#00005F' , '#000087' , '#0000AF' ,
'#0000D7' , '#0000FF' , '#005F00' , '#005F5F' , '#005F87' ,
'#005FAF' , '#005FD7' , '#005FFF' , '#008700' , '#00875F' ,
'#008787' , '#0087AF' , '#0087D7' , '#00AF00' , '#00AF5F' ,
'#00AF87' , '#00AFAF' , '#00AFD7' , '#00AFFF' , '#00D700' ,
'#00D75F' , '#00D787' , '#00D7AF' , '#00D7D7' , '#00D7FF' ,
'#00FF00' , '#00FF5F' , '#00FF87' , '#00FFAF' , '#00FFD7' ,
'#00FFFF' , '#5F0000' , '#5F005F' , '#5F0087' , '#5F00AF' ,
'#5F00D7' , '#5F00FF' , '#5F5F00' , '#5F5F5F' , '#5F5F87' ,
'#5F5FAF' , '#5F5FD7' , '#5F5FFF' , '#5F8700' , '#5F875F' ,
'#5F8787' , '#5F87AF' , '#5F87D7' , '#5F87FF' , '#5FAF00' ,
'#5FAF5F' , '#5FAF87' , '#5FAFAF' , '#5FAFD7' , '#5FAFFF' ,
'#5FD700' , '#5FD75F' , '#5FD787' , '#5FD7AF' , '#5FD7D7' ,
'#5FD7FF' , '#5FFF00' , '#5FFF5F' , '#5FFF87' , '#5FFFAF' ,
'#5FFFD7' , '#5FFFFF' , '#870000' , '#87005F' , '#870087' ,
'#8700AF' , '#8700D7' , '#8700FF' , '#875F00' , '#875F5F' ,
'#875F87' , '#875FAF' , '#875FD7' , '#875FFF' , '#878700' ,
'#87875F' , '#878787' , '#8787AF' , '#8787D7' , '#8787FF' ,
'#87AF00' , '#87AF5F' , '#87AF87' , '#87AFAF' , '#87AFD7' ,
'#87AFFF' , '#87D700' , '#87D75F' , '#87D787' , '#87D7AF' ,
'#87D7D7' , '#87D7FF' , '#87FF00' , '#87FF5F' , '#87FF87' ,
'#87FFAF' , '#87FFD7' , '#87FFFF' , '#AF0000' , '#AF005F' ,
'#AF0087' , '#AF00AF' , '#AF00D7' , '#AF00FF' , '#AF5F00' ,
'#AF5F5F' , '#AF5F87' , '#AF5FAF' , '#AF5FD7' , '#AF5FFF' ,
'#AF8700' , '#AF875F' , '#AF8787' , '#AF87AF' , '#AF87D7' ,
'#AF87FF' , '#AFAF00' , '#AFAF5F' , '#AFAF87' , '#AFAFAF' ,
'#AFAFD7' , '#AFAFFF' , '#AFD700' , '#AFD75F' , '#AFD787' ,
'#AFD7AF' , '#AFD7D7' , '#AFD7FF' , '#AFFF00' , '#AFFF5F' ,
'#AFFF87' , '#AFFFAF' , '#AFFFD7' , '#AFFFFF' , '#D70000' ,
'#D7005F' , '#D70087' , '#D700AF' , '#D700D7' , '#D700FF' ,
'#D75F00' , '#D75F5F' , '#D75F87' , '#D75FAF' , '#D75FD7' ,
'#D75FFF' , '#D78700' , '#D7875F' , '#D78787' , '#D787AF' ,
'#D787D7' , '#D787FF' , '#D7AF00' , '#D7AF5F' , '#D7AF87' ,
'#D7AFAF' , '#D7AFD7' , '#D7AFFF' , '#D7D700' , '#D7D75F' ,
'#D7D787' , '#D7D7AF' , '#D7D7D7' , '#D7D7FF' , '#D7FF00' ,
'#D7FF5F' , '#D7FF87' , '#D7FFAF' , '#D7FFD7' , '#D7FFFF' ,
'#FF0000' , '#FF005F' , '#FF0087' , '#FF00AF' , '#FF00D7' ,
'#FF00FF' , '#FF5F00' , '#FF5F5F' , '#FF5F87' , '#FF5FAF' ,
'#FF5FD7' , '#FF5FFF' , '#FF8700' , '#FF875F' , '#FF8787' ,
'#FF87AF' , '#FF87D7' , '#FF87FF' , '#FFAF00' , '#FFAF5F' ,
'#FFAF87' , '#FFAFAF' , '#FFAFD7' , '#FFAFFF' , '#FFD700' ,
'#FFD75F' , '#FFD787' , '#FFD7AF' , '#FFD7D7' , '#FFD7FF' ,
'#FFFF00' , '#FFFF5F' , '#FFFF87' , '#FFFFAF' , '#FFFFD7' ,
'#FFFFFF' , '#080808' , '#121212' , '#1C1C1C' , '#262626' ,
'#303030' , '#3A3A3A' , '#444444' , '#4E4E4E' , '#585858' ,
'#626262' , '#6C6C6C' , '#767676' , '#808080' , '#8A8A8A' ,
'#949494' , '#9E9E9E' , '#A8A8A8' , '#B2B2B2' , '#BCBCBC' ,
'#C6C6C6' , '#D0D0D0' , '#DADADA' , '#E4E4E4' , '#EEEEEE'
var WeeChatProtocol = function ( ) {
// specific parsing for each object type
this . _types = {
'chr' : this . _getChar ,
'int' : this . _getInt ,
'str' : this . _getString ,
'inf' : this . _getInfo ,
'hda' : this . _getHdata ,
'ptr' : this . _getPointer ,
'lon' : this . _getStrNumber ,
'tim' : this . _getTime ,
'buf' : this . _getString ,
'arr' : this . _getArray ,
'htb' : this . _getHashTable ,
'inl' : function ( ) {
this . _warnUnimplemented ( 'infolist' ) ;
}
} ;
// string value for some object types
this . _typesStr = {
'chr' : this . _strDirect ,
'str' : this . _strDirect ,
'int' : this . _strToString ,
'tim' : this . _strToString ,
'ptr' : this . _strDirect
} ;
} ;
/ * *
* WeeChat colors names .
* /
WeeChatProtocol . _weeChatColorsNames = [
'default' ,
'black' ,
'darkgray' ,
'darkred' ,
'lightred' ,
'darkgreen' ,
'lightgreen' ,
'brown' ,
'yellow' ,
'darkblue' ,
'lightblue' ,
'darkmagenta' ,
'lightmagenta' ,
'darkcyan' ,
'lightcyan' ,
'gray' ,
'white'
] ;
/ * *
* Style options names .
* /
WeeChatProtocol . _colorsOptionsNames = [
'separator' ,
'chat' ,
'chat_time' ,
'chat_time_delimiters' ,
'chat_prefix_error' ,
'chat_prefix_network' ,
'chat_prefix_action' ,
'chat_prefix_join' ,
'chat_prefix_quit' ,
'chat_prefix_more' ,
'chat_prefix_suffix' ,
'chat_buffer' ,
'chat_server' ,
'chat_channel' ,
'chat_nick' ,
'chat_nick_self' ,
'chat_nick_other' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'invalid' ,
'chat_host' ,
'chat_delimiters' ,
'chat_highlight' ,
'chat_read_marker' ,
'chat_text_found' ,
'chat_value' ,
'chat_prefix_buffer' ,
'chat_tags' ,
'chat_inactive_window' ,
'chat_inactive_buffer' ,
'chat_prefix_buffer_inactive_buffer' ,
'chat_nick_offline' ,
'chat_nick_offline_highlight' ,
'chat_nick_prefix' ,
'chat_nick_suffix' ,
'emphasis' ,
'chat_day_change'
] ;
// Push the basic color list on top of the extended color list
// and then when weechat requests a basic color (0-15) we rewrite
// it to be a number in the extended color table
colors . push . apply ( colors , [ '' , 'black' , 'darkgray' , 'darkred' , 'red' , 'darkgreen' , 'lightgreen' , 'brown' ,
'yellow' , 'darkblue' , 'lightblue' , 'darkmagenta' , 'magenta' , 'darkcyan' , 'lightcyan' , 'gray' , 'white'
] ) ;
/ * *
* Gets the default color .
*
* @ return Default color
* /
WeeChatProtocol . _getDefaultColor = function ( ) {
return {
type : 'weechat' ,
name : 'default'
} ;
}
function setAttrs ( ) {
while ( part . match ( /^[\*\/\_\|]/ ) ) {
attrs . push ( part . charAt ( 0 ) ) ;
part = part . slice ( 1 ) ;
/ * *
* Gets the default attributes .
*
* @ return Default attributes
* /
WeeChatProtocol . _getDefaultAttributes = function ( ) {
return {
name : null ,
override : {
'bold' : false ,
'reverse' : false ,
'italic' : false ,
'underline' : false
}
} ;
}
function getColor ( ) {
var c ;
if ( part . match ( /^@/ ) ) {
c = part . slice ( 1 , 6 ) ;
part = part . slice ( 6 ) ;
/ * *
* Gets the default style ( default colors and attributes ) .
*
* @ return Default style
* /
WeeChatProtocol . _getDefaultStyle = function ( ) {
return {
fgColor : WeeChatProtocol . _getDefaultColor ( ) ,
bgColor : WeeChatProtocol . _getDefaultColor ( ) ,
attrs : WeeChatProtocol . _getDefaultAttributes ( )
} ;
}
/ * *
* Clones a color object .
*
* @ param color Color object to clone
* @ return Cloned color object
* /
WeeChatProtocol . _cloneColor = function ( color ) {
var clone = { } ;
for ( var key in color ) {
clone [ key ] = color [ key ] ;
}
return clone ;
}
/ * *
* Clones an attributes object .
*
* @ param attrs Attributes object to clone
* @ return Cloned attributes object
* /
WeeChatProtocol . _cloneAttrs = function ( attrs ) {
var clone = { } ;
clone . name = attrs . name ;
clone . override = { } ;
for ( var attr in attrs . override ) {
clone . override [ attr ] = attrs . override [ attr ] ;
}
return clone ;
}
/ * *
* Gets the name of an attribute from its character .
*
* @ param ch Character of attribute
* @ return Name of attribute
* /
WeeChatProtocol . _attrNameFromChar = function ( ch ) {
var chars = {
'*' : 'bold' ,
'!' : 'reverse' ,
'/' : 'italic' ,
'_' : 'underline'
} ;
if ( ch in chars ) {
return chars [ ch ] ;
}
return null ;
}
/ * *
* Gets an attributes object from a string of attribute characters .
*
* @ param str String of attribute characters
* @ return Attributes object ( null if unchanged )
* /
WeeChatProtocol . _attrsFromStr = function ( str ) {
var attrs = WeeChatProtocol . _getDefaultAttributes ( ) ;
for ( var i = 0 ; i < str . length ; ++ i ) {
var ch = str . charAt ( i ) ;
if ( ch == '|' ) {
// means keep attributes, so unchanged
return null ;
}
var attrName = WeeChatProtocol . _attrNameFromChar ( ch ) ;
if ( attrName === null ) {
// ignore invalid attribute
continue ;
}
attrs . override [ attrName ] = true ;
}
return attrs ;
}
/ * *
* Gets a single color from a string representing its index ( WeeChat and
* extended colors only , NOT colors options ) .
*
* @ param str Color string ( e . g . , "05" or "00134" )
* @ return Color object
* /
WeeChatProtocol . _getColorObj = function ( str ) {
if ( str . length == 2 ) {
var code = parseInt ( str ) ;
if ( code > 16 ) {
// should never happen
return WeeChatProtocol . _getDefaultColor ( ) ;
} else {
c = part . slice ( 0 , 2 ) ;
// Rewrite the basic color value to the part in the extended
// palette where we store the basic colors
c = parseInt ( c , 10 ) + 255 ;
part = part . slice ( 2 ) ;
return {
type : 'weechat' ,
name : WeeChatProtocol . _weeChatColorsNames [ code ]
} ;
}
} else {
var codeStr = str . substring ( 1 ) ;
return {
type : 'ext' ,
name : parseInt ( codeStr ) . toString ( )
} ;
}
return c ;
}
function prepareCss ( color ) {
/ *
* Translates a weechat color to CSS
/ * *
* Gets colors and attributes of text element .
*
* See < http : //www.weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings>.
*
* @ param txt Text element
* @ return Colors , attributes and plain text of this text element :
* fgColor : Foreground color ( null if unchanged )
* bgColor : Background color ( null if unchanged )
* attrs : Attributes ( null if unchanged )
* text : Plain text element
* /
return 'color: ' + color ;
WeeChatProtocol . _getStyle = function ( txt ) {
var matchers = [
{
// color option
// STD
regex : /^(\d{2})/ ,
fn : function ( m ) {
var ret = { } ;
var optionCode = parseInt ( m [ 1 ] ) ;
if ( optionCode > 43 ) {
// should never happen
return {
fgColor : null ,
bgColor : null ,
attrs : null
} ;
}
var optionName = WeeChatProtocol . _colorsOptionsNames [ optionCode ] ;
ret . fgColor = {
type : 'option' ,
name : optionName
} ;
ret . bgColor = WeeChatProtocol . _cloneColor ( ret . fgColor ) ;
ret . attrs = {
name : optionName ,
override : { }
} ;
return ret ;
}
} ,
{
// ncurses pair
// EXT
regex : /^@(\d{5})/ ,
fn : function ( m ) {
// unimplemented case
return {
fgColor : null ,
bgColor : null ,
attrs : null
} ;
}
} ,
{
// foreground color with F
// "F" + (A)STD
// "F" + (A)EXT
regex : /^F(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5}))/ ,
fn : function ( m ) {
var ret = {
bgColor : null
} ;
var prefixes = {
'\x19' : function ( ) {
if ( part . match ( /^F/ ) ) {
part = part . slice ( 1 ) ;
setAttrs ( ) ;
fg = getColor ( ) ;
} else if ( part . match ( /^B/ ) ) {
part = part . slice ( 1 ) ;
setAttrs ( ) ;
bg = getColor ( ) ;
if ( m [ 2 ] ) {
ret . attrs = WeeChatProtocol . _attrsFromStr ( m [ 1 ] ) ;
ret . fgColor = WeeChatProtocol . _getColorObj ( m [ 2 ] ) ;
} else {
setAttrs ( ) ;
fg = getColor ( ) ;
if ( part . match ( /^,/ ) ) {
part = part . slice ( 1 ) ;
bg = getColor ( ) ;
ret . attrs = WeeChatProtocol . _attrsFromStr ( m [ 3 ] ) ;
ret . fgColor = WeeChatProtocol . _getColorObj ( m [ 4 ] ) ;
}
return ret ;
}
} ,
'\x1A' : function ( ) {
// Don't know what to do
{
// background color (no attributes)
// "B" + STD
// "B" + EXT
regex : /^B(\d{2}|@\d{5})/ ,
fn : function ( m ) {
return {
fgColor : null ,
bgColor : WeeChatProtocol . _getColorObj ( m [ 1 ] ) ,
attrs : null
} ;
}
} ,
'\x1B' : function ( ) {
attrs = [ ] ;
{
// foreground, background (+ attributes)
// "*" + (A)STD + "," + STD
// "*" + (A)STD + "," + EXT
// "*" + (A)EXT + "," + STD
// "*" + (A)EXT + "," + EXT
regex : /^\*(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5})),(\d{2}|@\d{5})/ ,
fn : function ( m ) {
var ret = { } ;
if ( m [ 2 ] ) {
ret . attrs = WeeChatProtocol . _attrsFromStr ( m [ 1 ] ) ;
ret . fgColor = WeeChatProtocol . _getColorObj ( m [ 2 ] ) ;
} else {
ret . attrs = WeeChatProtocol . _attrsFromStr ( m [ 3 ] ) ;
ret . fgColor = WeeChatProtocol . _getColorObj ( m [ 4 ] ) ;
}
ret . bgColor = WeeChatProtocol . _getColorObj ( m [ 5 ] ) ;
return ret ;
}
} ,
'\x1C' : function ( ) {
fg = '' ;
bg = '' ;
{
// foreground color with * (+ attributes) (fall back, must be checked before previous case)
// "*" + (A)STD
// "*" + (A)EXT
regex : /^\*([*!\/_|]*)(\d{2}|@\d{5})/ ,
fn : function ( m ) {
return {
fgColor : WeeChatProtocol . _getColorObj ( m [ 2 ] ) ,
bgColor : null ,
attrs : WeeChatProtocol . _attrsFromStr ( m [ 1 ] )
} ;
}
} ,
{
// emphasis
// "E"
regex : /^E/ ,
fn : function ( m ) {
var ret = { } ;
ret . fgColor = {
type : 'option' ,
name : 'emphasis'
} ;
ret . bgColor = WeeChatProtocol . _cloneColor ( ret . fgColor ) ;
ret . attrs = {
name : 'emphasis' ,
override : { }
} ;
function parse ( text ) {
if ( ! text ) {
return text ;
return ret ;
}
var f , parts = text . split ( /(\x19|\x1A|\x1B|\x1C)/ ) ;
if ( parts . length === 1 ) return [ {
text : parts [ 0 ]
} ] ;
attrs = [ ] ;
}
] ;
return parts . map ( function ( p ) {
var res , tmp = prefixes [ p . charAt ( 0 ) ] ;
if ( f ) {
part = p ;
f ( ) ;
res = {
text : part ,
fg : colors [ parseInt ( fg , 10 ) ] ,
bg : colors [ parseInt ( bg , 10 ) ] ,
attrs : attrs
} ;
if ( ! res . fg ) res . fg = fg ;
if ( ! res . bg ) res . bg = bg ;
}
f = tmp ;
return res ;
} ) . filter ( function ( p ) {
return p ;
// parse
var ret = {
fgColor : null ,
bgColor : null ,
attrs : null ,
text : txt
} ;
matchers . some ( function ( matcher ) {
var m = txt . match ( matcher . regex ) ;
if ( m ) {
ret = matcher . fn ( m ) ;
ret . text = txt . substring ( m [ 0 ] . length ) ;
return true ;
}
return false ;
} ) ;
return ret ;
}
exports . color = {
prepareCss : prepareCss ,
parse : parse
} ;
} ) ( ) ;
; / * *
* WeeChat protocol handling .
/ * *
* Transforms a raw text into an array of text elements with integrated
* colors and attributes .
*
* This object parses messages and formats commands for the WeeChat
* protocol . It ' s independent from the communication layer and thus
* may be used with any network mechanism .
* @ param rawText Raw text to transform
* @ return Array of text elements
* /
WeeChatProtocol . rawText2Rich = function ( rawText ) {
/ * T h i s i s s u b t l e , b u t J a v a S c r i p t a d d s t h e t o k e n t o t h e o u t p u t l i s t
* when it ' s surrounded by capturing parentheses .
* /
var parts = rawText . split ( /(\x19|\x1a|\x1b|\x1c)/ ) ;
// no colors/attributes
if ( parts . length == 1 ) {
return [
{
attrs : WeeChatProtocol . _getDefaultAttributes ( ) ,
fgColor : WeeChatProtocol . _getDefaultColor ( ) ,
bgColor : WeeChatProtocol . _getDefaultColor ( ) ,
text : parts [ 0 ]
}
] ;
}
( function ( ) {
var WeeChatProtocol = function ( ) {
// specific parsing for each message type
this . _types = {
'chr' : this . _getChar ,
'int' : this . _getInt ,
'str' : this . _getString ,
'inf' : this . _getInfo ,
'hda' : this . _getHdata ,
'ptr' : this . _getPointer ,
'lon' : this . _getStrNumber ,
'tim' : this . _getTime ,
'buf' : this . _getString ,
'arr' : this . _getArray ,
'htb' : this . _getHashTable ,
'inl' : function ( ) {
this . _warnUnimplemented ( 'infolist' ) ;
// find the style of every part
var curFgColor = WeeChatProtocol . _getDefaultColor ( ) ;
var curBgColor = WeeChatProtocol . _getDefaultColor ( ) ;
var curAttrs = WeeChatProtocol . _getDefaultAttributes ( ) ;
var curSpecialToken = null ;
var curAttrsOnlyFalseOverrides = true ;
return parts . map ( function ( p ) {
if ( p . length == 0 ) {
return null ;
}
var firstCharCode = p . charCodeAt ( 0 ) ;
var firstChar = p . charAt ( 0 ) ;
if ( firstCharCode >= 0x19 && firstCharCode <= 0x1c ) {
// special token
if ( firstCharCode == 0x1c ) {
// always reset colors
curFgColor = WeeChatProtocol . _getDefaultColor ( ) ;
curBgColor = WeeChatProtocol . _getDefaultColor ( ) ;
if ( curSpecialToken != 0x19 ) {
// also reset attributes
curAttrs = WeeChatProtocol . _getDefaultAttributes ( ) ;
}
}
curSpecialToken = firstCharCode ;
return null ;
}
} ;
// string value for some message types
this . _typesStr = {
'chr' : this . _strDirect ,
'str' : this . _strDirect ,
'int' : this . _strToString ,
'tim' : this . _strToString ,
'ptr' : this . _strDirect
var text = p ;
if ( curSpecialToken == 0x19 ) {
// get new style
var style = WeeChatProtocol . _getStyle ( p ) ;
// set foreground color if changed
if ( style . fgColor !== null ) {
curFgColor = style . fgColor ;
}
// set background color if changed
if ( style . bgColor !== null ) {
curBgColor = style . bgColor ;
}
// set attibutes if changed
if ( style . attrs !== null ) {
curAttrs = style . attrs ;
}
// set plain text
text = style . text ;
} else if ( curSpecialToken == 0x1a || curSpecialToken == 0x1b ) {
// set/reset attribute
var orideVal = ( curSpecialToken == 0x1a ) ;
// set attribute override if we don't have to keep all of them
if ( firstChar != '|' ) {
var orideName = WeeChatProtocol . _attrNameFromChar ( firstChar ) ;
if ( orideName ) {
// known attribute
curAttrs . override [ orideName ] = orideVal ;
text = p . substring ( 1 ) ;
}
}
}
// reset current special token
curSpecialToken = null ;
// if text is empty, don't bother returning it
if ( text . length == 0 ) {
return null ;
}
/ * A s l o n g a s a t t r i b u t e s a r e o n l y f a l s e o v e r r i d e s , w i t h o u t a n y o p t i o n
* name , it ' s safe to remove them .
* /
if ( curAttrsOnlyFalseOverrides && curAttrs . name === null ) {
var allReset = true ;
for ( var attr in curAttrs . override ) {
if ( curAttrs . override [ attr ] ) {
allReset = false ;
break ;
}
}
if ( allReset ) {
curAttrs . override = { } ;
} else {
curAttrsOnlyFalseOverrides = false ;
}
}
// parsed text element
return {
fgColor : WeeChatProtocol . _cloneColor ( curFgColor ) ,
bgColor : WeeChatProtocol . _cloneColor ( curBgColor ) ,
attrs : WeeChatProtocol . _cloneAttrs ( curAttrs ) ,
text : text
} ;
} ) . filter ( function ( p ) {
return p !== null ;
} ) ;
} ;
/ * *
@ -800,7 +1160,7 @@
* @ param data Message data ( ArrayBuffer )
* @ return Message value
* /
parse : function ( data ) {
parse : function ( data , optionsValues ) {
var self = this ;
this . _setData ( data ) ;
@ -815,12 +1175,13 @@
objects . push ( object ) ;
object = self . _getObject ( ) ;
}
return {
var msg = {
header : header ,
id : id ,
objects : objects ,
} ;
return msg ;
}
} ;