|
|
|
@ -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' |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Gets the default attributes. |
|
|
|
|
* |
|
|
|
|
* @return Default attributes |
|
|
|
|
*/ |
|
|
|
|
WeeChatProtocol._getDefaultAttributes = function() { |
|
|
|
|
return { |
|
|
|
|
name: null, |
|
|
|
|
override: { |
|
|
|
|
'bold': false, |
|
|
|
|
'reverse': false, |
|
|
|
|
'italic': false, |
|
|
|
|
'underline': false |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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 = {}; |
|
|
|
|
|
|
|
|
|
function setAttrs() { |
|
|
|
|
while (part.match(/^[\*\/\_\|]/)) { |
|
|
|
|
attrs.push(part.charAt(0)); |
|
|
|
|
part = part.slice(1); |
|
|
|
|
for (var key in color) { |
|
|
|
|
clone[key] = color[key]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return clone; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getColor() { |
|
|
|
|
var c; |
|
|
|
|
if (part.match(/^@/)) { |
|
|
|
|
c = part.slice(1, 6); |
|
|
|
|
part = part.slice(6); |
|
|
|
|
/** |
|
|
|
|
* 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) { |
|
|
|
|
/* This is subtle, but JavaScript adds the token to the output list |
|
|
|
|
* 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* As long as attributes are only false overrides, without any option |
|
|
|
|
* 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; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|