Skip to content

Instantly share code, notes, and snippets.

@alchen
Created May 29, 2015 10:49
Show Gist options
  • Save alchen/01f245e227439ff94dd6 to your computer and use it in GitHub Desktop.
Save alchen/01f245e227439ff94dd6 to your computer and use it in GitHub Desktop.
CodeMirror for Tweets
/*jslint latedef:false*/
'use strict';
var CodeMirror = require('codemirror');
var twitterText = require('twitter-text');
CodeMirror.defineSimpleMode = function(name, states) {
CodeMirror.defineMode(name, function(config) {
return CodeMirror.simpleMode(config, states);
});
};
CodeMirror.simpleMode = function(config, states) {
ensureState(states, 'start');
var states_ = {}, meta = states.meta || {};
for (var state in states) if (state !== meta && states.hasOwnProperty(state)) {
var list = states_[state] = [], orig = states[state];
for (var i = 0; i < orig.length; i++) {
var data = orig[i];
list.push(new Rule(data, states));
}
}
var mode = {
startState: function() {
return {state: 'start', pending: null,
local: null, localState: null};
},
copyState: function(state) {
var s = {state: state.state, pending: state.pending,
local: state.local, localState: null};
if (state.localState)
s.localState = CodeMirror.copyState(state.local.mode, state.localState);
if (state.stack)
s.stack = state.stack.slice(0);
for (var pers = state.persistentStates; pers; pers = pers.next)
s.persistentStates = {mode: pers.mode,
spec: pers.spec,
state: pers.state === state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state),
next: s.persistentStates};
return s;
},
token: tokenFunction(states_, config),
innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }
};
if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop))
mode[prop] = meta[prop];
return mode;
};
function ensureState(states, name) {
if (!states.hasOwnProperty(name))
throw new Error('Undefined state ' + name + 'in simple mode');
}
function toRegex(val, caret) {
if (!val) return /(?:)/;
var flags = '';
if (val instanceof RegExp) {
if (val.ignoreCase) flags = 'i';
val = val.source;
} else {
val = String(val);
}
return new RegExp((caret === false ? '' : '^') + '(?:' + val + ')', flags);
}
function Rule(data, states) {
if (data.next || data.push) ensureState(states, data.next || data.push);
this.regex = toRegex(data.regex);
this.token = data.token;
this.data = data;
}
function tokenFunction(states, config) {
return function(stream, state) {
if (state.pending) {
var pend = state.pending.shift();
if (state.pending.length === 0) state.pending = null;
stream.pos += pend.text.length;
return pend.token;
}
if (state.local) {
var tok;
if (state.local.end && stream.match(state.local.end)) {
tok = state.local.endToken || null;
state.local = state.localState = null;
return tok;
} else {
var m;
tok = state.local.mode.token(stream, state.localState);
if (state.local.endScan && (m = state.local.endScan.exec(stream.current())))
stream.pos = stream.start + m.index;
return tok;
}
}
var curState = states[state.state];
for (var i = 0; i < curState.length; i++) {
var rule = curState[i];
var matches = stream.match(rule.regex);
if (matches) {
return rule.token;
}
}
stream.next();
return null;
};
}
CodeMirror.defineSimpleMode('twitter', {
start: [
{regex: twitterText.regexen.validMentionOrList, token: 'keyword'},
{regex: twitterText.regexen.extractUrl, token: 'keyword'},
{regex: twitterText.regexen.validHashtag, token: 'keyword'},
{regex: twitterText.regexen.validCashtag, token: 'keyword'}
]
});
module.exports = CodeMirror;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment