mIRC syntax highlighting (javascript - highlight.js)


#1

WIP - Work in progress

See: https://github.com/isagalaev/highlight.js/issues/704

/*
Language: mIRC
Category: scripting
*/
function(hljs) {
	var ALIAS = {
		className: 'subst',
		variants: [
			{
				begin: /^alias (-l )?.+ \{/,
				end: /\}/
			},
			{
				begin: /^alias (-l )?.+/,
				end: /\n/
			}
		]
	};
	var MENU = {
		className: 'subst',
		variants: [
			{
				begin: /^menu .+ \{/,
				end: /\}/
			}
		]
	};
	var MENU_SUBST1 = {
		className: 'subst',
		begin: /\./,
		end: /:/,
		returnEnd: true
	};
	var MENU_SUBST2 = {
		className: 'subst',
		begin: /:/,
		end: /\n/,
		returnBegin: true
	};
	var DIALOG = {
		className: 'subst',
		variants: [
			{
				begin: /^dialog .+ \{/,
				end: /\}/
			}
		]
	};
	var ON = {
		className: 'subst',
		variants: [
			{
				begin: /^(on|ctcp|raw).+\{/,
				end: /\}/
			},
			{
				begin: /^(on|ctcp|raw).+:/,
				end: /\n/
			}
		]
	};
	var CODE_BLOCK = {
		className: 'subst',
		begin: /\{/,
		end: /\}/
	};
	var PAREN_BLOCK = {
		className: 'subst',
		begin: /\(/,
		end: /\)/
	};
	var LITERAL = {
		className: 'literal',
		begin: /\$(null|false|true)/
	};
	var VARIABLES = {
		className: 'variable',
		begin: /\%:?[\w\.\-<>=]*/
	};
	var IDENTIFIERS = {
		className: 'built_in',
		begin: /\$+(\d+-?|\+|yes|xor|wrap|window|wildtokcs|wildtok|wildsite|width|wid|wavedir|vol|vnick|version|vcmdver|vcmdstat|vcmd|vc|var|v2|v1|utfencode|utfdecode|usermode|url|uptime|upper|unsafe|ulist|ulevel|trust|true|treebar|totp|topic|toolbar|token|titlebar|tips|tip|timezone|timestampfmt|timestamp|timer|timeout|time|ticks|tempfn|target|tanh|tan|sysdir|switchbar|submenu|style|stripped|strip|str|status|starting|sslversion|sslready|ssllibdll|ssldll|sslcertsha256|sslcertsha1|ssl|sreq|sqrt|speak|sound|sorttokcs|sorttok|sockname|sockerr|sockbr|sock|snotify|snicks|snick|sline|site|sinh|sin|signal|show|shortfn|sha512|sha384|sha256|sha1|sfile|servertarget|serverip|server|send|sdir|scriptline|scriptdir|script|scon|scid|samepath|round|rnick|right|rgb|result|reptokcs|reptok|replacexcs|replacex|replacecs|replace|remtokcs|remtok|removecs|remove|remote|regsubex|regsub|regmlex|regml|regex|regerrstr|regbr|readn|readini|read|rawmsg|rawbytes|rand|raddress|r|query|qt|puttok|protect|prop|prefix|poscs|pos|portfree|portable|pnick|play|pic|pi|passivedcc|parseutf|parsetype|parseline|parms|os|ord|or|opnick|onpoly|onlinetotal|onlineserver|online|ok|nvnick|numtok|numeric|null|notify|notags|not|noqt|nopnick|nopath|nofile|no|nickmode|nick|nhnick|newnick|network|naddress|msgtags|msgstamp|msfile|mp3dir|mp3|mouse|modespl|modelast|modefirst|mode|mnick|mknickfn|mklogfn|mkfn|mircini|mircexe|mircdir|mididir|mid|menutype|menucontext|menubar|menu|me|md5|matchtokcs|matchtok|matchkey|mask|maddress|ltimer|lower|longip|longfn|logstampfmt|logstamp|logdir|log10|log|lof|locked|lock|link|lines|line|lf|level|len|leftwinwid|leftwincid|leftwin|left|lactivewid|lactivecid|lactive|knick|keyval|keyrpt|keychar|isutf|isupper|istok|islower|isid|isfile|isdir|isdde|isbit|isalias|iql|iptype|ip|inwho|inwave|intersect|int|instok|insong|inroundrect|inrect|input|inpoly|inpaste|inmp3|inmode|inmidi|initopic|ini|inellipse|iil|ignore|ifmatch2|ifmatch|iif|iel|idle|ibl|ialchan|ial|iaddress|hypot|hregex|hotp|hotlink|hotlinepos|hotline|host|hnick|hmatch|hmac|highlight|hget|hfind|hfile|height|hash|halted|group|gmt|gettok|getdot|getdir|get|fullscreen|fullname|fulldate|fulladdress|fserve|fserv|fromeditbox|fread|fopen|font|floor|fline|findtokcs|findtok|findfilen|findfile|finddirn|finddir|filtered|filename|file|fgetc|ferr|feof|false|exiting|exists|eventid|event|evalnext|eval|error|envvar|encode|emailaddr|email|editbox|ebeeps|duration|dqwindow|dname|dllcall|dll|dlevel|disk|dir|didwm|didtok|didreg|did|dialog|devent|deltok|decompress|decode|debug|ddename|dde|dccport|dccignore|dbuw|dbuh|daylight|day|date|ctrlenter|ctimer|ctime|crlf|creq|crc|cr|count|cosh|cos|comval|compress|compact|comerr|comchar|comchan|comcall|com|colour|color|cnick|cmdline|cmdbox|click|clevel|cid|chr|chat|chantypes|chanmodes|chan|ceil|cd|cb|cancel|caller|calc|bytes|bvar|bnick|bits|biton|bitoff|bindip|bfind|beta|base|banmask|banlist|awaytime|awaymsg|away|avoice|auto|atan2|atan|asin|asctime|asc|appstate|appactive|aop|ansi2mirc|anick|and|alias|agentver|agentstat|agentname|agent|addtokcs|addtok|address|adate|activewid|activecid|active|acos|abs|abook)/,
	};
	var KEYWORDS = {
		className: 'keyword',
		begin: /( (!?\.?!?\/?)|:)(xyzzy|writeini|write|winhelp|window|whois|while|wavplay|wallchops|vol|vcrem|vcmd|vcadd|var|uwho|username|url|updatenl|unsetall|unset|unload|ulist|treebar|tray|toolbar|tokenize|tnick|titlebar|tips|tip|timestamp|timer[\w\-\.]*|switchbar|strip|sreq|splay|speak|sound|sockwrite|sockudp|sockrename|sockread|sockpause|sockopen|sockmark|socklisten|socklist|sockclose|sockaccept|sline|signal|showmirc|setlayer|set|server|scon|scid|say|saveini|savebuf|save|ruser|run|rmdir|rline|rlevel|returnex|return|resetidle|reseterror|renwin|rename|remove|remote|remini|reload|registration|raw|quote|quit|queryrn|query|qmsg|qme|pvoice|proxy|protect|pop|playctrl|play|perform|pdcc|partall|part|parseline|onotice|omsg|notify|noop|msg|mode|mnick|mkdir|menubar|me|mdi|maxdepth|logview|log|localinfo|loadbuf|load|list|links|linesep|leave|join|iuser|inc|iline|ignore|if|identd|ialmark|ialclear|ial|hsave|hotlink|hop|hmake|hload|hinc|hfree|help|hdel|hdec|haltdef|halt|hadd|guser|gunload|gtalk|gstop|gsize|gshow|groups|gqreq|gpoint|gplay|goto|gopts|gmove|gload|ghide|fwrite|fupdate|fullname|fserve|fsend|fseek|fopen|font|fnord|flushini|flush|flood|flist|flash|firewall|finger|findtext|filter|fclose|exit|events|enable|emailaddr|elseif|else|editbox|echo|ebeeps|drawtext|drawsize|drawscroll|drawsave|drawrot|drawreplace|drawrect|drawpic|drawline|drawfill|drawdot|drawcopy|dqwindow|dns|dll|dline|dlevel|disconnect|disable|didtok|did|dialog|describe|dec|debug|ddeserver|dde|dccserver|dcc|ctcps|ctcpreply|ctcp|creq|copy|continue|comreg|comopen|commands|comlist|comclose|colour|color|cnick|closemsg|closefserves|closedccs|closechats|close|clipboard|cline|clearial|clearall|clear|channel|bwrite|bunset|btrunc|bset|breplace|break|bread|bindip|beep|bcopy|ban|background|away|avoice|autojoin|auto|auser|aop|anick|amsg|ame|aline|ajinvite|add|action|abook|nick)( |\n)/, 
	};
	var KEYWORDS2 = {
		className: 'keyword',
		begin: / !?(iswmcs|iswm|isvoice|isupper|isreg|isprotect|isop|ison|isnum|isnotify|islower|isletter|isinvite|isincs|isin|isignore|ishop|isexcept|ischan|isban|isavoice|isaop|isalpha|isalnum) /,
	};
	var M_COMMENT = hljs.inherit(
    	hljs.COMMENT(null, null),
    	{
      		variants: [
      		  /* single-line comment */
      		  { begin: /^\s*\;/, end: /\n/ },
      		  /* multi-line comment */
      		  { begin: /^\s*\/\*/, end: /\*\// }
     		],
   		}
  	);
	PAREN_BLOCK.contains = [LITERAL, IDENTIFIERS, VARIABLES, KEYWORDS2, hljs.NUMBER_MODE, 'self'];
	CODE_BLOCK.contains = [PAREN_BLOCK, M_COMMENT, IDENTIFIERS, VARIABLES, LITERAL, KEYWORDS, KEYWORDS2, hljs.NUMBER_MODE, 'self'];
  	ALIAS.contains = [M_COMMENT, IDENTIFIERS, LITERAL, VARIABLES, KEYWORDS, KEYWORDS2, hljs.NUMBER_MODE, PAREN_BLOCK, CODE_BLOCK];
  	DIALOG.contains = [hljs.NUMBER_MODE];
  	MENU.contains = [MENU_SUBST2, MENU_SUBST1, IDENTIFIERS, VARIABLES, hljs.NUMBER_MODE, PAREN_BLOCK];
  	MENU_SUBST1.contains = [IDENTIFIERS, VARIABLES, hljs.NUMBER_MODE, PAREN_BLOCK];
  	MENU_SUBST2.contains = [IDENTIFIERS, VARIABLES, KEYWORDS, hljs.NUMBER_MODE, PAREN_BLOCK, CODE_BLOCK];
  	ON.contains = [M_COMMENT, IDENTIFIERS, LITERAL, VARIABLES, KEYWORDS, KEYWORDS2, hljs.NUMBER_MODE, CODE_BLOCK];
  	return {
  		aliases: ['mrc'],
  		case_insensitive: true,
  		contains: [
			ALIAS,
			DIALOG,
			MENU,
			ON,
			M_COMMENT,
  		]
  	};
}

Syntax highlighting on this forum
#2

I’ve actually Pull Requested a mIRC.js definition file, see: https://github.com/highlightjs/highlight.js/pull/1788

However the travis build failed and I don’t know enough to correct it. I went ahead and performed the same travis build on my fork @GitHub which completed fine… :thinking:


#3

Here is my take on it:

/*
Language: mIRC Scripting Language
Category: scripting
*/
function(hljs) {
	var COMMENT_DOC = {
		className: 'comment',
		begin: /^\x20*\/\*\*\s+/,
		end: /\*\//,
		contains: [
			{
				className: 'doctag',
				begin: /@\w+/
			}
		]
	};

	var COMMENT_BLOCK = {
		className: 'comment',
		begin: /^\x20*\/\*/,
		end: /\*\//
	};

	var COMMENT_LINE = {
		className: 'comment',
		begin: /^\x20*;/,
		end: /$/
	};

	var STATEMENTS = {
		className: 'code',
		begin: /^(alias|dialog)(\x20+-l)?\x20+[^\x20]+/,
		returnBegin: true,
		contains: [
			{
				className: 'built_in',
				begin: /^(alias|dialog)\b/,
				contains: [
					{
						className: 'symbol',
						begin: /\x20+-l/,
					},
					{
						className: 'title',
						begin: /\x20+[^\x20]+\b/,
						endsParent: true
					}
				]
			}
		]
	};

	var EVENTS1 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:(action|notice|text):[^:]+:(\?|#[^:]*|\*)/,
		end: /:/
	};

	var EVENTS2 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:(active|input|tabcomp):(\*|#[^:]*|\?|=|!|@[^:]*)/,
		end: /:/
	};

	var EVENTS3 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:(agent|appactive|(dis)?connect(fail)?|dns|exit|(un)?load|(midi|mp3|play|wave)end|nick|nosound|u?notify|ping|pong|quit|start|usermode)/,
		end: /:/
	};

	var EVENTS4 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:((un)?ban|(de)?help|(de|server)?op|(de)?owner|(de)?voice|invite|join|kick|(server)?mode|part|rawmode|topic):(?:\*|#[^:]*)/,
		end: /:/
	};

	var EVENTS5 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:(chat|ctcpreply|error|file(rcvd|sent)|(get|send)fail|logon|serv|signal|snotice|sock(close|listen|open|read|write)|udpread|vcmd|wallops):[^:]+/,
		end: /:/
	};

	var EVENTS6 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:close:(\*|\?|=|!|@[^:]*)/,
		end: /:/
	};

	var EVENTS7 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:dccserver:(chat|send|fserve)/,
		end: /:/
	};

	var EVENTS8 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:dialog:[^:]+:(init|close|edit|sclick|dclick|menu|scroll|mouse|rclick|drop|\*):[\d\-,\*]+/,
		end: /:/
	};

	var EVENTS9 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:hotlink:[^:]+:(?:\*|#[^:]*|\?|=|!|@[^:]*)/,
		end: /:/
	};

	var EVENTS10 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:key(down|up):(\*|@[^:]*):(\*|\d+(,\d+)*)/,
		end: /:/
	};

	var EVENTS11 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:open:(\*|\?|=|!|@[^:]*):[^:]+/,
		end: /:/
	};

	var EVENTS12 = {
		className: 'built_in',
		begin: /^on\x20+[^:\x20]+:parseline:(\*|in|out):[^:]+/,
		end: /:/
	};

	var EVENTS13 = {
		className: 'built_in',
		begin: /^raw\x20+[^:\x20]+:[^:]+/,
		end: /:/
	};

	var EVENTS14 = {
		className: 'built_in',
		begin: /^ctcp\x20+[^:\x20]+:[^:]+:(\*|#.*|\?)/,
		end: /:/
	};

	var CODE = {
		className: 'code',
		begin: /{/,
		end: /^}$/,
		contains: [
			{
				className: 'keyword',
				beginKeywords: 'if elseif else while break continue halt haltdef goto return'
			},
			{
				className: 'leteral',
				beginKeywords: '$true $false $null'
			}
		]
	};

	return {
  		aliases: ['mrc'],
		case_insensitive: true,
		keywords: {
			keyword: 'if elseif else while break continue halt haltdef goto return',
			leteral: '$true $false $null'
		},
  		contains: [
			COMMENT_DOC,
			COMMENT_BLOCK,
			COMMENT_LINE,
			STATEMENTS,
			EVENTS1,
			EVENTS2,
			EVENTS3,
			EVENTS4,
			EVENTS5,
			EVENTS6,
			EVENTS7,
			EVENTS8,
			EVENTS9,
			EVENTS10,
			EVENTS11,
			EVENTS12,
			EVENTS13,
			EVENTS14,
			CODE
  		]
  	};
}

still needs commands, identifiers, menu, among other things.


#4

@SykO, how are you testing? I’ve got mine on display on a raspberry pi here: http://highlight.duckdns.org/highlight.js/build/demo/

I quite like yours! Will you fork the highlight.js repo on GitHub and pr yours as well?


#5

I am testing it by building it using: node tools/build.js and previewing it in the file: tools/developer.html.

yeah that sounds good.


#6

Hey @Syko! How are you going with the syntax definition? Do you feel like placing it in a repo on mircscripts.nl? Maybe we (myself and the community) can work on it together!


#7

Oh sorry, been busy with school. I have not made any changes. All I have is there, on my previous post. I welcome you to create the repo, I will fork it and work on it whenever I got time.


#8

See --> https://www.mircscripts.nl/acvxqs/highlight.js

I’ve added you as a collaborator (Admin rights)

Note: I copy pasted your code and only changed instances of “leteral” to “literal

Cheers


#9

Added commands and identifiers. I do not like the commands, because you can have something like:
echo -s echo is a command
and it will highlight both echo. I could not figure out how to fix this. Still need stuff like group and dialog control commands like title, icon, option…


#10

As for the following: echo -s echo is a command we can try to state the premise under which you only highlight the first echo

basically after a ) the first word can be a command
after a { the first word can be a command
after a | the first word can be a command
the first word in a line can be a command
In a menu { } block statement, the first word after a colon can be a command…

See for example how Eneerge did this with his mSL syntax highlighter for Sublime Text : https://github.com/eneerge/mIRC-Scripting-Language-for-Sublime-Text/blob/master/mIRC-msl.sublime-syntax


#11

I did try that, but there are multiple things that do not work because of the parser. It is true that you can use: ), {, |, and the first word of the line, but there more, for example:

after an event:
on *:some_event: commands
so after “:”

after an alias:
alias my_alias return $false
so after a space.

Maybe there is something I am missing and this is possible. I did try to contribute a bit to a syntax highlighter for vs code: https://github.com/Kedyn/vscode-mirc from https://github.com/lol2k. I also was trying to create my own because lol2k has not updated the project. My own syntax highlighter for vs code contains the same content as you have seen on my last commit for our current project. Based on this experiences I know is hard to do because of the highlightjs parser, where as the vs code and other parsers give you a bit more freedom. I do hope someone finds a way, but mean while this is a better highlighter than the one we had.


#12

To clarify, it is not the library’s parser but javascript. It does not have a lookbehind operator. This makes it hard for few syntax strings. I have also looked at other languages defined for hljs, for example javascript and cpp.

for js one can have:

@for

let

@function @function@ @function@

and as you can clearly see it highlights some weird things.

for cpp:


auto @for for

int

just the same as in the previous example.

So the question is, how much should we do for ours?

Maybe we can just keep it simple like the first version on this thread.


#13

Version 1.0.0-alpha has been released… needs testing… because no one answer my question on my previous post and because I moved too fast with it, there are somethings specified on the readme (known issues) that I will not change for now. I think this is a great start and a good stopping (not final) point for this project. You may check this release version on: highlight release page.

Note: If you have contributed to the project please add your name on mirc.js file header.


#14

Wow, well done @SykO! I’ve been busy with work so not really had a good chance to look. What I can do is test your mirc.js file with pai’s peace and protection…
I’ll open an issue when I find anything!