Created
May 29, 2015 10:49
-
-
Save alchen/01f245e227439ff94dd6 to your computer and use it in GitHub Desktop.
CodeMirror for Tweets
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
/*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