Created
January 23, 2014 22:48
-
-
Save d3m3vilurr/8588379 to your computer and use it in GitHub Desktop.
IRCCloud CJK Autocompletion Patch
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
// ==UserScript== | |
// @name IRCCloud CJK Autocompletion Patch | |
// @namespace https://gist.github.com/d3m3vilurr/8588379 | |
// @version 0.1 | |
// @include https://www.irccloud.com/* | |
// @run-at document-body | |
// @grant unsafeWindow | |
// ==/UserScript== | |
var init = function() { | |
if (!unsafeWindow.TabCompletion) { | |
console.log('wait irccloud modules'); | |
return setTimeout(init, 1000); | |
} | |
unsafeWindow.TabCompletion.prototype.getCandidates = function () { | |
if (!this.word && !this.cycling) { | |
this.cacheCursorRange(); | |
// Split the sentence either side of the word before the selection | |
var value = this.getValue(); | |
this.wordsTillSelection = value.slice(0, this.cursorRange.start); | |
this.afterSelection = value.slice(this.cursorRange.start); | |
// Split on non words | |
// Word chars are alnum: a-z0-9 | |
// diacritics: \u00C0-\u00D6 \u00D8-\u00F6 \u00F8-\u02AF | |
// specific list of chars: # [ \ ] ^ _ ` { | } - | |
var tokens = this.wordsTillSelection.split(/[^a-z0-9\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02AF\uAC00-\uD7FF\u1100-\u11FF\u3130-\u318F\u31C0-\u4DBF\uA960-\uA97F\uFF00-\uFFEF\u1B000-\u1B0FF\u2FF0-\u30FF\u4E00-\u9FFF\u20000-\u2A6DF\u2A700-\u2B73F\u2B740-\u2B81F\uF900-\uFAFF\u2E80-\u2EFF\u2F00-\u2FDF\uF900-\uFAFF\u2F800-\u2FA1F\uFE30-\uFE4F#[\\\]^_`{|}-]+/i); | |
this.word = tokens.pop(); | |
} | |
var members = this.model.getMembers(); | |
var channels = this.model.connection.buffers.channels; | |
var previousBuffer = this.model.session.previousBuffer; | |
// Build up list of matching candidates | |
var candidates = []; | |
var chanCommandMatch = this.wordsTillSelection.match(/^\/(j|join|channel|rejoin|mode)\s*$/i); | |
var startChanCommandMatch = this.wordsTillSelection.match(/^\/(j|join|channel|rejoin|mode)(?:\s+|$)/i); | |
if (startChanCommandMatch) { | |
if (startChanCommandMatch[1].toLowerCase() == 'mode') { | |
this.cyclingModeChannels = true; | |
} else { | |
this.cyclingJoin = true; | |
} | |
} | |
var topicCommandMatch = this.wordsTillSelection.match(/^\/topic\s*$/i); | |
var startBanCommandMatch = this.wordsTillSelection.match(/^\/ban(?:\s+|$)/i); | |
var nonJoinOnlyChans = false; | |
if (chanCommandMatch) { | |
// Channel command, only complete from channels | |
this.cycling = true; | |
this.cyclingCommand = true; | |
if (this.cyclingModeChannels) { | |
nonJoinOnlyChans = true; | |
} | |
channels.each(function (channel) { | |
if (!channel.isArchived()) { | |
candidates.push(channel); | |
} | |
}); | |
candidates.sort(this.cmpBuffers); | |
} else if (this.model.isChannel() && topicCommandMatch) { | |
// Cycle topics | |
var topic = this.model.getTopic().getText(); | |
this.cycling = true; | |
this.cyclingCommand = true; | |
this.cyclingTopic = true; | |
// TODO keep a history of topics server side | |
candidates.push(topic); | |
} else if (!this.word) { | |
// No word, only complete from last highlighted (or conversation recipient) | |
this.cycling = true; | |
this.cyclingLastHighlighted = true; | |
if (this.model.isConversation()) { | |
candidates.push(this.model.getRecipient()); | |
} else { | |
members.each(function (member) { | |
if (!member.isIgnored() && member.lastHighlighted) { | |
candidates.push(member); | |
} | |
}); | |
} | |
// Sort by last highlighted | |
candidates.sort(function (a, b) { | |
return (b.getLastHighlighted() || 0) - (a.getLastHighlighted() || 0); | |
}); | |
} else { | |
// Have a word, not a channel command, add matching members and channels | |
var anyMembers = false; | |
members.each(function (member) { | |
if (this.inputMatches(member.getName(), this.word)) { | |
anyMembers = true; | |
candidates.push(member); | |
} | |
}, this); | |
if (!startBanCommandMatch) { | |
channels.each(function (chan) { | |
if (this.inputMatchesNoStrip(chan.getName(), this.word)) { | |
if (!anyMembers) { | |
nonJoinOnlyChans = true; | |
} | |
candidates.push(chan); | |
} | |
}, this); | |
} | |
candidates.sort(_.bind(this.cmpAll, this)); | |
} | |
// Move previous chan to start for join commands | |
if (startChanCommandMatch && previousBuffer && previousBuffer.isChannel()) { | |
var prevChanIndex = $.inArray(previousBuffer, candidates); | |
if (prevChanIndex !== -1) { | |
var prevChan = candidates.splice(prevChanIndex, 1)[0]; | |
candidates.unshift(prevChan); | |
} | |
} | |
var selfChanIndex = $.inArray(this.model, candidates); | |
if (selfChanIndex !== -1) { | |
// Move current chan to end for join commands and to start for other chan only commands | |
var selfChan = candidates.splice(selfChanIndex, 1)[0]; | |
if (nonJoinOnlyChans) { | |
candidates.unshift(selfChan); | |
} else { | |
candidates.push(selfChan); | |
} | |
} | |
if (!this.cyclingTopic) { | |
// Move yourself to the end | |
var selfIndex = _.indexOf(_.map(candidates, function (item, index) { | |
return item.getName().toLowerCase(); | |
}), this.model.getNick().toLowerCase()); | |
if (selfIndex !== -1) { | |
candidates.push(candidates.splice(selfIndex, 1)[0]); | |
} | |
} | |
if (startBanCommandMatch) { | |
this.cyclingBan = true; | |
// Add a ban mask too | |
candidates = _.flatten(_.map(candidates, function (m) { | |
return [m, m.getBanMask(true)]; | |
})); | |
} | |
return candidates; | |
}; | |
}; | |
init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment