Created
July 24, 2018 14:26
-
-
Save tomatosoupcan/7ba40896f2417c0d4d5a8087dfdd5c08 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/** | |
* Portable utilities for IRC. | |
*/ | |
(function() { | |
'use strict'; | |
var IrcUtils = angular.module('IrcUtils', []); | |
IrcUtils.service('IrcUtils', [function() { | |
/** | |
* Escape a string for usage in a larger regexp | |
* @param str String to escape | |
* @return Escaped string | |
*/ | |
var escapeRegExp = function(str) { | |
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | |
}; | |
/** | |
* Get a new version of a nick list, sorted by last speaker | |
* | |
* @param nickList Original nick list | |
* @return Sorted nick list | |
*/ | |
var _ciNickList = function(nickList) { | |
var newList = _(nickList).sortBy(function(nickObj) { | |
return -nickObj.spokeAt; | |
}); | |
newList = _(newList).pluck('name'); | |
return newList; | |
}; | |
/** | |
* Completes a single nick. | |
* | |
* @param candidate What to search for | |
* @param nickList Array of current nicks sorted for case insensitive searching | |
* @return Completed nick (null if not found) | |
*/ | |
var _completeSingleNick = function(candidate, nickList) { | |
var foundNick = null; | |
nickList.some(function(nick) { | |
if (nick.toLowerCase().indexOf(candidate.toLowerCase()) === 0) { | |
// found! | |
foundNick = nick; | |
return true; | |
} | |
return false; | |
}); | |
return foundNick; | |
}; | |
/** | |
* Get the next nick when iterating nicks. | |
* | |
* @param iterCandidate First characters to look at | |
* @param currentNick Current selected nick | |
* @param nickList Array of current nicks sorted for case insensitive searching | |
* @return Next nick (may be the same) | |
*/ | |
var _nextNick = function(iterCandidate, currentNick, nickList) { | |
var matchingNicks = []; | |
var at = null; | |
var lcIterCandidate = iterCandidate.toLowerCase(); | |
var lcCurrentNick = currentNick.toLowerCase(); | |
// collect matching nicks | |
for (var i = 0; i < nickList.length; ++i) { | |
var lcNick = nickList[i].toLowerCase(); | |
if (lcNick.indexOf(lcIterCandidate) === 0) { | |
matchingNicks.push(nickList[i]); | |
if (lcCurrentNick === lcNick) { | |
at = matchingNicks.length - 1; | |
} | |
} | |
/* Since we aren't sorted any more torhve disabled this: | |
else if (matchingNicks.length > 0) { | |
// end of group, no need to check after this | |
//break; | |
} | |
*/ | |
} | |
if (at === null || matchingNicks.length === 0) { | |
return currentNick; | |
} else { | |
++at; | |
if (at === matchingNicks.length) { | |
// cycle | |
at = 0; | |
} | |
return matchingNicks[at]; | |
} | |
}; | |
/** | |
* Nicks tab completion. | |
* | |
* @param text Plain text (no colors) | |
* @param caretPos Current caret position (0 means before the first character) | |
* @param iterCandidate Current iteration candidate (null if not iterating) | |
* @param nickList Array of current nicks | |
* @param suf Custom suffix (at least one character, escaped for regex) | |
* @param addSpace Whether to add a space after nick completion in the middle | |
* @return Object with following properties: | |
* text: new complete replacement text | |
* caretPos: new caret position within new text | |
* foundNick: completed nick (or null if not possible) | |
* iterCandidate: current iterating candidate | |
*/ | |
var completeNick = function(text, caretPos, iterCandidate, nickList, suf, addSpace) { | |
var doIterate = (iterCandidate !== null); | |
if (suf === undefined) { | |
suf = ':'; | |
} | |
var prf = '@'; | |
// addSpace defaults to true | |
var addSpaceChar = (addSpace === undefined || addSpace === true) ? ' ' : ' '; | |
// new nick list to search in | |
var searchNickList = _ciNickList(nickList); | |
// text before and after caret | |
var beforeCaret = text.substring(0, caretPos); | |
var afterCaret = text.substring(caretPos); | |
// default: don't change anything | |
var ret = { | |
text: text, | |
caretPos: caretPos, | |
foundNick: null, | |
iterCandidate: null | |
}; | |
// iterating nicks at the beginning? | |
var m = beforeCaret.match(new RegExp('^@([a-zA-Z0-9_\\\\\\[\\]{}^`|-]+)' + suf + ' $')); | |
var newNick = null; | |
if (m) { | |
if (doIterate) { | |
// try iterating | |
newNick = _nextNick(iterCandidate, m[1], searchNickList); | |
beforeCaret = prf + newNick + suf + ' '; | |
return { | |
text: beforeCaret + afterCaret, | |
caretPos: beforeCaret.length, | |
foundNick: newNick, | |
iterCandidate: iterCandidate | |
}; | |
} else { | |
// if not iterating, don't do anything | |
return ret; | |
} | |
} | |
// nick completion in the beginning? | |
m = beforeCaret.match(/^([a-zA-Z0-9_\\\[\]{}^`|-]+)$/); | |
if (m) { | |
// try completing | |
newNick = _completeSingleNick(m[1], searchNickList); | |
if (newNick === null) { | |
// no match | |
return ret; | |
} | |
beforeCaret = prf + newNick + suf + ' '; | |
if (afterCaret[0] === ' ') { | |
// swallow first space after caret if any | |
afterCaret = afterCaret.substring(1); | |
} | |
return { | |
text: beforeCaret + afterCaret, | |
caretPos: beforeCaret.length, | |
foundNick: newNick, | |
iterCandidate: m[1] | |
}; | |
} | |
// iterating nicks in the middle? | |
m = beforeCaret.match(/^(.* )@([a-zA-Z0-9_\\\[\]{}^`|-]+) $/); | |
if (m) { | |
if (doIterate) { | |
// try iterating | |
newNick = _nextNick(iterCandidate, m[2], searchNickList); | |
beforeCaret = m[1] + prf + newNick + addSpaceChar; | |
return { | |
text: beforeCaret + afterCaret, | |
caretPos: beforeCaret.length, | |
foundNick: newNick, | |
iterCandidate: iterCandidate | |
}; | |
} else { | |
// if not iterating, don't do anything | |
return ret; | |
} | |
} | |
// nick completion elsewhere in the middle? | |
m = beforeCaret.match(/^(.* )([a-zA-Z0-9_\\\[\]{}^`|-]+)$/); | |
if (m) { | |
// try completing | |
newNick = _completeSingleNick(m[2], searchNickList); | |
if (newNick === null) { | |
// no match | |
return ret; | |
} | |
beforeCaret = m[1] + prf + newNick + addSpaceChar; | |
if (afterCaret[0] === ' ') { | |
// swallow first space after caret if any | |
afterCaret = afterCaret.substring(1); | |
} | |
return { | |
text: beforeCaret + afterCaret, | |
caretPos: beforeCaret.length, | |
foundNick: newNick, | |
iterCandidate: m[2] | |
}; | |
} | |
// completion not possible | |
return ret; | |
}; | |
return { | |
'completeNick': completeNick | |
}; | |
}]); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment