1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/sourceeditor/codemirror/search/match-highlighter.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,100 @@ 1.4 +// Highlighting text that matches the selection 1.5 +// 1.6 +// Defines an option highlightSelectionMatches, which, when enabled, 1.7 +// will style strings that match the selection throughout the 1.8 +// document. 1.9 +// 1.10 +// The option can be set to true to simply enable it, or to a 1.11 +// {minChars, style, showToken} object to explicitly configure it. 1.12 +// minChars is the minimum amount of characters that should be 1.13 +// selected for the behavior to occur, and style is the token style to 1.14 +// apply to the matches. This will be prefixed by "cm-" to create an 1.15 +// actual CSS class name. showToken, when enabled, will cause the 1.16 +// current token to be highlighted when nothing is selected. 1.17 + 1.18 +(function(mod) { 1.19 + if (typeof exports == "object" && typeof module == "object") // CommonJS 1.20 + mod(require("../../lib/codemirror")); 1.21 + else if (typeof define == "function" && define.amd) // AMD 1.22 + define(["../../lib/codemirror"], mod); 1.23 + else // Plain browser env 1.24 + mod(CodeMirror); 1.25 +})(function(CodeMirror) { 1.26 + "use strict"; 1.27 + 1.28 + var DEFAULT_MIN_CHARS = 2; 1.29 + var DEFAULT_TOKEN_STYLE = "matchhighlight"; 1.30 + var DEFAULT_DELAY = 100; 1.31 + 1.32 + function State(options) { 1.33 + if (typeof options == "object") { 1.34 + this.minChars = options.minChars; 1.35 + this.style = options.style; 1.36 + this.showToken = options.showToken; 1.37 + this.delay = options.delay; 1.38 + } 1.39 + if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; 1.40 + if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; 1.41 + if (this.delay == null) this.delay = DEFAULT_DELAY; 1.42 + this.overlay = this.timeout = null; 1.43 + } 1.44 + 1.45 + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { 1.46 + if (old && old != CodeMirror.Init) { 1.47 + var over = cm.state.matchHighlighter.overlay; 1.48 + if (over) cm.removeOverlay(over); 1.49 + clearTimeout(cm.state.matchHighlighter.timeout); 1.50 + cm.state.matchHighlighter = null; 1.51 + cm.off("cursorActivity", cursorActivity); 1.52 + } 1.53 + if (val) { 1.54 + cm.state.matchHighlighter = new State(val); 1.55 + highlightMatches(cm); 1.56 + cm.on("cursorActivity", cursorActivity); 1.57 + } 1.58 + }); 1.59 + 1.60 + function cursorActivity(cm) { 1.61 + var state = cm.state.matchHighlighter; 1.62 + clearTimeout(state.timeout); 1.63 + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); 1.64 + } 1.65 + 1.66 + function highlightMatches(cm) { 1.67 + cm.operation(function() { 1.68 + var state = cm.state.matchHighlighter; 1.69 + if (state.overlay) { 1.70 + cm.removeOverlay(state.overlay); 1.71 + state.overlay = null; 1.72 + } 1.73 + if (!cm.somethingSelected() && state.showToken) { 1.74 + var re = state.showToken === true ? /[\w$]/ : state.showToken; 1.75 + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; 1.76 + while (start && re.test(line.charAt(start - 1))) --start; 1.77 + while (end < line.length && re.test(line.charAt(end))) ++end; 1.78 + if (start < end) 1.79 + cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); 1.80 + return; 1.81 + } 1.82 + if (cm.getCursor("head").line != cm.getCursor("anchor").line) return; 1.83 + var selection = cm.getSelections()[0].replace(/^\s+|\s+$/g, ""); 1.84 + if (selection.length >= state.minChars) 1.85 + cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); 1.86 + }); 1.87 + } 1.88 + 1.89 + function boundariesAround(stream, re) { 1.90 + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && 1.91 + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); 1.92 + } 1.93 + 1.94 + function makeOverlay(query, hasBoundary, style) { 1.95 + return {token: function(stream) { 1.96 + if (stream.match(query) && 1.97 + (!hasBoundary || boundariesAround(stream, hasBoundary))) 1.98 + return style; 1.99 + stream.next(); 1.100 + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); 1.101 + }}; 1.102 + } 1.103 +});