WordPress.org

Plugin Directory

Changeset 607254


Ignore:
Timestamp:
10/03/12 01:01:11 (22 months ago)
Author:
bainternet
Message:

tagged 2.1.5

Location:
advanced-code-editor
Files:
74 added
4 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • advanced-code-editor/trunk/advanced-code-editor.php

    r583191 r607254  
    44Plugin URI: http://en.bainternet.info 
    55Description: Enables syntax highlighting in the integrated themes and plugins source code editors with line numbers, AutoComplete and much more. Supports PHP, HTML, CSS and JS. 
    6 Version: 2.1.4 
     6Version: 2.1.5 
    77Author: BaInternet 
    88Author URI: http://en.bainternet.info 
     
    5757         * @var string 
    5858         */ 
    59         static $version = '2.1.3'; 
     59        static $version = '2.1.5'; 
    6060 
    6161        /** 
     
    8686                //ajax get file revisions 
    8787                add_action('wp_ajax_get_file_revisions',array($this,'ajax_get_file_revisions')); 
    88                 if( strpos( strtolower( $_SERVER[ 'REQUEST_URI' ] ), 'plugin-editor.php' ) !== false || strpos( strtolower( $_SERVER[ 'REQUEST_URI' ] ), 'theme-editor.php' ) !== false ){ 
    89                     add_filter( 'admin_footer', array($this,'do_edit' )); 
    90                     add_filter('admin_enqueue_scripts',array($this,'add_scripts')); 
    91                     //Language Setup 
    92                     $locale = get_locale(); 
    93                     load_plugin_textdomain( $this->localization_domain, false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' ); 
    94                     $options = get_option('ace_options',$this->get_defaults()); 
    95                     if (isset($options['use_file_tree'])){ 
    96                         if (strpos( strtolower( $_SERVER[ 'REQUEST_URI' ] ), 'plugin-editor.php' ) !== false) 
    97                             add_action('admin_footer',array($this,'plugin_file_tree')); 
    98                         else 
    99                             add_action('admin_footer',array($this,'theme_file_tree')); 
    100                     } 
     88                add_action('load-theme-editor.php', array($this,'add_scripts')); 
     89                add_filter( 'admin_footer-theme-editor.php', array($this,'do_edit' )); 
     90                add_action('load-plugin-editor.php', array($this,'add_scripts')); 
     91                add_filter( 'admin_footer-plugin-editor.php', array($this,'do_edit' )); 
     92                //Language Setup 
     93                $locale = get_locale(); 
     94                load_plugin_textdomain( $this->localization_domain, false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' ); 
     95                $options = get_option('ace_options',$this->get_defaults()); 
     96                if (isset($options['use_file_tree'])){ 
     97                    add_action('admin_footer-plugin-editor.php',array($this,'plugin_file_tree')); 
     98                    add_action('admin_footer-theme-editor.php',array($this,'theme_file_tree')); 
    10199                } 
    102100                $this->update_wpdb($this->tablename); 
    103                  
    104                      
    105101            } 
    106102             
     
    588584                        if ($_POST['f_type'] == "plugin" ){ 
    589585                            $dir_name = WP_PLUGIN_DIR . '/' . $_POST['dir'] . '/' . $new_dir_name; 
    590                         } 
    591                         if ($_POST['f_type'] == "theme" ){ 
    592                             $dir_name = $_POST['dir'] . '/' . $new_dir_name; 
     586                        }elseif ($_POST['f_type'] == "theme" ){ 
     587                            $t = wp_get_theme($_POST['dir']); 
     588                            if ( $t->exists() ){ 
     589                                $dir_name = $t->get_stylesheet_directory(). '/' . $new_dir_name;;  
     590                            } 
    593591                        } 
    594592                         
     
    662660                            if (current_user_can( 'edit_themes' )){ 
    663661                                $checks = true; 
    664                                 $file_name = $_POST['dir'] . '/' . $f_name; 
    665  
     662                                $t = wp_get_theme($_POST['dir']); 
     663                                if ( $t->exists() ){ 
     664                                    $file_name = $t->get_stylesheet_directory(). '/' . $f_name;;  
     665                                } 
    666666                            } 
    667667                        }else{ 
     
    702702         */ 
    703703        function add_scripts(){ 
     704             
    704705            $url = plugins_url()."/advanced-code-editor/"; 
     706            $v = "1.1.1.512";//$this->version; 
    705707            wp_enqueue_script( 'jquery' ); 
    706708            wp_enqueue_script( 'jquery-form' ); 
    707             wp_enqueue_script('codemirror',$url.'js/codemirror.js',array(),$this->version,true); 
    708             wp_enqueue_script('codemirror-fold',$url.'js/foldcode.js',array(),$this->version,true); 
    709             wp_enqueue_script('codemirror-format',$url.'js/formatting.js',array(),$this->version,true); 
    710             wp_enqueue_script('codemirror-xml',$url.'js/xml.js',array(),$this->version,true); 
    711             wp_enqueue_script('codemirror-js',$url.'js/javascript.js',array(),$this->version,true); 
    712             wp_enqueue_script('codemirror-css',$url.'js/css.js',array(),$this->version,true); 
    713             wp_enqueue_script('codemirror-clike',$url.'js/clike.js',array(),$this->version,true); 
    714             wp_enqueue_script('codemirror-php',$url.'js/php.js',array(),$this->version,true); 
    715             wp_enqueue_script('codemirror-search',$url.'js/searchcursor.js',array(),$this->version,true); 
    716             wp_enqueue_script('codemirror-complete',$url.'js/complete.js',array(),$this->version,true); 
     709             
     710            wp_enqueue_script('codemirror',$url.'js/codemirror.js',array(),$v,true); 
     711            wp_enqueue_script('codemirror-fold',$url.'js/foldcode.js',array(),$v,true); 
     712            wp_enqueue_script('codemirror-format',$url.'js/formatting.js',array(),$v,true); 
     713            wp_enqueue_script('codemirror-xml',$url.'js/xml.js',array(),$v,true); 
     714            wp_enqueue_script('codemirror-js',$url.'js/javascript.js',array(),$v,true); 
     715            wp_enqueue_script('codemirror-css',$url.'js/css.js',array(),$v,true); 
     716            wp_enqueue_script('codemirror-php',$url.'js/php.js',array(),$v,true); 
     717            wp_enqueue_script('codemirror-clike',$url.'js/clike.js',array(),$v,true); 
     718            wp_enqueue_script('codemirror-search',$url.'js/searchcursor.js',array(),$v,true); 
     719            wp_enqueue_script('codemirror-complete',$url.'js/complete.js',array(),$v,true); 
     720             
    717721            $def = $this->get_defaults(); 
    718722            $options = get_option('ace_options',array()); 
     
    726730            //stylesheets 
    727731            wp_enqueue_style('codemirror', $url.'css/codemirror.css', false, false); 
     732             
    728733            wp_enqueue_style('codemirror-def', $url.'themes/default.css', false, false); 
    729734            wp_enqueue_style('codemirror-night', $url.'themes/night.css', false, false); 
     
    750755           ?> 
    751756            <style> 
    752             .CodeMirror-scroll {height: 550px;overflow-y: hidden;overflow-x: auto;} 
    753757            .ace_tool_bar{list-style: none;} 
    754758            .ace_tool_bar li{cursor: pointer;} 
    755759            .completions {position: absolute;z-index: 10;overflow: hidden;-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);box-shadow: 2px 3px 5px rgba(0,0,0,.2);} 
    756760            .completions select {background: #fafafa;outline: none;border: none;padding: 0;margin: 0;font-family: monospace;} 
    757                <?php if (!is_rtl()){?> 
    758             /*.CodeMirror-scroll {height: 600px;overflow: auto; margin-right: 0 !important;}*/ 
    759             .CodeMirror-gutter{ width: 50px !important;} 
     761            .CodeMirror {border: 1px solid #eee;} 
     762             <?php if (!is_rtl()){?> 
    760763            .fullscreen{background-color: #FFFFFF;height: 89%;left: 0;position: fixed;top: 80px;width: 100%;z-index: 100;} 
    761764            .ace_ToolBar{background-color: #FFFFFF;left: 0;min-height: 85px;position: fixed;top: 0;width: 100%;z-index: 100;} 
     
    768771 
    769772            <?php }else{ ?> 
    770               
    771             .CodeMirror {border: 1px solid #eee; margin-left: 190px !important;}  
    772             /*.CodeMirror-scroll {height: 600px;overflow: auto; margin-left: 0 !important;}*/ 
    773             .CodeMirror-gutter{ width: 50px !important;} 
    774              #template div {margin-left: 0px;} 
     773            /*#template div {margin-left: 0px;}*/ 
    775774            .fullscreen{background-color: #FFFFFF;height: 89%;right: 0;position: fixed;top: 80px;width: 100%;z-index: 100;} 
    776775            .ace_ToolBar{background-color: #FFFFFF;right: 0;min-height: 85px;position: fixed;top: 0;width: 100%;z-index: 100;} 
    777776            .ace_tool_bar li{float: right; } 
    778             .clean_ace{clear:right;} 
     777 
    779778            .CodeMirror-lines{direction: ltr;} 
    780779            .completions{direction: ltr;} 
     
    12411240                    }else{ 
    12421241                        //theme file 
    1243                         plugin_meta = jQuery('input[name="file"]').val().split('/'); 
    1244                         var plugin_dir = plugin_meta[0]; 
    1245                         var dirs = plugin_meta.length - 1; 
    1246                         for(i=1; i < dirs; i++) {  
    1247                             plugin_dir = plugin_dir + '/' + plugin_meta[i]; 
    1248                         } 
     1242                        plugin_dir = theme_to_download; 
    12491243                        f_type2 = 'theme'; 
    12501244                    } 
     
    12881282                }else{ 
    12891283                //theme file 
    1290                     plugin_meta = jQuery('input[name="file"]').val().split('/'); 
    1291                     var plugin_dir = plugin_meta[0]; 
    1292                     var dirs = plugin_meta.length - 1; 
    1293                     for(i=1; i < dirs; i++) {  
    1294                         plugin_dir = plugin_dir + '/' + plugin_meta[i]; 
    1295                     } 
     1284                    plugin_dir = theme_to_download; 
    12961285                    f_type = 'theme'; 
    12971286                } 
  • advanced-code-editor/trunk/css/codemirror.css

    r566232 r607254  
    99} 
    1010 
     11.CodeMirror, .CodeMirror div { 
     12    margin-right: 0!important; 
     13} 
    1114.CodeMirror-scroll { 
    12   overflow-x: auto; 
    13   overflow-y: hidden; 
    14   height: 300px; 
    15   /* This is needed to prevent an IE[67] bug where the scrolled content 
    16      is visible outside of the scrolling box. */ 
    17   position: relative; 
    18   outline: none; 
     15    overflow-x: auto; 
     16    overflow-y: hidden; 
     17    height: 550px; 
     18    /* 
     19     This is needed to prevent an IE[67] bug where the scrolled content 
     20     is visible outside of the scrolling box. 
     21    */ 
     22    position: relative; 
     23    outline: none; 
    1924} 
     25 
    2026 
    2127/* Vertical scrollbar */ 
    2228.CodeMirror-scrollbar { 
    23   float: right; 
     29  position: absolute; 
     30  right: 0; top: 0; 
    2431  overflow-x: hidden; 
    2532  overflow-y: scroll; 
    26  
    27   /* This corrects for the 1px gap introduced to the left of the scrollbar 
    28      by the rule for .CodeMirror-scrollbar-inner. */ 
    29   margin-left: -1px; 
     33  z-index: 5; 
    3034} 
    3135.CodeMirror-scrollbar-inner { 
     
    6367  padding: .4em .2em .4em .4em; 
    6468  white-space: pre !important; 
     69  cursor: default; 
    6570} 
    6671.CodeMirror-lines { 
     
    6873  white-space: pre; 
    6974  cursor: text; 
    70 } 
    71 .CodeMirror-lines * { 
    72   /* Necessary for throw-scrolling to decelerate properly on Safari. */ 
    73   pointer-events: none; 
    7475} 
    7576 
     
    134135} 
    135136 
    136 /* Default theme */ 
    137  
    138 .cm-s-default span.cm-keyword {color: #708;} 
    139 .cm-s-default span.cm-atom {color: #219;} 
    140 .cm-s-default span.cm-number {color: #164;} 
    141 .cm-s-default span.cm-def {color: #00f;} 
    142 .cm-s-default span.cm-variable {color: black;} 
    143 .cm-s-default span.cm-variable-2 {color: #05a;} 
    144 .cm-s-default span.cm-variable-3 {color: #085;} 
    145 .cm-s-default span.cm-property {color: black;} 
    146 .cm-s-default span.cm-operator {color: black;} 
    147 .cm-s-default span.cm-comment {color: #a50;} 
    148 .cm-s-default span.cm-string {color: #a11;} 
    149 .cm-s-default span.cm-string-2 {color: #f50;} 
    150 .cm-s-default span.cm-meta {color: #555;} 
    151 .cm-s-default span.cm-error {color: #f00;} 
    152 .cm-s-default span.cm-qualifier {color: #555;} 
    153 .cm-s-default span.cm-builtin {color: #30a;} 
    154 .cm-s-default span.cm-bracket {color: #cc7;} 
    155 .cm-s-default span.cm-tag {color: #170;} 
    156 .cm-s-default span.cm-attribute {color: #00c;} 
    157 .cm-s-default span.cm-header {color: blue;} 
    158 .cm-s-default span.cm-quote {color: #090;} 
    159 .cm-s-default span.cm-hr {color: #999;} 
    160 .cm-s-default span.cm-link {color: #00c;} 
    161  
    162137span.cm-header, span.cm-strong {font-weight: bold;} 
    163138span.cm-em {font-style: italic;} 
     
    165140span.cm-link {text-decoration: underline;} 
    166141 
     142span.cm-invalidchar {color: #f00;} 
     143 
    167144div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 
    168145div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 
     146 
     147@media print { 
     148 
     149  /* Hide the cursor when printing */ 
     150  .CodeMirror pre.CodeMirror-cursor { 
     151    visibility: hidden; 
     152  } 
     153 
     154} 
  • advanced-code-editor/trunk/js/clike.js

    r518172 r607254  
    11CodeMirror.defineMode("clike", function(config, parserConfig) { 
    2   var indentUnit = config.indentUnit, keywords = parserConfig.keywords, 
    3       cpp = parserConfig.useCPP, multiLineStrings = parserConfig.multiLineStrings, 
    4       $vars = parserConfig.$vars, atAnnotations = parserConfig.atAnnotations; 
    5   var isOperatorChar = /[+\-*&%=<>!?|]/; 
    6  
    7   function chain(stream, state, f) { 
    8     state.tokenize = f; 
    9     return f(stream, state); 
    10   } 
    11  
    12   var type; 
    13   function ret(tp, style) { 
    14     type = tp; 
    15     return style; 
    16   } 
     2  var indentUnit = config.indentUnit, 
     3      keywords = parserConfig.keywords || {}, 
     4      builtin = parserConfig.builtin || {}, 
     5      blockKeywords = parserConfig.blockKeywords || {}, 
     6      atoms = parserConfig.atoms || {}, 
     7      hooks = parserConfig.hooks || {}, 
     8      multiLineStrings = parserConfig.multiLineStrings; 
     9  var isOperatorChar = /[+\-*&%=<>!?|\/]/; 
     10 
     11  var curPunc; 
    1712 
    1813  function tokenBase(stream, state) { 
    1914    var ch = stream.next(); 
    20     if (ch == '"' || ch == "'") 
    21       return chain(stream, state, tokenString(ch)); 
    22     else if (/[\[\]{}\(\),;\:\.]/.test(ch)) 
    23       return ret(ch); 
    24     else if (ch == "#" && cpp && state.startOfLine) { 
    25       stream.skipToEnd(); 
    26       return ret("directive", "meta"); 
    27     } 
    28     else if (/\d/.test(ch)) { 
    29       stream.eatWhile(/[\w\.]/) 
    30       return ret("number", "number"); 
    31     } 
    32     else if (ch == "/") { 
     15    if (hooks[ch]) { 
     16      var result = hooks[ch](stream, state); 
     17      if (result !== false) return result; 
     18    } 
     19    if (ch == '"' || ch == "'") { 
     20      state.tokenize = tokenString(ch); 
     21      return state.tokenize(stream, state); 
     22    } 
     23    if (/[\[\]{}\(\),;\:\.]/.test(ch)) { 
     24      curPunc = ch; 
     25      return null; 
     26    } 
     27    if (/\d/.test(ch)) { 
     28      stream.eatWhile(/[\w\.]/); 
     29      return "number"; 
     30    } 
     31    if (ch == "/") { 
    3332      if (stream.eat("*")) { 
    34         return chain(stream, state, tokenComment); 
    35       } 
    36       else if (stream.eat("/")) { 
     33        state.tokenize = tokenComment; 
     34        return tokenComment(stream, state); 
     35      } 
     36      if (stream.eat("/")) { 
    3737        stream.skipToEnd(); 
    38         return ret("comment", "comment"); 
    39       } 
    40       else { 
    41         stream.eatWhile(isOperatorChar); 
    42         return ret("operator"); 
    43       } 
    44     } 
    45     else if (isOperatorChar.test(ch)) { 
     38        return "comment"; 
     39      } 
     40    } 
     41    if (isOperatorChar.test(ch)) { 
    4642      stream.eatWhile(isOperatorChar); 
    47       return ret("operator"); 
    48     } 
    49     else if (atAnnotations && ch == "@") { 
    50         stream.eatWhile(/[\w\$_]/); 
    51         return ret("annotation", "meta"); 
    52     } 
    53     else if ($vars && ch == "$") { 
    54       stream.eatWhile(/[\w\$_]/); 
    55       return ret("word", "variable"); 
    56     } 
    57     else { 
    58       stream.eatWhile(/[\w\$_]/); 
    59       if (keywords && keywords.propertyIsEnumerable(stream.current())) return ret("keyword", "keyword"); 
    60       return ret("word"); 
    61     } 
     43      return "operator"; 
     44    } 
     45    stream.eatWhile(/[\w\$_]/); 
     46    var cur = stream.current(); 
     47    if (keywords.propertyIsEnumerable(cur)) { 
     48      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; 
     49      return "keyword"; 
     50    } 
     51    if (builtin.propertyIsEnumerable(cur)) { 
     52      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; 
     53      return "builtin"; 
     54    } 
     55    if (atoms.propertyIsEnumerable(cur)) return "atom"; 
     56    return "variable"; 
    6257  } 
    6358 
     
    7065      } 
    7166      if (end || !(escaped || multiLineStrings)) 
    72         state.tokenize = tokenBase; 
    73       return ret("string", "string"); 
     67        state.tokenize = null; 
     68      return "string"; 
    7469    }; 
    7570  } 
     
    7974    while (ch = stream.next()) { 
    8075      if (ch == "/" && maybeEnd) { 
    81         state.tokenize = tokenBase; 
     76        state.tokenize = null; 
    8277        break; 
    8378      } 
    8479      maybeEnd = (ch == "*"); 
    8580    } 
    86     return ret("comment", "comment"); 
     81    return "comment"; 
    8782  } 
    8883 
     
    9489    this.prev = prev; 
    9590  } 
    96  
    9791  function pushContext(state, col, type) { 
    9892    return state.context = new Context(state.indented, col, type, null, state.context); 
    9993  } 
    10094  function popContext(state) { 
     95    var t = state.context.type; 
     96    if (t == ")" || t == "]" || t == "}") 
     97      state.indented = state.context.indented; 
    10198    return state.context = state.context.prev; 
    10299  } 
     
    107104    startState: function(basecolumn) { 
    108105      return { 
    109         tokenize: tokenBase, 
     106        tokenize: null, 
    110107        context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), 
    111108        indented: 0, 
     
    122119      } 
    123120      if (stream.eatSpace()) return null; 
    124       var style = state.tokenize(stream, state); 
    125       if (type == "comment") return style; 
     121      curPunc = null; 
     122      var style = (state.tokenize || tokenBase)(stream, state); 
     123      if (style == "comment" || style == "meta") return style; 
    126124      if (ctx.align == null) ctx.align = true; 
    127125 
    128       if ((type == ";" || type == ":") && ctx.type == "statement") popContext(state); 
    129       else if (type == "{") pushContext(state, stream.column(), "}"); 
    130       else if (type == "[") pushContext(state, stream.column(), "]"); 
    131       else if (type == "(") pushContext(state, stream.column(), ")"); 
    132       else if (type == "}") { 
    133         if (ctx.type == "statement") ctx = popContext(state); 
     126      if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); 
     127      else if (curPunc == "{") pushContext(state, stream.column(), "}"); 
     128      else if (curPunc == "[") pushContext(state, stream.column(), "]"); 
     129      else if (curPunc == "(") pushContext(state, stream.column(), ")"); 
     130      else if (curPunc == "}") { 
     131        while (ctx.type == "statement") ctx = popContext(state); 
    134132        if (ctx.type == "}") ctx = popContext(state); 
    135         if (ctx.type == "statement") ctx = popContext(state); 
    136       } 
    137       else if (type == ctx.type) popContext(state); 
    138       else if (ctx.type == "}" || ctx.type == "top") pushContext(state, stream.column(), "statement"); 
     133        while (ctx.type == "statement") ctx = popContext(state); 
     134      } 
     135      else if (curPunc == ctx.type) popContext(state); 
     136      else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) 
     137        pushContext(state, stream.column(), "statement"); 
    139138      state.startOfLine = false; 
    140139      return style; 
     
    142141 
    143142    indent: function(state, textAfter) { 
    144       if (state.tokenize != tokenBase) return 0; 
    145       var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type; 
     143      if (state.tokenize == tokenComment) return CodeMirror.Pass; 
     144      if (state.tokenize != tokenBase && state.tokenize != null) return 0; 
     145      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); 
     146      if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; 
     147      var closing = firstChar == ctx.type; 
    146148      if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit); 
    147149      else if (ctx.align) return ctx.column + (closing ? 0 : 1); 
     
    154156 
    155157(function() { 
    156   function keywords(str) { 
     158  function words(str) { 
    157159    var obj = {}, words = str.split(" "); 
    158160    for (var i = 0; i < words.length; ++i) obj[words[i]] = true; 
     
    163165    "goto while enum void const signed volatile"; 
    164166 
    165   CodeMirror.defineMIME("text/x-csrc", { 
    166     name: "clike", 
    167     useCPP: true, 
    168     keywords: keywords(cKeywords) 
    169   }); 
    170   CodeMirror.defineMIME("text/x-c++src", { 
    171     name: "clike", 
    172     useCPP: true, 
    173     keywords: keywords(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " + 
    174                        "static_cast typeid catch false operator template typename class friend private " + 
    175                        "this using const_cast inline public throw virtual delete mutable protected true " + 
    176                        "wchar_t") 
     167  function cppHook(stream, state) { 
     168    if (!state.startOfLine) return false; 
     169    stream.skipToEnd(); 
     170    return "meta"; 
     171  } 
     172 
     173  // C#-style strings where "" escapes a quote. 
     174  function tokenAtString(stream, state) { 
     175    var next; 
     176    while ((next = stream.next()) != null) { 
     177      if (next == '"' && !stream.eat('"')) { 
     178        state.tokenize = null; 
     179        break; 
     180      } 
     181    } 
     182    return "string"; 
     183  } 
     184 
     185  function mimes(ms, mode) { 
     186    for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode); 
     187  } 
     188 
     189  mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], { 
     190    name: "clike", 
     191    keywords: words(cKeywords), 
     192    blockKeywords: words("case do else for if switch while struct"), 
     193    atoms: words("null"), 
     194    hooks: {"#": cppHook} 
     195  }); 
     196  mimes(["text/x-c++src", "text/x-c++hdr"], { 
     197    name: "clike", 
     198    keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " + 
     199                    "static_cast typeid catch operator template typename class friend private " + 
     200                    "this using const_cast inline public throw virtual delete mutable protected " + 
     201                    "wchar_t"), 
     202    blockKeywords: words("catch class do else finally for if struct switch try while"), 
     203    atoms: words("true false null"), 
     204    hooks: {"#": cppHook} 
    177205  }); 
    178206  CodeMirror.defineMIME("text/x-java", { 
    179207    name: "clike", 
    180     atAnnotations: true, 
    181     keywords: keywords("abstract assert boolean break byte case catch char class const continue default " +  
    182                        "do double else enum extends false final finally float for goto if implements import " + 
    183                        "instanceof int interface long native new null package private protected public " + 
    184                        "return short static strictfp super switch synchronized this throw throws transient " + 
    185                        "true try void volatile while") 
     208    keywords: words("abstract assert boolean break byte case catch char class const continue default " +  
     209                    "do double else enum extends final finally float for goto if implements import " + 
     210                    "instanceof int interface long native new package private protected public " + 
     211                    "return short static strictfp super switch synchronized this throw throws transient " + 
     212                    "try void volatile while"), 
     213    blockKeywords: words("catch class do else finally for if switch try while"), 
     214    atoms: words("true false null"), 
     215    hooks: { 
     216      "@": function(stream, state) { 
     217        stream.eatWhile(/[\w\$_]/); 
     218        return "meta"; 
     219      } 
     220    } 
     221  }); 
     222  CodeMirror.defineMIME("text/x-csharp", { 
     223    name: "clike", 
     224    keywords: words("abstract as base break case catch checked class const continue" +  
     225                    " default delegate do else enum event explicit extern finally fixed for" +  
     226                    " foreach goto if implicit in interface internal is lock namespace new" +  
     227                    " operator out override params private protected public readonly ref return sealed" +  
     228                    " sizeof stackalloc static struct switch this throw try typeof unchecked" +  
     229                    " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +  
     230                    " global group into join let orderby partial remove select set value var yield"), 
     231    blockKeywords: words("catch class do else finally for foreach if struct switch try while"), 
     232    builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" + 
     233                    " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" + 
     234                    " UInt64 bool byte char decimal double short int long object"  + 
     235                    " sbyte float string ushort uint ulong"), 
     236    atoms: words("true false null"), 
     237    hooks: { 
     238      "@": function(stream, state) { 
     239        if (stream.eat('"')) { 
     240          state.tokenize = tokenAtString; 
     241          return tokenAtString(stream, state); 
     242        } 
     243        stream.eatWhile(/[\w\$_]/); 
     244        return "meta"; 
     245      } 
     246    } 
     247  }); 
     248  CodeMirror.defineMIME("text/x-scala", { 
     249    name: "clike", 
     250    keywords: words( 
     251       
     252      /* scala */ 
     253      "abstract case catch class def do else extends false final finally for forSome if " + 
     254      "implicit import lazy match new null object override package private protected return " + 
     255      "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " + 
     256      "<% >: # @ " + 
     257                     
     258      /* package scala */ 
     259      "assert assume require print println printf readLine readBoolean readByte readShort " + 
     260      "readChar readInt readLong readFloat readDouble " + 
     261       
     262      "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + 
     263      "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " + 
     264      "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + 
     265      "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + 
     266      "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " + 
     267       
     268      /* package java.lang */             
     269      "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + 
     270      "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + 
     271      "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + 
     272      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" 
     273       
     274       
     275    ), 
     276    blockKeywords: words("catch class do else finally for forSome if match switch try while"), 
     277    atoms: words("true false null"), 
     278    hooks: { 
     279      "@": function(stream, state) { 
     280        stream.eatWhile(/[\w\$_]/); 
     281        return "meta"; 
     282      } 
     283    } 
    186284  }); 
    187285}()); 
  • advanced-code-editor/trunk/js/codemirror.js

    r566232 r607254  
    44 
    55// CodeMirror is the only global var we claim 
    6 var CodeMirror = (function() { 
     6window.CodeMirror = (function() { 
     7  "use strict"; 
    78  // This is the function that produces an editor instance. Its 
    89  // closure is used to store the editor state. 
     
    1415        options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; 
    1516 
     17    var input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em"); 
     18    input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); 
     19    // Wraps and hides input textarea 
     20    var inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); 
     21    // The empty scrollbar content, used solely for managing the scrollbar thumb. 
     22    var scrollbarInner = elt("div", null, "CodeMirror-scrollbar-inner"); 
     23    // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself. 
     24    var scrollbar = elt("div", [scrollbarInner], "CodeMirror-scrollbar"); 
     25    // DIVs containing the selection and the actual code 
     26    var lineDiv = elt("div"), selectionDiv = elt("div", null, null, "position: relative; z-index: -1"); 
     27    // Blinky cursor, and element used to ensure cursor fits at the end of a line 
     28    var cursor = elt("pre", "\u00a0", "CodeMirror-cursor"), widthForcer = elt("pre", "\u00a0", "CodeMirror-cursor", "visibility: hidden"); 
     29    // Used to measure text size 
     30    var measure = elt("div", null, null, "position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;"); 
     31    var lineSpace = elt("div", [measure, cursor, widthForcer, selectionDiv, lineDiv], null, "position: relative; z-index: 0"); 
     32    var gutterText = elt("div", null, "CodeMirror-gutter-text"), gutter = elt("div", [gutterText], "CodeMirror-gutter"); 
     33    // Moved around its parent to cover visible view 
     34    var mover = elt("div", [gutter, elt("div", [lineSpace], "CodeMirror-lines")], null, "position: relative"); 
     35    // Set to the height of the text, causes scrolling 
     36    var sizer = elt("div", [mover], null, "position: relative"); 
     37    // Provides scrolling 
     38    var scroller = elt("div", [sizer], "CodeMirror-scroll"); 
     39    scroller.setAttribute("tabIndex", "-1"); 
    1640    // The element in which the editor lives. 
    17     var wrapper = document.createElement("div"); 
    18     wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : ""); 
    19     // This mess creates the base DOM structure for the editor. 
    20     wrapper.innerHTML = 
    21       '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea 
    22         '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' + 
    23           'autocorrect="off" autocapitalize="off"></textarea></div>' + 
    24       '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself. 
    25         '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb. 
    26       '</div></div>' + // This must be before the scroll area because it's float-right. 
    27       '<div class="CodeMirror-scroll" tabindex="-1">' + 
    28         '<div style="position: relative">' + // Set to the height of the text, causes scrolling 
    29           '<div style="position: relative">' + // Moved around its parent to cover visible view 
    30             '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' + 
    31             // Provides positioning relative to (visible) text origin 
    32             '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' + 
    33               // Used to measure text size 
    34               '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;"></div>' + 
    35               '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor 
    36               '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width 
    37               '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code 
    38             '</div></div></div></div></div>'; 
     41    var wrapper = elt("div", [inputDiv, scrollbar, scroller], "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "")); 
    3942    if (place.appendChild) place.appendChild(wrapper); else place(wrapper); 
    40     // I've never seen more elegant code in my life. 
    41     var inputDiv = wrapper.firstChild, input = inputDiv.firstChild, 
    42         scroller = wrapper.lastChild, code = scroller.firstChild, 
    43         mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild, 
    44         lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild, 
    45         cursor = measure.nextSibling, widthForcer = cursor.nextSibling, 
    46         selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling, 
    47         scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild; 
     43 
    4844    themeChanged(); keyMapChanged(); 
    4945    // Needed to hide big blue blinking cursor on Mobile Safari 
     
    5753    if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute"; 
    5854 
    59     // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and  
    60     // make it overlap the content. (But we only do this if the scrollbar doesn't already 
    61     // have a natural width. If the mouse is plugged in or the user sets the system pref 
    62     // to always show scrollbars, the scrollbar shouldn't overlap.) 
    63     if (mac_geLion) { 
    64       scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap"); 
    65     } else if (ie_lt8) { 
    66       // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). 
    67       scrollbar.className += " cm-sb-ie7"; 
    68     } 
    69  
    70     // Check for problem with IE innerHTML not working when we have a 
    71     // P (or similar) parent node. 
    72     try { stringWidth("x"); } 
    73     catch (e) { 
    74       if (e.message.match(/runtime/i)) 
    75         e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)"); 
    76       throw e; 
    77     } 
     55    // Check for OS X >= 10.7. This has transparent scrollbars, so the 
     56    // overlaying of one scrollbar with another won't work. This is a 
     57    // temporary hack to simply turn off the overlay scrollbar. See 
     58    // issue #727. 
     59    if (mac_geLion) { scrollbar.style.zIndex = -2; scrollbar.style.visibility = "hidden"; } 
     60    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). 
     61    else if (ie_lt8) scrollbar.style.minWidth = "18px"; 
    7862 
    7963    // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval. 
     
    8165 
    8266    // mode holds a mode API object. doc is the tree of Line objects, 
    83     // work an array of lines that should be parsed, and history the 
    84     // undo history (instance of History constructor). 
    85     var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused; 
     67    // frontier is the point up to which the content has been parsed, 
     68    // and history the undo history (instance of History constructor). 
     69    var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), frontier = 0, focused; 
    8670    loadMode(); 
    8771    // The selection. These are always maintained to point at valid 
     
    9175    // Selection-related flags. shiftSelecting obviously tracks 
    9276    // whether the user is holding shift. 
    93     var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText, 
    94         overwrite = false, suppressEdits = false; 
     77    var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, draggingText, 
     78        overwrite = false, suppressEdits = false, pasteIncoming = false; 
    9579    // Variables used by startOperation/endOperation to track what 
    9680    // happened during the operation. 
    97     var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone, 
     81    var updateInput, userSelChange, changes, textChanged, selectionChanged, 
    9882        gutterDirty, callbacks; 
    9983    // Current visible range (may be bigger than the view window). 
     
    10488    // Tracks the maximum line length so that the horizontal scrollbar 
    10589    // can be kept static when scrolling. 
    106     var maxLine = "", updateMaxLine = false, maxLineChanged = true; 
    107     var tabCache = {}; 
     90    var maxLine = getLine(0), updateMaxLine = false, maxLineChanged = true; 
     91    var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll 
     92    var goalColumn = null; 
    10893 
    10994    // Initialize the content. 
     
    119104    // handled in onMouseDown for Gecko. 
    120105    if (!gecko) connect(scroller, "contextmenu", onContextMenu); 
    121     connect(scroller, "scroll", onScroll); 
    122     connect(scrollbar, "scroll", onScroll); 
    123     connect(scrollbar, "mousedown", function() {setTimeout(focusInput, 0);}); 
    124     connect(scroller, "mousewheel", onMouseWheel); 
    125     connect(scroller, "DOMMouseScroll", onMouseWheel); 
    126     connect(window, "resize", function() {updateDisplay(true);}); 
     106    connect(scroller, "scroll", onScrollMain); 
     107    connect(scrollbar, "scroll", onScrollBar); 
     108    connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);}); 
     109    var resizeHandler = connect(window, "resize", function() { 
     110      if (wrapper.parentNode) updateDisplay(true); 
     111      else resizeHandler(); 
     112    }, true); 
    127113    connect(input, "keyup", operation(onKeyUp)); 
    128114    connect(input, "input", fastPoll); 
     
    132118    connect(input, "blur", onBlur); 
    133119 
     120    function drag_(e) { 
     121      if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return; 
     122      e_stop(e); 
     123    } 
    134124    if (options.dragDrop) { 
    135125      connect(scroller, "dragstart", onDragStart); 
    136       function drag_(e) { 
    137         if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return; 
    138         e_stop(e); 
    139       } 
    140126      connect(scroller, "dragenter", drag_); 
    141127      connect(scroller, "dragover", drag_); 
     
    143129    } 
    144130    connect(scroller, "paste", function(){focusInput(); fastPoll();}); 
    145     connect(input, "paste", fastPoll); 
     131    connect(input, "paste", function(){pasteIncoming = true; fastPoll();}); 
    146132    connect(input, "cut", operation(function(){ 
    147133      if (!options.readOnly) replaceSelection(""); 
     
    149135 
    150136    // Needed to handle Tab key in KHTML 
    151     if (khtml) connect(code, "mouseup", function() { 
     137    if (khtml) connect(sizer, "mouseup", function() { 
    152138        if (document.activeElement == input) input.blur(); 
    153139        focusInput(); 
     
    182168        else if (option == "tabSize") updateDisplay(true); 
    183169        else if (option == "keyMap") keyMapChanged(); 
    184         if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") { 
     170        else if (option == "tabindex") input.tabIndex = value; 
     171        if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || 
     172            option == "theme" || option == "lineNumberFormatter") { 
    185173          gutterChanged(); 
    186174          updateDisplay(true); 
     
    188176      }, 
    189177      getOption: function(option) {return options[option];}, 
     178      getMode: function() {return mode;}, 
    190179      undo: operation(undo), 
    191180      redo: operation(redo), 
     
    200189      historySize: function() {return {undo: history.done.length, redo: history.undone.length};}, 
    201190      clearHistory: function() {history = new History();}, 
     191      setHistory: function(histData) { 
     192        history = new History(); 
     193        history.done = histData.done; 
     194        history.undone = histData.undone; 
     195      }, 
     196      getHistory: function() { 
     197        function cp(arr) { 
     198          for (var i = 0, nw = [], nwelt; i < arr.length; ++i) { 
     199            nw.push(nwelt = []); 
     200            for (var j = 0, elt = arr[i]; j < elt.length; ++j) { 
     201              var old = [], cur = elt[j]; 
     202              nwelt.push({start: cur.start, added: cur.added, old: old}); 
     203              for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k])); 
     204            } 
     205          } 
     206          return nw; 
     207        } 
     208        return {done: cp(history.done), undone: cp(history.undone)}; 
     209      }, 
    202210      matchBrackets: operation(function(){matchBrackets(true);}), 
    203211      getTokenAt: operation(function(pos) { 
    204212        pos = clipPos(pos); 
    205         return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch); 
     213        return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), options.tabSize, pos.ch); 
    206214      }), 
    207215      getStateAfter: function(line) { 
     
    240248      }, 
    241249      lineInfo: lineInfo, 
     250      getViewport: function() { return {from: showingFrom, to: showingTo};}, 
    242251      addWidget: function(pos, node, scroll, vert, horiz) { 
    243252        pos = localCoords(clipPos(pos)); 
    244253        var top = pos.yBot, left = pos.x; 
    245254        node.style.position = "absolute"; 
    246         code.appendChild(node); 
     255        sizer.appendChild(node); 
    247256        if (vert == "over") top = pos.y; 
    248257        else if (vert == "near") { 
    249258          var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()), 
    250               hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft(); 
     259              hspace = Math.max(sizer.clientWidth, lineSpace.clientWidth) - paddingLeft(); 
    251260          if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight) 
    252261            top = pos.y - node.offsetHeight; 
     
    257266        node.style.left = node.style.right = ""; 
    258267        if (horiz == "right") { 
    259           left = code.clientWidth - node.offsetWidth; 
     268          left = sizer.clientWidth - node.offsetWidth; 
    260269          node.style.right = "0px"; 
    261270        } else { 
    262271          if (horiz == "left") left = 0; 
    263           else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2; 
     272          else if (horiz == "middle") left = (sizer.clientWidth - node.offsetWidth) / 2; 
    264273          node.style.left = (left + paddingLeft()) + "px"; 
    265274        } 
     
    291300      }), 
    292301      replaceRange: operation(replaceRange), 
    293       getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));}, 
     302      getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);}, 
    294303 
    295304      triggerOnKeyDown: operation(onKeyDown), 
     
    329338      scrollTo: function(x, y) { 
    330339        if (x != null) scroller.scrollLeft = x; 
    331         if (y != null) scrollbar.scrollTop = y; 
     340        if (y != null) scrollbar.scrollTop = scroller.scrollTop = y; 
    332341        updateDisplay([]); 
    333342      }, 
     
    336345                height: scrollbar.scrollHeight, width: scroller.scrollWidth}; 
    337346      }, 
     347      setSize: function(width, height) { 
     348        function interpret(val) { 
     349          val = String(val); 
     350          return /^\d+$/.test(val) ? val + "px" : val; 
     351        } 
     352        if (width != null) wrapper.style.width = interpret(width); 
     353        if (height != null) scroller.style.height = interpret(height); 
     354        instance.refresh(); 
     355      }, 
    338356 
    339357      operation: function(f){return operation(f)();}, 
    340358      compoundChange: function(f){return compoundChange(f);}, 
    341359      refresh: function(){ 
    342         updateDisplay(true); 
     360        updateDisplay(true, null, lastScrollTop); 
    343361        if (scrollbar.scrollHeight > lastScrollTop) 
    344362          scrollbar.scrollTop = lastScrollTop; 
     
    357375    } 
    358376 
     377    function lineContent(line, wrapAt) { 
     378      if (!line.styles) 
     379        line.highlight(mode, line.stateAfter = getStateBefore(lineNo(line)), options.tabSize); 
     380      return line.getContent(options.tabSize, wrapAt, options.lineWrapping); 
     381    } 
     382 
    359383    function setValue(code) { 
    360384      var top = {line: 0, ch: 0}; 
     
    363387      updateInput = true; 
    364388    } 
    365     function getValue() { 
     389    function getValue(lineSep) { 
    366390      var text = []; 
    367391      doc.iter(0, doc.size, function(line) { text.push(line.text); }); 
    368       return text.join("\n"); 
    369     } 
    370  
    371     function onScroll(e) { 
    372       if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) { 
    373         lastScrollTop = scrollbar.scrollTop; 
    374         lastScrollLeft = scroller.scrollLeft; 
     392      return text.join(lineSep || "\n"); 
     393    } 
     394 
     395    function onScrollBar(e) { 
     396      if (scrollbar.scrollTop != lastScrollTop) { 
     397        lastScrollTop = scroller.scrollTop = scrollbar.scrollTop; 
    375398        updateDisplay([]); 
    376         if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px"; 
    377         if (options.onScroll) options.onScroll(instance); 
    378       } 
     399      } 
     400    } 
     401 
     402    function onScrollMain(e) { 
     403      if (options.fixedGutter && gutter.style.left != scroller.scrollLeft + "px") 
     404        gutter.style.left = scroller.scrollLeft + "px"; 
     405      if (scroller.scrollTop != lastScrollTop) { 
     406        lastScrollTop = scroller.scrollTop; 
     407        if (scrollbar.scrollTop != lastScrollTop) 
     408          scrollbar.scrollTop = lastScrollTop; 
     409        updateDisplay([]); 
     410      } 
     411      if (options.onScroll) options.onScroll(instance); 
    379412    } 
    380413 
     
    383416      // Check whether this is a click in a widget 
    384417      for (var n = e_target(e); n != wrapper; n = n.parentNode) 
    385         if (n.parentNode == code && n != mover) return; 
     418        if (n.parentNode == sizer && n != mover) return; 
    386419 
    387420      // See if this is a click in the gutter 
     
    397430      switch (e_button(e)) { 
    398431      case 3: 
    399         if (gecko && !mac) onContextMenu(e); 
     432        if (gecko) onContextMenu(e); 
    400433        return; 
    401434      case 2: 
     
    412445      if (!focused) onFocus(); 
    413446 
    414       var now = +new Date; 
     447      var now = +new Date, type = "single"; 
    415448      if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { 
     449        type = "triple"; 
    416450        e_preventDefault(e); 
    417451        setTimeout(focusInput, 20); 
    418         return selectLine(start.line); 
     452        selectLine(start.line); 
    419453      } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) { 
     454        type = "double"; 
    420455        lastDoubleClick = {time: now, pos: start}; 
    421456        e_preventDefault(e); 
    422         return selectWordAt(start); 
     457        var word = findWordAt(start); 
     458        setSelectionUser(word.from, word.to); 
    423459      } else { lastClick = {time: now, pos: start}; } 
    424460 
     461      function dragEnd(e2) { 
     462        if (webkit) scroller.draggable = false; 
     463        draggingText = false; 
     464        up(); drop(); 
     465        if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { 
     466          e_preventDefault(e2); 
     467          setCursor(start.line, start.ch, true); 
     468          focusInput(); 
     469        } 
     470      } 
    425471      var last = start, going; 
    426472      if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) && 
    427           !posLess(start, sel.from) && !posLess(sel.to, start)) { 
     473          !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") { 
    428474        // Let the drag handler handle this. 
    429475        if (webkit) scroller.draggable = true; 
    430         function dragEnd(e2) { 
    431           if (webkit) scroller.draggable = false; 
    432           draggingText = false; 
    433           up(); drop(); 
    434           if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { 
    435             e_preventDefault(e2); 
    436             setCursor(start.line, start.ch, true); 
    437             focusInput(); 
    438           } 
    439         } 
    440476        var up = connect(document, "mouseup", operation(dragEnd), true); 
    441477        var drop = connect(scroller, "drop", operation(dragEnd), true); 
     
    446482      } 
    447483      e_preventDefault(e); 
    448       setCursor(start.line, start.ch, true); 
     484      if (type == "single") setCursor(start.line, start.ch, true); 
     485 
     486      var startstart = sel.from, startend = sel.to; 
     487 
     488      function doSelect(cur) { 
     489        if (type == "single") { 
     490          setSelectionUser(start, cur); 
     491        } else if (type == "double") { 
     492          var word = findWordAt(cur); 
     493          if (posLess(cur, startstart)) setSelectionUser(word.from, startend); 
     494          else setSelectionUser(startstart, word.to); 
     495        } else if (type == "triple") { 
     496          if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0})); 
     497          else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0})); 
     498        } 
     499      } 
    449500 
    450501      function extend(e) { 
     
    453504          if (!focused) onFocus(); 
    454505          last = cur; 
    455           setSelectionUser(start, cur); 
     506          doSelect(cur); 
    456507          updateInput = false; 
    457508          var visible = visibleLines(); 
     
    464515        clearTimeout(going); 
    465516        var cur = posFromMouse(e); 
    466         if (cur) setSelectionUser(start, cur); 
     517        if (cur) doSelect(cur); 
    467518        e_preventDefault(e); 
    468519        focusInput(); 
     
    481532      for (var n = e_target(e); n != wrapper; n = n.parentNode) 
    482533        if (n.parentNode == gutterText) return e_preventDefault(e); 
    483       var start = posFromMouse(e); 
    484       if (!start) return; 
    485       lastDoubleClick = {time: +new Date, pos: start}; 
    486534      e_preventDefault(e); 
    487       selectWordAt(start); 
    488535    } 
    489536    function onDrop(e) { 
    490537      if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return; 
    491       e.preventDefault(); 
     538      e_preventDefault(e); 
    492539      var pos = posFromMouse(e, true), files = e.dataTransfer.files; 
    493540      if (!pos || options.readOnly) return; 
    494541      if (files && files.length && window.FileReader && window.File) { 
    495         function loadFile(file, i) { 
     542        var n = files.length, text = Array(n), read = 0; 
     543        var loadFile = function(file, i) { 
    496544          var reader = new FileReader; 
    497545          reader.onload = function() { 
     
    506554          }; 
    507555          reader.readAsText(file); 
    508         } 
    509         var n = files.length, text = Array(n), read = 0; 
     556        }; 
    510557        for (var i = 0; i < n; ++i) loadFile(files[i], i); 
    511558      } else { 
     
    530577      var txt = getSelection(); 
    531578      e.dataTransfer.setData("Text", txt); 
    532        
     579 
    533580      // Use dummy image instead of default browsers image. 
    534       if (gecko || chrome || opera) { 
    535         var img = document.createElement('img'); 
    536         img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image 
    537         e.dataTransfer.setDragImage(img, 0, 0); 
    538       } 
     581      if (e.dataTransfer.setDragImage) 
     582        e.dataTransfer.setDragImage(elt('img'), 0, 0); 
    539583    } 
    540584 
     
    558602      return true; 
    559603    } 
     604    var maybeTransition; 
    560605    function handleKeyBinding(e) { 
    561606      // Handle auto keymap transitions 
     
    569614 
    570615      var name = keyNames[e_prop(e, "keyCode")], handled = false; 
     616      var flipCtrlCmd = opera && mac; 
    571617      if (name == null || e.altGraphKey) return false; 
    572618      if (e_prop(e, "altKey")) name = "Alt-" + name; 
    573       if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name; 
    574       if (e_prop(e, "metaKey")) name = "Cmd-" + name; 
     619      if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name; 
     620      if (e_prop(e, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name; 
    575621 
    576622      var stopped = false; 
     
    604650    } 
    605651 
    606     var lastStoppedKey = null, maybeTransition; 
     652    var lastStoppedKey = null; 
    607653    function onKeyDown(e) { 
    608654      if (!focused) onFocus(); 
     
    648694        if (scroller.className.search(/\bCodeMirror-focused\b/) == -1) 
    649695          scroller.className += " CodeMirror-focused"; 
    650         if (!leaveInputAlone) resetInput(true); 
    651696      } 
    652697      slowPoll(); 
     
    667712    } 
    668713 
    669     function chopDelta(delta) { 
    670       // Make sure we always scroll a little bit for any nonzero delta. 
    671       if (delta > 0.0 && delta < 1.0) return 1; 
    672       else if (delta > -1.0 && delta < 0.0) return -1; 
    673       else return Math.round(delta); 
    674     } 
    675  
    676     function onMouseWheel(e) { 
    677       var deltaX = 0, deltaY = 0; 
    678       if (e.type == "DOMMouseScroll") { // Firefox 
    679         var delta = -e.detail * 8.0; 
    680         if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta; 
    681         else if (e.axis == e.VERTICAL_AXIS) deltaY = delta; 
    682       } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit 
    683         deltaX = e.wheelDeltaX / 3.0; 
    684         deltaY = e.wheelDeltaY / 3.0; 
    685       } else if (e.wheelDelta !== undefined) { // IE or Opera 
    686         deltaY = e.wheelDelta / 3.0; 
    687       } 
    688  
    689       var scrolled = false; 
    690       deltaX = chopDelta(deltaX); 
    691       deltaY = chopDelta(deltaY); 
    692       if ((deltaX > 0 && scroller.scrollLeft > 0) || 
    693           (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) { 
    694         scroller.scrollLeft -= deltaX; 
    695         scrolled = true; 
    696       } 
    697       if ((deltaY > 0 && scrollbar.scrollTop > 0) || 
    698           (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) { 
    699         scrollbar.scrollTop -= deltaY; 
    700         scrolled = true; 
    701       } 
    702       if (scrolled) e_stop(e); 
    703     } 
    704  
    705714    // Replace the range from from to to by the strings in newText. 
    706715    // Afterwards, set the selection to selFrom, selTo. 
    707716    function updateLines(from, to, newText, selFrom, selTo) { 
    708717      if (suppressEdits) return; 
     718      var old = []; 
     719      doc.iter(from.line, to.line + 1, function(line) { 
     720        old.push(newHL(line.text, line.markedSpans)); 
     721      }); 
    709722      if (history) { 
    710         var old = []; 
    711         doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); }); 
    712723        history.addChange(from.line, newText.length, old); 
    713724        while (history.done.length > options.undoDepth) history.done.shift(); 
    714725      } 
    715       updateLinesNoUndo(from, to, newText, selFrom, selTo); 
     726      var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText); 
     727      updateLinesNoUndo(from, to, lines, selFrom, selTo); 
    716728    } 
    717729    function unredoHelper(from, to) { 
     
    721733        var change = set[i]; 
    722734        var replaced = [], end = change.start + change.added; 
    723         doc.iter(change.start, end, function(line) { replaced.push(line.text); }); 
     735        doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); }); 
    724736        out.push({start: change.start, added: change.old.length, old: replaced}); 
    725737        var pos = {line: change.start + change.old.length - 1, 
    726                    ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])}; 
    727         updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos); 
     738                   ch: editEnd(hlText(lst(replaced)), hlText(lst(change.old)))}; 
     739        updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, 
     740                          change.old, pos, pos); 
    728741      } 
    729742      updateInput = true; 
     
    733746    function redo() {unredoHelper(history.undone, history.done);} 
    734747 
    735     function updateLinesNoUndo(from, to, newText, selFrom, selTo) { 
     748    function updateLinesNoUndo(from, to, lines, selFrom, selTo) { 
    736749      if (suppressEdits) return; 
    737       var recomputeMaxLength = false, maxLineLength = maxLine.length; 
     750      var recomputeMaxLength = false, maxLineLength = maxLine.text.length; 
    738751      if (!options.lineWrapping) 
    739752        doc.iter(from.line, to.line + 1, function(line) { 
    740753          if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;} 
    741754        }); 
    742       if (from.line != to.line || newText.length > 1) gutterDirty = true; 
     755      if (from.line != to.line || lines.length > 1) gutterDirty = true; 
    743756 
    744757      var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line); 
    745       // First adjust the line structure, taking some care to leave highlighting intact. 
    746       if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") { 
     758      var lastHL = lst(lines); 
     759 
     760      // First adjust the line structure 
     761      if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") { 
    747762        // This is a whole-line replace. Treated specially to make 
    748763        // sure line objects move the way they are supposed to. 
    749764        var added = [], prevLine = null; 
    750         if (from.line) { 
    751           prevLine = getLine(from.line - 1); 
    752           prevLine.fixMarkEnds(lastLine); 
    753         } else lastLine.fixMarkStarts(); 
    754         for (var i = 0, e = newText.length - 1; i < e; ++i) 
    755           added.push(Line.inheritMarks(newText[i], prevLine)); 
     765        for (var i = 0, e = lines.length - 1; i < e; ++i) 
     766          added.push(new Line(hlText(lines[i]), hlSpans(lines[i]))); 
     767        lastLine.update(lastLine.text, hlSpans(lastHL)); 
    756768        if (nlines) doc.remove(from.line, nlines, callbacks); 
    757769        if (added.length) doc.insert(from.line, added); 
    758770      } else if (firstLine == lastLine) { 
    759         if (newText.length == 1) 
    760           firstLine.replace(from.ch, to.ch, newText[0]); 
    761         else { 
    762           lastLine = firstLine.split(to.ch, newText[newText.length-1]); 
    763           firstLine.replace(from.ch, null, newText[0]); 
    764           firstLine.fixMarkEnds(lastLine); 
    765           var added = []; 
    766           for (var i = 1, e = newText.length - 1; i < e; ++i) 
    767             added.push(Line.inheritMarks(newText[i], firstLine)); 
    768           added.push(lastLine); 
     771        if (lines.length == 1) { 
     772          firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + firstLine.text.slice(to.ch), hlSpans(lines[0])); 
     773        } else { 
     774          for (var added = [], i = 1, e = lines.length - 1; i < e; ++i) 
     775            added.push(new Line(hlText(lines[i]), hlSpans(lines[i]))); 
     776          added.push(new Line(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL))); 
     777          firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0])); 
    769778          doc.insert(from.line + 1, added); 
    770779        } 
    771       } else if (newText.length == 1) { 
    772         firstLine.replace(from.ch, null, newText[0]); 
    773         lastLine.replace(null, to.ch, ""); 
    774         firstLine.append(lastLine); 
     780      } else if (lines.length == 1) { 
     781        firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + lastLine.text.slice(to.ch), hlSpans(lines[0])); 
    775782        doc.remove(from.line + 1, nlines, callbacks); 
    776783      } else { 
    777784        var added = []; 
    778         firstLine.replace(from.ch, null, newText[0]); 
    779         lastLine.replace(null, to.ch, newText[newText.length-1]); 
    780         firstLine.fixMarkEnds(lastLine); 
    781         for (var i = 1, e = newText.length - 1; i < e; ++i) 
    782           added.push(Line.inheritMarks(newText[i], firstLine)); 
     785        firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0])); 
     786        lastLine.update(hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL)); 
     787        for (var i = 1, e = lines.length - 1; i < e; ++i) 
     788          added.push(new Line(hlText(lines[i]), hlSpans(lines[i]))); 
    783789        if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks); 
    784790        doc.insert(from.line + 1, added); 
     
    786792      if (options.lineWrapping) { 
    787793        var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3); 
    788         doc.iter(from.line, from.line + newText.length, function(line) { 
     794        doc.iter(from.line, from.line + lines.length, function(line) { 
    789795          if (line.hidden) return; 
    790796          var guess = Math.ceil(line.text.length / perLine) || 1; 
     
    792798        }); 
    793799      } else { 
    794         doc.iter(from.line, from.line + newText.length, function(line) { 
     800        doc.iter(from.line, from.line + lines.length, function(line) { 
    795801          var l = line.text; 
    796802          if (!line.hidden && l.length > maxLineLength) { 
    797             maxLine = l; maxLineLength = l.length; maxLineChanged = true; 
     803            maxLine = line; maxLineLength = l.length; maxLineChanged = true; 
    798804            recomputeMaxLength = false; 
    799805          } 
     
    802808      } 
    803809 
    804       // Add these lines to the work array, so that they will be 
    805       // highlighted. Adjust work lines if lines were added/removed. 
    806       var newWork = [], lendiff = newText.length - nlines - 1; 
    807       for (var i = 0, l = work.length; i < l; ++i) { 
    808         var task = work[i]; 
    809         if (task < from.line) newWork.push(task); 
    810         else if (task > to.line) newWork.push(task + lendiff); 
    811       } 
    812       var hlEnd = from.line + Math.min(newText.length, 500); 
    813       highlightLines(from.line, hlEnd); 
    814       newWork.push(hlEnd); 
    815       work = newWork; 
    816       startWorker(100); 
     810      // Adjust frontier, schedule worker 
     811      frontier = Math.min(frontier, from.line); 
     812      startWorker(400); 
     813 
     814      var lendiff = lines.length - nlines - 1; 
    817815      // Remember that these lines changed, for updating the display 
    818816      changes.push({from: from.line, to: to.line + 1, diff: lendiff}); 
    819       var changeObj = {from: from, to: to, text: newText}; 
    820       if (textChanged) { 
    821         for (var cur = textChanged; cur.next; cur = cur.next) {} 
    822         cur.next = changeObj; 
    823       } else textChanged = changeObj; 
     817      if (options.onChange) { 
     818        // Normalize lines to contain only strings, since that's what 
     819        // the change event handler expects 
     820        for (var i = 0; i < lines.length; ++i) 
     821          if (typeof lines[i] != "string") lines[i] = lines[i].text; 
     822        var changeObj = {from: from, to: to, text: lines}; 
     823        if (textChanged) { 
     824          for (var cur = textChanged; cur.next; cur = cur.next) {} 
     825          cur.next = changeObj; 
     826        } else textChanged = changeObj; 
     827      } 
    824828 
    825829      // Update the selection 
     
    829833    } 
    830834 
     835    function needsScrollbar() { 
     836      var realHeight = doc.height * textHeight() + 2 * paddingTop(); 
     837      return realHeight * .99 > scroller.offsetHeight ? realHeight : false; 
     838    } 
     839 
    831840    function updateVerticalScroll(scrollTop) { 
    832       var th = textHeight(), virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight; 
    833       scrollbar.style.height = scrollbarHeight + "px"; 
    834       if (scroller.clientHeight) 
    835         scrollbarInner.style.height = virtualHeight + "px"; 
     841      var scrollHeight = needsScrollbar(); 
     842      scrollbar.style.display = scrollHeight ? "block" : "none"; 
     843      if (scrollHeight) { 
     844        scrollbarInner.style.height = sizer.style.minHeight = scrollHeight + "px"; 
     845        scrollbar.style.height = scroller.clientHeight + "px"; 
     846        if (scrollTop != null) { 
     847          scrollbar.scrollTop = scroller.scrollTop = scrollTop; 
     848          // 'Nudge' the scrollbar to work around a Webkit bug where, 
     849          // in some situations, we'd end up with a scrollbar that 
     850          // reported its scrollTop (and looked) as expected, but 
     851          // *behaved* as if it was still in a previous state (i.e. 
     852          // couldn't scroll up, even though it appeared to be at the 
     853          // bottom). 
     854          if (webkit) setTimeout(function() { 
     855            if (scrollbar.scrollTop != scrollTop) return; 
     856            scrollbar.scrollTop = scrollTop + (scrollTop ? -1 : 1); 
     857            scrollbar.scrollTop = scrollTop; 
     858          }, 0); 
     859        } 
     860      } else { 
     861        sizer.style.minHeight = ""; 
     862      } 
    836863      // Position the mover div to align with the current virtual scroll position 
    837       if (scrollTop != null) scrollbar.scrollTop = scrollTop; 
    838       mover.style.top = (displayOffset * th - scrollbar.scrollTop) + "px"; 
    839       scrollbar.style.display = (virtualHeight > scrollbarHeight) ? "block" : "none"; 
    840     } 
    841    
    842     // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring  
    843     // the width of a div with a scrollbar in it. If the width is <= 1, then 
    844     // the mouse isn't plugged in and scrollbars should overlap the content. 
    845     function overlapScrollbars() { 
    846       var tmpSb = document.createElement('div'), 
    847           tmpSbInner = document.createElement('div'); 
    848       tmpSb.className = "CodeMirror-scrollbar"; 
    849       tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;"; 
    850       tmpSbInner.className = "CodeMirror-scrollbar-inner"; 
    851       tmpSbInner.style.height = "200px"; 
    852       tmpSb.appendChild(tmpSbInner); 
    853  
    854       document.body.appendChild(tmpSb); 
    855       var result = (tmpSb.offsetWidth <= 1); 
    856       document.body.removeChild(tmpSb); 
    857       return result; 
     864      mover.style.top = displayOffset * textHeight() + "px"; 
    858865    } 
    859866 
    860867    function computeMaxLength() { 
    861       var maxLineLength = 0;  
    862       maxLine = ""; maxLineChanged = true; 
    863       doc.iter(0, doc.size, function(line) { 
     868      maxLine = getLine(0); maxLineChanged = true; 
     869      var maxLineLength = maxLine.text.length; 
     870      doc.iter(1, doc.size, function(line) { 
    864871        var l = line.text; 
    865872        if (!line.hidden && l.length > maxLineLength) { 
    866           maxLineLength = l.length; maxLine = l; 
     873          maxLineLength = l.length; maxLine = line; 
    867874        } 
    868875      }); 
     
    880887        var ch = pos.ch; 
    881888        if (pos.line == to.line) 
    882           ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0)); 
     889          ch += lst(code).length - (to.ch - (to.line == from.line ? from.ch : 0)); 
    883890        return {line: line, ch: ch}; 
    884891      } 
     
    898905    } 
    899906    function replaceRange1(code, from, to, computeSel) { 
    900       var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length; 
     907      var endch = code.length == 1 ? code[0].length + from.ch : lst(code).length; 
    901908      var newSel = computeSel({line: from.line + code.length - 1, ch: endch}); 
    902909      updateLines(from, to, code, newSel.from, newSel.to); 
    903910    } 
    904911 
    905     function getRange(from, to) { 
     912    function getRange(from, to, lineSep) { 
    906913      var l1 = from.line, l2 = to.line; 
    907914      if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch); 
     
    909916      doc.iter(l1 + 1, l2, function(line) { code.push(line.text); }); 
    910917      code.push(getLine(l2).text.slice(0, to.ch)); 
    911       return code.join("\n"); 
    912     } 
    913     function getSelection() { 
    914       return getRange(sel.from, sel.to); 
    915     } 
    916  
    917     var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll 
     918      return code.join(lineSep || "\n"); 
     919    } 
     920    function getSelection(lineSep) { 
     921      return getRange(sel.from, sel.to, lineSep); 
     922    } 
     923 
    918924    function slowPoll() { 
    919925      if (pollingFast) return; 
    920926      poll.set(options.pollInterval, function() { 
    921         startOperation(); 
    922927        readInput(); 
    923928        if (focused) slowPoll(); 
    924         endOperation(); 
    925929      }); 
    926930    } 
     
    929933      pollingFast = true; 
    930934      function p() { 
    931         startOperation(); 
    932935        var changed = readInput(); 
    933936        if (!changed && !missed) {missed = true; poll.set(60, p);} 
    934937        else {pollingFast = false; slowPoll();} 
    935         endOperation(); 
    936938      } 
    937939      poll.set(20, p); 
     
    945947    var prevInput = ""; 
    946948    function readInput() { 
    947       if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false; 
     949      if (!focused || hasSelection(input) || options.readOnly) return false; 
    948950      var text = input.value; 
    949951      if (text == prevInput) return false; 
     952      if (!nestedOperation) startOperation(); 
    950953      shiftSelecting = null; 
    951954      var same = 0, l = Math.min(prevInput.length, text.length); 
     
    953956      if (same < prevInput.length) 
    954957        sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)}; 
    955       else if (overwrite && posEq(sel.from, sel.to)) 
     958      else if (overwrite && posEq(sel.from, sel.to) && !pasteIncoming) 
    956959        sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))}; 
    957960      replaceSelection(text.slice(same), "end"); 
    958961      if (text.length > 1000) { input.value = prevInput = ""; } 
    959962      else prevInput = text; 
     963      if (!nestedOperation) endOperation(); 
     964      pasteIncoming = false; 
    960965      return true; 
    961966    } 
     
    964969        prevInput = ""; 
    965970        input.value = getSelection(); 
    966         selectInput(input); 
     971        if (focused) selectInput(input); 
    967972      } else if (user) prevInput = input.value = ""; 
    968973    } 
     
    972977    } 
    973978 
    974     function scrollEditorIntoView() { 
    975       if (!cursor.getBoundingClientRect) return; 
    976       var rect = cursor.getBoundingClientRect(); 
    977       // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden 
    978       if (ie && rect.top == rect.bottom) return; 
    979       var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); 
    980       if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView(); 
    981     } 
    982979    function scrollCursorIntoView() { 
    983980      var coords = calculateCursorCoords(); 
    984       return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot); 
     981      scrollIntoView(coords.x, coords.y, coords.x, coords.yBot); 
     982      if (!focused) return; 
     983      var box = sizer.getBoundingClientRect(), doScroll = null; 
     984      if (coords.y + box.top < 0) doScroll = true; 
     985      else if (coords.y + box.top + textHeight() > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; 
     986      if (doScroll != null) { 
     987        var hidden = cursor.style.display == "none"; 
     988        if (hidden) { 
     989          cursor.style.display = ""; 
     990          cursor.style.left = coords.x + "px"; 
     991          cursor.style.top = (coords.y - displayOffset) + "px"; 
     992        } 
     993        cursor.scrollIntoView(doScroll); 
     994        if (hidden) cursor.style.display = "none"; 
     995      } 
    985996    } 
    986997    function calculateCursorCoords() { 
     
    9901001    } 
    9911002    function scrollIntoView(x1, y1, x2, y2) { 
    992       var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false; 
    993       if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;} 
    994       if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;} 
    995       if (scrolled && options.onScroll) options.onScroll(instance); 
     1003      var scrollPos = calculateScrollPos(x1, y1, x2, y2); 
     1004      if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft;} 
     1005      if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scroller.scrollTop = scrollPos.scrollTop;} 
    9961006    } 
    9971007    function calculateScrollPos(x1, y1, x2, y2) { 
     
    9991009      y1 += pt; y2 += pt; x1 += pl; x2 += pl; 
    10001010      var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {}; 
    1001       var atTop = y1 < paddingTop() + 10; 
     1011      var docBottom = needsScrollbar() || Infinity; 
     1012      var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10; 
    10021013      if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1); 
    1003       else if (y2 > screentop + screen) result.scrollTop = y2 - screen; 
     1014      else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen; 
    10041015 
    10051016      var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft; 
     
    10711082      // resized or the font size changes. 
    10721083      if (different) lastSizeC = scroller.clientHeight + th; 
     1084      if (from != showingFrom || to != showingTo && options.onViewportChange) 
     1085        setTimeout(function(){ 
     1086          if (options.onViewportChange) options.onViewportChange(instance, from, to); 
     1087        }); 
    10731088      showingFrom = from; showingTo = to; 
    10741089      displayOffset = heightAtLine(doc, from); 
     1090      startWorker(100); 
    10751091 
    10761092      // Since this is all rather error prone, it is honoured with the 
     
    10831099        var curNode = lineDiv.firstChild, heightChanged = false; 
    10841100        doc.iter(showingFrom, showingTo, function(line) { 
     1101          // Work around bizarro IE7 bug where, sometimes, our curNode 
     1102          // is magically replaced with a new node in the DOM, leaving 
     1103          // us with a reference to an orphan (nextSibling-less) node. 
     1104          if (!curNode) return; 
    10851105          if (!line.hidden) { 
    10861106            var height = Math.round(curNode.offsetHeight / th) || 1; 
     
    10951115      } 
    10961116 
    1097       if (options.lineWrapping) { 
    1098         // Guess whether we're going to need the scrollbar, so that we don't end up changing the linewrapping 
    1099         // after the scrollbar appears (during updateVerticalScroll()). Only do this if the scrollbar is 
    1100         // appearing (if it's disappearing, we don't have to worry about the scroll position, and there are 
    1101         // issues on IE7 if we turn it off too early). 
    1102         var virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight; 
    1103         if (virtualHeight > scrollbarHeight) scrollbar.style.display = "block"; 
    1104         checkHeights(); 
    1105       } 
     1117      if (options.lineWrapping) checkHeights(); 
    11061118 
    11071119      gutter.style.display = gutterDisplay; 
     
    11101122        updateGutter() && options.lineWrapping && checkHeights() && updateGutter(); 
    11111123      } 
     1124      updateVerticalScroll(scrollTop); 
    11121125      updateSelection(); 
    1113       updateVerticalScroll(scrollTop); 
    11141126      if (!suppressCallback && options.onUpdate) options.onUpdate(instance); 
    11151127      return true; 
     
    11401152 
    11411153    function patchDisplay(from, to, intact) { 
     1154      function killNode(node) { 
     1155        var tmp = node.nextSibling; 
     1156        node.parentNode.removeChild(node); 
     1157        return tmp; 
     1158      } 
    11421159      // The first pass removes the DOM nodes that aren't intact. 
    1143       if (!intact.length) lineDiv.innerHTML = ""; 
     1160      if (!intact.length) removeChildren(lineDiv); 
    11441161      else { 
    1145         function killNode(node) { 
    1146           var tmp = node.nextSibling; 
    1147           node.parentNode.removeChild(node); 
    1148           return tmp; 
    1149         } 
    11501162        var domPos = 0, curNode = lineDiv.firstChild, n; 
    11511163        for (var i = 0; i < intact.length; ++i) { 
     
    11581170      // This pass fills in the lines that actually changed. 
    11591171      var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from; 
    1160       var scratch = document.createElement("div"); 
    11611172      doc.iter(from, to, function(line) { 
    11621173        if (nextIntact && nextIntact.to == j) nextIntact = intact.shift(); 
    11631174        if (!nextIntact || nextIntact.from > j) { 
    1164           if (line.hidden) var html = scratch.innerHTML = "<pre></pre>"; 
     1175          if (line.hidden) var lineElement = elt("pre"); 
    11651176          else { 
    1166             var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>' 
    1167               + line.getHTML(makeTab) + '</pre>'; 
     1177            var lineElement = lineContent(line); 
     1178            if (line.className) lineElement.className = line.className; 
    11681179            // Kludge to make sure the styled element lies behind the selection (by z-index) 
    1169             if (line.bgClassName) 
    1170               html = '<div style="position: relative"><pre class="' + line.bgClassName + 
    1171               '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>"; 
     1180            if (line.bgClassName) { 
     1181              var pre = elt("pre", "\u00a0", line.bgClassName, "position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2"); 
     1182              lineElement = elt("div", [pre, lineElement], null, "position: relative"); 
     1183            } 
    11721184          } 
    1173           scratch.innerHTML = html; 
    1174           lineDiv.insertBefore(scratch.firstChild, curNode); 
     1185          lineDiv.insertBefore(lineElement, curNode); 
    11751186        } else { 
    11761187          curNode = curNode.nextSibling; 
     
    11841195      var hText = mover.offsetHeight, hEditor = scroller.clientHeight; 
    11851196      gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px"; 
    1186       var html = [], i = showingFrom, normalNode; 
     1197      var fragment = document.createDocumentFragment(), i = showingFrom, normalNode; 
    11871198      doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) { 
    11881199        if (line.hidden) { 
    1189           html.push("<pre></pre>"); 
     1200          fragment.appendChild(elt("pre")); 
    11901201        } else { 
    11911202          var marker = line.gutterMarker; 
    1192           var text = options.lineNumbers ? i + options.firstLineNumber : null; 
     1203          var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null; 
    11931204          if (marker && marker.text) 
    11941205            text = marker.text.replace("%N%", text != null ? text : ""); 
    11951206          else if (text == null) 
    11961207            text = "\u00a0"; 
    1197           html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text); 
    1198           for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;"); 
    1199           html.push("</pre>"); 
     1208          var markerElement = fragment.appendChild(elt("pre", null, marker && marker.style)); 
     1209          markerElement.innerHTML = text; 
     1210          for (var j = 1; j < line.height; ++j) { 
     1211            markerElement.appendChild(elt("br")); 
     1212            markerElement.appendChild(document.createTextNode("\u00a0")); 
     1213          } 
    12001214          if (!marker) normalNode = i; 
    12011215        } 
     
    12031217      }); 
    12041218      gutter.style.display = "none"; 
    1205       gutterText.innerHTML = html.join(""); 
     1219      removeChildrenAndAdd(gutterText, fragment); 
    12061220      // Make sure scrolling doesn't cause number gutter size to pop 
    12071221      if (normalNode != null && options.lineNumbers) { 
     
    12311245        selectionDiv.style.display = "none"; 
    12321246      } else { 
    1233         var sameLine = fromPos.y == toPos.y, html = ""; 
     1247        var sameLine = fromPos.y == toPos.y, fragment = document.createDocumentFragment(); 
    12341248        var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth; 
    12351249        var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight; 
    1236         function add(left, top, right, height) { 
     1250        var add = function(left, top, right, height) { 
    12371251          var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px" 
    12381252                                  : "right: " + right + "px"; 
    1239           html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left + 
    1240             'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>'; 
    1241         } 
     1253          fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + 
     1254                                   "px; top: " + top + "px; " + rstyle + "; height: " + height + "px")); 
     1255        }; 
    12421256        if (sel.from.ch && fromPos.y >= 0) { 
    12431257          var right = sameLine ? clientWidth - toPos.x : 0; 
     
    12501264        if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th) 
    12511265          add(0, toPos.y, clientWidth - toPos.x, th); 
    1252         selectionDiv.innerHTML = html; 
     1266        removeChildrenAndAdd(selectionDiv, fragment); 
    12531267        cursor.style.display = "none"; 
    12541268        selectionDiv.style.display = ""; 
     
    13821396      userSelChange = true; 
    13831397    } 
    1384     var goalColumn = null; 
    13851398    function moveV(dir, unit) { 
    13861399      var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true); 
    13871400      if (goalColumn != null) pos.x = goalColumn; 
    1388       if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight); 
    1389       else if (unit == "line") dist = textHeight(); 
    1390       var target = coordsChar(pos.x, pos.y + dist * dir + 2); 
     1401      if (unit == "page") { 
     1402        var screen = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight); 
     1403        var target = coordsChar(pos.x, pos.y + screen * dir); 
     1404      } else if (unit == "line") { 
     1405        var th = textHeight(); 
     1406        var target = coordsChar(pos.x, pos.y + .5 * th + dir * th); 
     1407      } 
    13911408      if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y; 
    13921409      setCursor(target.line, target.ch, true); 
     
    13941411    } 
    13951412 
    1396     function selectWordAt(pos) { 
     1413    function findWordAt(pos) { 
    13971414      var line = getLine(pos.line).text; 
    13981415      var start = pos.ch, end = pos.ch; 
    1399       while (start > 0 && isWordChar(line.charAt(start - 1))) --start; 
    1400       while (end < line.length && isWordChar(line.charAt(end))) ++end; 
    1401       setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end}); 
     1416      if (line) { 
     1417        if (pos.after === false || end == line.length) --start; else ++end; 
     1418        var startChar = line.charAt(start); 
     1419        var check = isWordChar(startChar) ? isWordChar : 
     1420                    /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} : 
     1421                    function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; 
     1422        while (start > 0 && check(line.charAt(start - 1))) --start; 
     1423        while (end < line.length && check(line.charAt(end))) ++end; 
     1424      } 
     1425      return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}}; 
    14021426    } 
    14031427    function selectLine(line) { 
     
    14321456      var diff = indentation - curSpace; 
    14331457 
    1434       if (!diff) { 
    1435         if (sel.from.line != n && sel.to.line != n) return; 
    1436         var indentString = curSpaceString; 
    1437       } else { 
    1438         var indentString = "", pos = 0; 
    1439         if (options.indentWithTabs) 
    1440           for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";} 
    1441         while (pos < indentation) {++pos; indentString += " ";} 
    1442       } 
    1443  
    1444       replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}); 
     1458      var indentString = "", pos = 0; 
     1459      if (options.indentWithTabs) 
     1460        for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";} 
     1461      if (pos < indentation) indentString += spaceStr(indentation - pos); 
     1462 
     1463      if (indentString != curSpaceString) 
     1464        replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}); 
     1465      line.stateAfter = null; 
    14451466    } 
    14461467 
     
    14481469      mode = CodeMirror.getMode(options, options.mode); 
    14491470      doc.iter(0, doc.size, function(line) { line.stateAfter = null; }); 
    1450       work = [0]; 
    1451       startWorker(); 
     1471      frontier = 0; 
     1472      startWorker(100); 
    14521473    } 
    14531474    function gutterChanged() { 
     
    14661487          if (guess != 1) updateLineHeight(line, guess); 
    14671488        }); 
    1468         lineSpace.style.width = code.style.width = ""; 
    1469         widthForcer.style.left = ""; 
     1489        lineSpace.style.minWidth = widthForcer.style.left = ""; 
    14701490      } else { 
    14711491        wrapper.className = wrapper.className.replace(" CodeMirror-wrap", ""); 
    1472         maxLine = ""; maxLineChanged = true; 
     1492        computeMaxLength(); 
    14731493        doc.iter(0, doc.size, function(line) { 
    14741494          if (line.height != 1 && !line.hidden) updateLineHeight(line, 1); 
    1475           if (line.text.length > maxLine.length) maxLine = line.text; 
    14761495        }); 
    14771496      } 
    14781497      changes.push({from: 0, to: doc.size}); 
    1479     } 
    1480     function makeTab(col) { 
    1481       var w = options.tabSize - col % options.tabSize, cached = tabCache[w]; 
    1482       if (cached) return cached; 
    1483       for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " "; 
    1484       return (tabCache[w] = {html: str + "</span>", width: w}); 
    14851498    } 
    14861499    function themeChanged() { 
     
    14941507    } 
    14951508 
    1496     function TextMarker() { this.set = []; } 
     1509    function TextMarker(type, style) { this.lines = []; this.type = type; if (style) this.style = style; } 
    14971510    TextMarker.prototype.clear = operation(function() { 
    14981511      var min = Infinity, max = -Infinity; 
    1499       for (var i = 0, e = this.set.length; i < e; ++i) { 
    1500         var line = this.set[i], mk = line.marked; 
    1501         if (!mk || !line.parent) continue; 
    1502         var lineN = lineNo(line); 
    1503         min = Math.min(min, lineN); max = Math.max(max, lineN); 
    1504         for (var j = 0; j < mk.length; ++j) 
    1505           if (mk[j].marker == this) mk.splice(j--, 1); 
     1512      for (var i = 0; i < this.lines.length; ++i) { 
     1513        var line = this.lines[i]; 
     1514        var span = getMarkedSpanFor(line.markedSpans, this, true); 
     1515        if (span.from != null || span.to != null) { 
     1516          var lineN = lineNo(line); 
     1517          min = Math.min(min, lineN); max = Math.max(max, lineN); 
     1518        } 
    15061519      } 
    15071520      if (min != Infinity) 
    15081521        changes.push({from: min, to: max + 1}); 
     1522      this.lines.length = 0; 
    15091523    }); 
    15101524    TextMarker.prototype.find = function() { 
    15111525      var from, to; 
    1512       for (var i = 0, e = this.set.length; i < e; ++i) { 
    1513         var line = this.set[i], mk = line.marked; 
    1514         for (var j = 0; j < mk.length; ++j) { 
    1515           var mark = mk[j]; 
    1516           if (mark.marker == this) { 
    1517             if (mark.from != null || mark.to != null) { 
    1518               var found = lineNo(line); 
    1519               if (found != null) { 
    1520                 if (mark.from != null) from = {line: found, ch: mark.from}; 
    1521                 if (mark.to != null) to = {line: found, ch: mark.to}; 
    1522               } 
    1523             } 
    1524           } 
    1525         } 
    1526       } 
    1527       return {from: from, to: to}; 
     1526      for (var i = 0; i < this.lines.length; ++i) { 
     1527        var line = this.lines[i]; 
     1528        var span = getMarkedSpanFor(line.markedSpans, this); 
     1529        if (span.from != null || span.to != null) { 
     1530          var found = lineNo(line); 
     1531          if (span.from != null) from = {line: found, ch: span.from}; 
     1532          if (span.to != null) to = {line: found, ch: span.to}; 
     1533        } 
     1534      } 
     1535      if (this.type == "bookmark") return from; 
     1536      return from && {from: from, to: to}; 
    15281537    }; 
    15291538 
    1530     function markText(from, to, className) { 
     1539    function markText(from, to, className, options) { 
    15311540      from = clipPos(from); to = clipPos(to); 
    1532       var tm = new TextMarker(); 
    1533       if (!posLess(from, to)) return tm; 
    1534       function add(line, from, to, className) { 
    1535         getLine(line).addMark(new MarkedText(from, to, className, tm)); 
    1536       } 
    1537       if (from.line == to.line) add(from.line, from.ch, to.ch, className); 
    1538       else { 
    1539         add(from.line, from.ch, null, className); 
    1540         for (var i = from.line + 1, e = to.line; i < e; ++i) 
    1541           add(i, null, null, className); 
    1542         add(to.line, null, to.ch, className); 
    1543       } 
     1541      var marker = new TextMarker("range", className); 
     1542      if (options) for (var opt in options) if (options.hasOwnProperty(opt)) 
     1543        marker[opt] = options[opt]; 
     1544      var curLine = from.line; 
     1545      doc.iter(curLine, to.line + 1, function(line) { 
     1546        var span = {from: curLine == from.line ? from.ch : null, 
     1547                    to: curLine == to.line ? to.ch : null, 
     1548                    marker: marker}; 
     1549        (line.markedSpans || (line.markedSpans = [])).push(span); 
     1550        marker.lines.push(line); 
     1551        ++curLine; 
     1552      }); 
    15441553      changes.push({from: from.line, to: to.line + 1}); 
    1545       return tm; 
     1554      return marker; 
    15461555    } 
    15471556 
    15481557    function setBookmark(pos) { 
    15491558      pos = clipPos(pos); 
    1550       var bm = new Bookmark(pos.ch); 
    1551       getLine(pos.line).addMark(bm); 
    1552       return bm; 
     1559      var marker = new TextMarker("bookmark"), line = getLine(pos.line); 
     1560      var span = {from: pos.ch, to: pos.ch, marker: marker}; 
     1561      (line.markedSpans || (line.markedSpans = [])).push(span); 
     1562      marker.lines.push(line); 
     1563      return marker; 
    15531564    } 
    15541565 
    15551566    function findMarksAt(pos) { 
    15561567      pos = clipPos(pos); 
    1557       var markers = [], marked = getLine(pos.line).marked; 
    1558       if (!marked) return markers; 
    1559       for (var i = 0, e = marked.length; i < e; ++i) { 
    1560         var m = marked[i]; 
    1561         if ((m.from == null || m.from <= pos.ch) && 
    1562             (m.to == null || m.to >= pos.ch)) 
    1563           markers.push(m.marker || m); 
     1568      var markers = [], spans = getLine(pos.line).markedSpans; 
     1569      if (spans) for (var i = 0; i < spans.length; ++i) { 
     1570        var span = spans[i]; 
     1571        if ((span.from == null || span.from <= pos.ch) && 
     1572            (span.to == null || span.to >= pos.ch)) 
     1573          markers.push(span.marker); 
    15641574      } 
    15651575      return markers; 
     
    16011611          line.hidden = hidden; 
    16021612          if (!options.lineWrapping) { 
    1603             var l = line.text; 
    1604             if (hidden && l.length == maxLine.length) { 
     1613            if (hidden && line.text.length == maxLine.text.length) { 
    16051614              updateMaxLine = true; 
    1606             } else if (!hidden && l.length > maxLine.length) { 
    1607               maxLine = l; maxWidth = null; updateMaxLine = false; 
     1615            } else if (!hidden && line.text.length > maxLine.text.length) { 
     1616              maxLine = line; updateMaxLine = false; 
    16081617            } 
    16091618          } 
     
    16371646    } 
    16381647 
    1639     function stringWidth(str) { 
    1640       measure.innerHTML = "<pre><span>x</span></pre>"; 
    1641       measure.firstChild.firstChild.firstChild.nodeValue = str; 
    1642       return measure.firstChild.firstChild.offsetWidth || 10; 
    1643     } 
    1644     // These are used to go from pixel positions to character 
    1645     // positions, taking varying character widths into account. 
    1646     function charFromX(line, x) { 
    1647       if (x <= 0) return 0; 
    1648       var lineObj = getLine(line), text = lineObj.text; 
    1649       function getX(len) { 
    1650         return measureLine(lineObj, len).left; 
    1651       } 
    1652       var from = 0, fromX = 0, to = text.length, toX; 
    1653       // Guess a suitable upper bound for our search. 
    1654       var estimated = Math.min(to, Math.ceil(x / charWidth())); 
    1655       for (;;) { 
    1656         var estX = getX(estimated); 
    1657         if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2)); 
    1658         else {toX = estX; to = estimated; break;} 
    1659       } 
    1660       if (x > toX) return to; 
    1661       // Try to guess a suitable lower bound as well. 
    1662       estimated = Math.floor(to * 0.8); estX = getX(estimated); 
    1663       if (estX < x) {from = estimated; fromX = estX;} 
    1664       // Do a binary search between these bounds. 
    1665       for (;;) { 
    1666         if (to - from <= 1) return (toX - x > x - fromX) ? from : to; 
    1667         var middle = Math.ceil((from + to) / 2), middleX = getX(middle); 
    1668         if (middleX > x) {to = middle; toX = middleX;} 
    1669         else {from = middle; fromX = middleX;} 
    1670       } 
    1671     } 
    1672  
    1673     var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16); 
    16741648    function measureLine(line, ch) { 
    16751649      if (ch == 0) return {top: 0, left: 0}; 
    16761650      var wbr = options.lineWrapping && ch < line.text.length && 
    16771651                spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1)); 
    1678       measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>"; 
    1679       var elt = document.getElementById(tempId); 
    1680       var top = elt.offsetTop, left = elt.offsetLeft; 
     1652      var pre = lineContent(line, ch); 
     1653      removeChildrenAndAdd(measure, pre); 
     1654      var anchor = pre.anchor; 
     1655      var top = anchor.offsetTop, left = anchor.offsetLeft; 
    16811656      // Older IEs report zero offsets for spans directly after a wrap 
    16821657      if (ie && top == 0 && left == 0) { 
    1683         var backup = document.createElement("span"); 
    1684         backup.innerHTML = "x"; 
    1685         elt.parentNode.insertBefore(backup, elt.nextSibling); 
     1658        var backup = elt("span", "x"); 
     1659        anchor.parentNode.insertBefore(backup, anchor.nextSibling); 
    16861660        top = backup.offsetTop; 
    16871661      } 
     
    17001674    // Coords must be lineSpace-local 
    17011675    function coordsChar(x, y) { 
    1702       if (y < 0) y = 0; 
    17031676      var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th); 
     1677      if (heightPos < 0) return {line: 0, ch: 0}; 
    17041678      var lineNo = lineAtHeight(doc, heightPos); 
    17051679      if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length}; 
     
    17071681      var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0; 
    17081682      if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0}; 
     1683      var wrongLine = false; 
    17091684      function getX(len) { 
    17101685        var sp = measureLine(lineObj, len); 
    17111686        if (tw) { 
    17121687          var off = Math.round(sp.top / th); 
     1688          wrongLine = off != innerOff; 
    17131689          return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth); 
    17141690        } 
     
    17291705      // Do a binary search between these bounds. 
    17301706      for (;;) { 
    1731         if (to - from <= 1) return {line: lineNo, ch: (toX - x > x - fromX) ? from : to}; 
     1707        if (to - from <= 1) { 
     1708          var after = x - fromX < toX - x; 
     1709          return {line: lineNo, ch: after ? from : to, after: after}; 
     1710        } 
    17321711        var middle = Math.ceil((from + to) / 2), middleX = getX(middle); 
    1733         if (middleX > x) {to = middle; toX = middleX;} 
     1712        if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; } 
    17341713        else {from = middle; fromX = middleX;} 
    17351714      } 
     
    17401719    } 
    17411720 
    1742     var cachedHeight, cachedHeightFor, measureText; 
     1721    var cachedHeight, cachedHeightFor, measurePre; 
    17431722    function textHeight() { 
    1744       if (measureText == null) { 
    1745         measureText = "<pre>"; 
    1746         for (var i = 0; i < 49; ++i) measureText += "x<br/>"; 
    1747         measureText += "x</pre>"; 
     1723      if (measurePre == null) { 
     1724        measurePre = elt("pre"); 
     1725        for (var i = 0; i < 49; ++i) { 
     1726          measurePre.appendChild(document.createTextNode("x")); 
     1727          measurePre.appendChild(elt("br")); 
     1728        } 
     1729        measurePre.appendChild(document.createTextNode("x")); 
    17481730      } 
    17491731      var offsetHeight = lineDiv.clientHeight; 
    17501732      if (offsetHeight == cachedHeightFor) return cachedHeight; 
    17511733      cachedHeightFor = offsetHeight; 
    1752       measure.innerHTML = measureText; 
     1734      removeChildrenAndAdd(measure, measurePre.cloneNode(true)); 
    17531735      cachedHeight = measure.firstChild.offsetHeight / 50 || 1; 
    1754       measure.innerHTML = ""; 
     1736      removeChildren(measure); 
    17551737      return cachedHeight; 
    17561738    } 
     
    17591741      if (scroller.clientWidth == cachedWidthFor) return cachedWidth; 
    17601742      cachedWidthFor = scroller.clientWidth; 
    1761       return (cachedWidth = stringWidth("x")); 
     1743      var anchor = elt("span", "x"); 
     1744      var pre = elt("pre", [anchor]); 
     1745      removeChildrenAndAdd(measure, pre); 
     1746      return (cachedWidth = anchor.offsetWidth || 10); 
    17621747    } 
    17631748    function paddingTop() {return lineSpace.offsetTop;} 
     
    17761761      return coordsChar(x - offL.left, y - offL.top); 
    17771762    } 
     1763    var detectingSelectAll; 
    17781764    function onContextMenu(e) { 
    17791765      var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop; 
     
    17871773        "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " + 
    17881774        "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; 
    1789       leaveInputAlone = true; 
    1790       var val = input.value = getSelection(); 
    17911775      focusInput(); 
    1792       selectInput(input); 
     1776      resetInput(true); 
     1777      // Adds "Select all" to context menu in FF 
     1778      if (posEq(sel.from, sel.to)) input.value = prevInput = " "; 
     1779 
    17931780      function rehide() { 
    1794         var newVal = splitLines(input.value).join("\n"); 
    1795         if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end"); 
    17961781        inputDiv.style.position = "relative"; 
    17971782        input.style.cssText = oldCSS; 
    17981783        if (ie_lt9) scrollbar.scrollTop = scrollPos; 
    1799         leaveInputAlone = false; 
    1800         resetInput(true); 
    18011784        slowPoll(); 
     1785 
     1786        // Try to detect the user choosing select-all  
     1787        if (input.selectionStart != null) { 
     1788          clearTimeout(detectingSelectAll); 
     1789          var extval = input.value = " " + (posEq(sel.from, sel.to) ? "" : input.value), i = 0; 
     1790          prevInput = " "; 
     1791          input.selectionStart = 1; input.selectionEnd = extval.length; 
     1792          detectingSelectAll = setTimeout(function poll(){ 
     1793            if (prevInput == " " && input.selectionStart == 0) 
     1794              operation(commands.selectAll)(instance); 
     1795            else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500); 
     1796            else resetInput(); 
     1797          }, 200); 
     1798        } 
    18021799      } 
    18031800 
     
    18201817      blinker = setInterval(function() { 
    18211818        cursor.style.visibility = (on = !on) ? "" : "hidden"; 
    1822       }, 650); 
     1819      }, options.cursorBlinkRate); 
    18231820    } 
    18241821 
     
    18831880    } 
    18841881    function getStateBefore(n) { 
    1885       var start = findStartLine(n), state = start && getLine(start-1).stateAfter; 
     1882      var pos = findStartLine(n), state = pos && getLine(pos-1).stateAfter; 
    18861883      if (!state) state = startState(mode); 
    18871884      else state = copyState(mode, state); 
    1888       doc.iter(start, n, function(line) { 
    1889         line.highlight(mode, state, options.tabSize); 
    1890         line.stateAfter = copyState(mode, state); 
     1885      doc.iter(pos, n, function(line) { 
     1886        line.process(mode, state, options.tabSize); 
     1887        line.stateAfter = (pos == n - 1 || pos % 5 == 0) ? copyState(mode, state) : null; 
    18911888      }); 
    1892       if (start < n) changes.push({from: start, to: n}); 
    1893       if (n < doc.size && !getLine(n).stateAfter) work.push(n); 
    18941889      return state; 
    18951890    } 
    1896     function highlightLines(start, end) { 
    1897       var state = getStateBefore(start); 
    1898       doc.iter(start, end, function(line) { 
    1899         line.highlight(mode, state, options.tabSize); 
    1900         line.stateAfter = copyState(mode, state); 
     1891    function highlightWorker() { 
     1892      if (frontier >= showingTo) return; 
     1893      var end = +new Date + options.workTime, state = copyState(mode, getStateBefore(frontier)); 
     1894      var startFrontier = frontier; 
     1895      doc.iter(frontier, showingTo, function(line) { 
     1896        if (frontier >= showingFrom) { // Visible 
     1897          line.highlight(mode, state, options.tabSize); 
     1898          line.stateAfter = copyState(mode, state); 
     1899        } else { 
     1900          line.process(mode, state, options.tabSize); 
     1901          line.stateAfter = frontier % 5 == 0 ? copyState(mode, state) : null; 
     1902        } 
     1903        ++frontier; 
     1904        if (+new Date > end) { 
     1905          startWorker(options.workDelay); 
     1906          return true; 
     1907        } 
    19011908      }); 
    1902     } 
    1903     function highlightWorker() { 
    1904       var end = +new Date + options.workTime; 
    1905       var foundWork = work.length; 
    1906       while (work.length) { 
    1907         if (!getLine(showingFrom).stateAfter) var task = showingFrom; 
    1908         else var task = work.pop(); 
    1909         if (task >= doc.size) continue; 
    1910         var start = findStartLine(task), state = start && getLine(start-1).stateAfter; 
    1911         if (state) state = copyState(mode, state); 
    1912         else state = startState(mode); 
    1913  
    1914         var unchanged = 0, compare = mode.compareStates, realChange = false, 
    1915             i = start, bail = false; 
    1916         doc.iter(i, doc.size, function(line) { 
    1917           var hadState = line.stateAfter; 
    1918           if (+new Date > end) { 
    1919             work.push(i); 
    1920             startWorker(options.workDelay); 
    1921             if (realChange) changes.push({from: task, to: i + 1}); 
    1922             return (bail = true); 
    1923           } 
    1924           var changed = line.highlight(mode, state, options.tabSize); 
    1925           if (changed) realChange = true; 
    1926           line.stateAfter = copyState(mode, state); 
    1927           var done = null; 
    1928           if (compare) { 
    1929             var same = hadState && compare(hadState, state); 
    1930             if (same != Pass) done = !!same; 
    1931           } 
    1932           if (done == null) { 
    1933             if (changed !== false || !hadState) unchanged = 0; 
    1934             else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, ""))) 
    1935               done = true; 
    1936           } 
    1937           if (done) return true; 
    1938           ++i; 
    1939         }); 
    1940         if (bail) return; 
    1941         if (realChange) changes.push({from: task, to: i + 1}); 
    1942       } 
    1943       if (foundWork && options.onHighlightComplete) 
    1944         options.onHighlightComplete(instance); 
     1909      if (showingTo > startFrontier && frontier >= showingFrom) 
     1910        operation(function() {changes.push({from: startFrontier, to: frontier});})(); 
    19451911    } 
    19461912    function startWorker(time) { 
    1947       if (!work.length) return; 
    1948       highlight.set(time, operation(highlightWorker)); 
     1913      if (frontier < showingTo) 
     1914        highlight.set(time, highlightWorker); 
    19491915    } 
    19501916 
     
    19601926      if (updateMaxLine) computeMaxLength(); 
    19611927      if (maxLineChanged && !options.lineWrapping) { 
    1962         widthForcer.style.left = stringWidth(maxLine) + "px"; 
     1928        var cursorWidth = widthForcer.offsetWidth, left = measureLine(maxLine, maxLine.text.length).left; 
     1929        if (!ie_lt8) { 
     1930          widthForcer.style.left = left + "px"; 
     1931          lineSpace.style.minWidth = (left + cursorWidth) + "px"; 
     1932        } 
    19631933        maxLineChanged = false; 
    19641934      } 
     
    19681938        newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot); 
    19691939      } 
    1970       if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null)); 
    1971       else { 
     1940      if (changes.length || newScrollPos && newScrollPos.scrollTop != null) 
     1941        updated = updateDisplay(changes, true, newScrollPos && newScrollPos.scrollTop); 
     1942      if (!updated) { 
    19721943        if (selectionChanged) updateSelection(); 
    19731944        if (gutterDirty) updateGutter(); 
    19741945      } 
    19751946      if (newScrollPos) scrollCursorIntoView(); 
    1976       if (selectionChanged) {scrollEditorIntoView(); restartBlink();} 
    1977  
    1978       if (focused && !leaveInputAlone && 
    1979           (updateInput === true || (updateInput !== false && selectionChanged))) 
     1947      if (selectionChanged) restartBlink(); 
     1948 
     1949      if (focused && (updateInput === true || (updateInput !== false && selectionChanged))) 
    19801950        resetInput(userSelChange); 
    19811951 
     
    20392009    onChange: null, 
    20402010    onCursorActivity: null, 
     2011    onViewportChange: null, 
    20412012    onGutterClick: null, 
    2042     onHighlightComplete: null, 
    20432013    onUpdate: null, 
    20442014    onFocus: null, onBlur: null, onScroll: null, 
    20452015    matchBrackets: false, 
     2016    cursorBlinkRate: 530, 
    20462017    workTime: 100, 
    20472018    workDelay: 200, 
     
    20492020    undoDepth: 40, 
    20502021    tabindex: null, 
    2051     autofocus: null 
     2022    autofocus: null, 
     2023    lineNumberFormatter: function(integer) { return integer; } 
    20522024  }; 
    20532025 
     
    20812053    var mfactory = modes[spec.name]; 
    20822054    if (!mfactory) return CodeMirror.getMode(options, "text/plain"); 
    2083     return mfactory(options, spec); 
     2055    var modeObj = mfactory(options, spec); 
     2056    if (modeExtensions.hasOwnProperty(spec.name)) { 
     2057      var exts = modeExtensions[spec.name]; 
     2058      for (var prop in exts) if (exts.hasOwnProperty(prop)) modeObj[prop] = exts[prop]; 
     2059    } 
     2060    modeObj.name = spec.name; 
     2061    return modeObj; 
    20842062  }; 
    20852063  CodeMirror.listModes = function() { 
     
    20992077  CodeMirror.defineExtension = function(name, func) { 
    21002078    extensions[name] = func; 
     2079  }; 
     2080 
     2081  var modeExtensions = CodeMirror.modeExtensions = {}; 
     2082  CodeMirror.extendMode = function(mode, properties) { 
     2083    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); 
     2084    for (var prop in properties) if (properties.hasOwnProperty(prop)) 
     2085      exts[prop] = properties[prop]; 
    21012086  }; 
    21022087 
     
    21982183      map = getKeyMap(map); 
    21992184      var found = map[name]; 
     2185      if (found === false) { 
     2186        if (stop) stop(); 
     2187        return true; 
     2188      } 
    22002189      if (found != null && handle(found)) return true; 
    22012190      if (map.nofallthrough) { 
     
    22192208    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; 
    22202209  } 
     2210  CodeMirror.isModifierKey = isModifierKey; 
    22212211 
    22222212  CodeMirror.fromTextArea = function(textarea, options) { 
     
    22252215    if (!options.tabindex && textarea.tabindex) 
    22262216      options.tabindex = textarea.tabindex; 
    2227     if (options.autofocus == null && textarea.getAttribute("autofocus") != null) 
    2228       options.autofocus = true; 
     2217    // Set autofocus to true if this textarea is focused, or if it has 
     2218    // autofocus and no other element is focused. 
     2219    if (options.autofocus == null) { 
     2220      var hasFocus = document.body; 
     2221      // doc.activeElement occasionally throws on IE 
     2222      try { hasFocus = document.activeElement; } catch(e) {} 
     2223      options.autofocus = hasFocus == textarea || 
     2224        textarea.getAttribute("autofocus") != null && hasFocus == document.body; 
     2225    } 
    22292226 
    22302227    function save() {textarea.value = instance.getValue();} 
     
    22342231      if (typeof textarea.form.submit == "function") { 
    22352232        var realSubmit = textarea.form.submit; 
    2236         function wrappedSubmit() { 
     2233        textarea.form.submit = function wrappedSubmit() { 
    22372234          save(); 
    22382235          textarea.form.submit = realSubmit; 
    22392236          textarea.form.submit(); 
    22402237          textarea.form.submit = wrappedSubmit; 
    2241         } 
    2242         textarea.form.submit = wrappedSubmit; 
     2238        }; 
    22432239      } 
    22442240    } 
     
    22632259  }; 
    22642260 
     2261  var gecko = /gecko\/\d{7}/i.test(navigator.userAgent); 
     2262  var ie = /MSIE \d/.test(navigator.userAgent); 
     2263  var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent); 
     2264  var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent); 
     2265  var quirksMode = ie && document.documentMode == 5; 
     2266  var webkit = /WebKit\//.test(navigator.userAgent); 
     2267  var chrome = /Chrome\//.test(navigator.userAgent); 
     2268  var opera = /Opera\//.test(navigator.userAgent); 
     2269  var safari = /Apple Computer/.test(navigator.vendor); 
     2270  var khtml = /KHTML\//.test(navigator.userAgent); 
     2271  var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent); 
     2272 
    22652273  // Utility functions for working with state. Exported because modes 
    22662274  // sometimes need to do this. 
     
    22812289  } 
    22822290  CodeMirror.startState = startState; 
     2291  CodeMirror.innerMode = function(mode, state) { 
     2292    while (mode.innerMode) { 
     2293      var info = mode.innerMode(state); 
     2294      state = info.state; 
     2295      mode = info.mode; 
     2296    } 
     2297    return info || {mode: mode, state: state}; 
     2298  }; 
    22832299 
    22842300  // The character stream used by a mode's parser. 
     
    22912307    eol: function() {return this.pos >= this.string.length;}, 
    22922308    sol: function() {return this.pos == 0;}, 
    2293     peek: function() {return this.string.charAt(this.pos);}, 
     2309    peek: function() {return this.string.charAt(this.pos) || undefined;}, 
    22942310    next: function() { 
    22952311      if (this.pos < this.string.length) 
     
    23222338    match: function(pattern, consume, caseInsensitive) { 
    23232339      if (typeof pattern == "string") { 
    2324         function cased(str) {return caseInsensitive ? str.toLowerCase() : str;} 
     2340        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; 
    23252341        if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { 
    23262342          if (consume !== false) this.pos += pattern.length; 
     
    23292345      } else { 
    23302346        var match = this.string.slice(this.pos).match(pattern); 
     2347        if (match && match.index > 0) return null; 
    23312348        if (match && consume !== false) this.pos += match[0].length; 
    23322349        return match; 
     
    23372354  CodeMirror.StringStream = StringStream; 
    23382355 
    2339   function MarkedText(from, to, className, marker) { 
    2340     this.from = from; this.to = to; this.style = className; this.marker = marker; 
    2341   } 
    2342   MarkedText.prototype = { 
    2343     attach: function(line) { this.marker.set.push(line); }, 
    2344     detach: function(line) { 
    2345       var ix = indexOf(this.marker.set, line); 
    2346       if (ix > -1) this.marker.set.splice(ix, 1); 
    2347     }, 
    2348     split: function(pos, lenBefore) { 
    2349       if (this.to <= pos && this.to != null) return null; 
    2350       var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore; 
    2351       var to = this.to == null ? null : this.to - pos + lenBefore; 
    2352       return new MarkedText(from, to, this.style, this.marker); 
    2353     }, 
    2354     dup: function() { return new MarkedText(null, null, this.style, this.marker); }, 
    2355     clipTo: function(fromOpen, from, toOpen, to, diff) { 
    2356       if (fromOpen && to > this.from && (to < this.to || this.to == null)) 
    2357         this.from = null; 
    2358       else if (this.from != null && this.from >= from) 
    2359         this.from = Math.max(to, this.from) + diff; 
    2360       if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null)) 
    2361         this.to = null; 
    2362       else if (this.to != null && this.to > from) 
    2363         this.to = to < this.to ? this.to + diff : from; 
    2364     }, 
    2365     isDead: function() { return this.from != null && this.to != null && this.from >= this.to; }, 
    2366     sameSet: function(x) { return this.marker == x.marker; } 
    2367   }; 
    2368  
    2369   function Bookmark(pos) { 
    2370     this.from = pos; this.to = pos; this.line = null; 
    2371   } 
    2372   Bookmark.prototype = { 
    2373     attach: function(line) { this.line = line; }, 
    2374     detach: function(line) { if (this.line == line) this.line = null; }, 
    2375     split: function(pos, lenBefore) { 
    2376       if (pos < this.from) { 
    2377         this.from = this.to = (this.from - pos) + lenBefore; 
    2378         return this; 
    2379       } 
    2380     }, 
    2381     isDead: function() { return this.from > this.to; }, 
    2382     clipTo: function(fromOpen, from, toOpen, to, diff) { 
    2383       if ((fromOpen || from < this.from) && (toOpen || to > this.to)) { 
    2384         this.from = 0; this.to = -1; 
    2385       } else if (this.from > from) { 
    2386         this.from = this.to = Math.max(to, this.from) + diff; 
    2387       } 
    2388     }, 
    2389     sameSet: function(x) { return false; }, 
    2390     find: function() { 
    2391       if (!this.line || !this.line.parent) return null; 
    2392       return {line: lineNo(this.line), ch: this.from}; 
    2393     }, 
    2394     clear: function() { 
    2395       if (this.line) { 
    2396         var found = indexOf(this.line.marked, this); 
    2397         if (found != -1) this.line.marked.splice(found, 1); 
    2398         this.line = null; 
    2399       } 
    2400     } 
    2401   }; 
     2356  function MarkedSpan(from, to, marker) { 
     2357    this.from = from; this.to = to; this.marker = marker; 
     2358  } 
     2359 
     2360  function getMarkedSpanFor(spans, marker, del) { 
     2361    if (spans) for (var i = 0; i < spans.length; ++i) { 
     2362      var span = spans[i]; 
     2363      if (span.marker == marker) { 
     2364        if (del) spans.splice(i, 1); 
     2365        return span; 
     2366      } 
     2367    } 
     2368  } 
     2369 
     2370  function markedSpansBefore(old, startCh, endCh) { 
     2371    if (old) for (var i = 0, nw; i < old.length; ++i) { 
     2372      var span = old[i], marker = span.marker; 
     2373      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); 
     2374      if (startsBefore || marker.type == "bookmark" && span.from == startCh && span.from != endCh) { 
     2375        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); 
     2376        (nw || (nw = [])).push({from: span.from, 
     2377                                to: endsAfter ? null : span.to, 
     2378                                marker: marker}); 
     2379      } 
     2380    } 
     2381    return nw; 
     2382  } 
     2383 
     2384  function markedSpansAfter(old, endCh) { 
     2385    if (old) for (var i = 0, nw; i < old.length; ++i) { 
     2386      var span = old[i], marker = span.marker; 
     2387      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); 
     2388      if (endsAfter || marker.type == "bookmark" && span.from == endCh) { 
     2389        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); 
     2390        (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh, 
     2391                                to: span.to == null ? null : span.to - endCh, 
     2392                                marker: marker}); 
     2393      } 
     2394    } 
     2395    return nw; 
     2396  } 
     2397 
     2398  function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) { 
     2399    if (!oldFirst && !oldLast) return newText; 
     2400    // Get the spans that 'stick out' on both sides 
     2401    var first = markedSpansBefore(oldFirst, startCh); 
     2402    var last = markedSpansAfter(oldLast, endCh); 
     2403 
     2404    // Next, merge those two ends 
     2405    var sameLine = newText.length == 1, offset = lst(newText).length + (sameLine ? startCh : 0); 
     2406    if (first) { 
     2407      // Fix up .to properties of first 
     2408      for (var i = 0; i < first.length; ++i) { 
     2409        var span = first[i]; 
     2410        if (span.to == null) { 
     2411          var found = getMarkedSpanFor(last, span.marker); 
     2412          if (!found) span.to = startCh; 
     2413          else if (sameLine) span.to = found.to == null ? null : found.to + offset; 
     2414        } 
     2415      } 
     2416    } 
     2417    if (last) { 
     2418      // Fix up .from in last (or move them into first in case of sameLine) 
     2419      for (var i = 0; i < last.length; ++i) { 
     2420        var span = last[i]; 
     2421        if (span.to != null) span.to += offset; 
     2422        if (span.from == null) { 
     2423          var found = getMarkedSpanFor(first, span.marker); 
     2424          if (!found) { 
     2425            span.from = offset; 
     2426            if (sameLine) (first || (first = [])).push(span); 
     2427          } 
     2428        } else { 
     2429          span.from += offset; 
     2430          if (sameLine) (first || (first = [])).push(span); 
     2431        } 
     2432      } 
     2433    } 
     2434 
     2435    var newMarkers = [newHL(newText[0], first)]; 
     2436    if (!sameLine) { 
     2437      // Fill gap with whole-line-spans 
     2438      var gap = newText.length - 2, gapMarkers; 
     2439      if (gap > 0 && first) 
     2440        for (var i = 0; i < first.length; ++i) 
     2441          if (first[i].to == null) 
     2442            (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker}); 
     2443      for (var i = 0; i < gap; ++i) 
     2444        newMarkers.push(newHL(newText[i+1], gapMarkers)); 
     2445      newMarkers.push(newHL(lst(newText), last)); 
     2446    } 
     2447    return newMarkers; 
     2448  } 
     2449 
     2450  // hl stands for history-line, a data structure that can be either a 
     2451  // string (line without markers) or a {text, markedSpans} object. 
     2452  function hlText(val) { return typeof val == "string" ? val : val.text; } 
     2453  function hlSpans(val) { return typeof val == "string" ? null : val.markedSpans; } 
     2454  function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; } 
     2455 
     2456  function detachMarkedSpans(line) { 
     2457    var spans = line.markedSpans; 
     2458    if (!spans) return; 
     2459    for (var i = 0; i < spans.length; ++i) { 
     2460      var lines = spans[i].marker.lines; 
     2461      var ix = indexOf(lines, line); 
     2462      lines.splice(ix, 1); 
     2463    } 
     2464    line.markedSpans = null; 
     2465  } 
     2466 
     2467  function attachMarkedSpans(line, spans) { 
     2468    if (!spans) return; 
     2469    for (var i = 0; i < spans.length; ++i) 
     2470      var marker = spans[i].marker.lines.push(line); 
     2471    line.markedSpans = spans; 
     2472  } 
     2473 
     2474  // When measuring the position of the end of a line, different 
     2475  // browsers require different approaches. If an empty span is added, 
     2476  // many browsers report bogus offsets. Of those, some (Webkit, 
     2477  // recent IE) will accept a space without moving the whole span to 
     2478  // the next line when wrapping it, others work with a zero-width 
     2479  // space. 
     2480  var eolSpanContent = " "; 
     2481  if (gecko || (ie && !ie_lt8)) eolSpanContent = "\u200b"; 
     2482  else if (opera) eolSpanContent = ""; 
    24022483 
    24032484  // Line objects. These hold state related to a line, including 
    24042485  // highlighting info (the styles array). 
    2405   function Line(text, styles) { 
    2406     this.styles = styles || [text, null]; 
     2486  function Line(text, markedSpans) { 
    24072487    this.text = text; 
    24082488    this.height = 1; 
    2409     this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null; 
    2410     this.stateAfter = this.parent = this.hidden = null; 
    2411   } 
    2412   Line.inheritMarks = function(text, orig) { 
    2413     var ln = new Line(text), mk = orig && orig.marked; 
    2414     if (mk) { 
    2415       for (var i = 0; i < mk.length; ++i) { 
    2416         if (mk[i].to == null && mk[i].style) { 
    2417           var newmk = ln.marked || (ln.marked = []), mark = mk[i]; 
    2418           var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln); 
    2419         } 
    2420       } 
    2421     } 
    2422     return ln; 
     2489    attachMarkedSpans(this, markedSpans); 
    24232490  } 
    24242491  Line.prototype = { 
    2425     // Replace a piece of a line, keeping the styles around it intact. 
    2426     replace: function(from, to_, text) { 
    2427       var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_; 
    2428       copyStyles(0, from, this.styles, st); 
    2429       if (text) st.push(text, null); 
    2430       copyStyles(to, this.text.length, this.styles, st); 
    2431       this.styles = st; 
    2432       this.text = this.text.slice(0, from) + text + this.text.slice(to); 
    2433       this.stateAfter = null; 
    2434       if (mk) { 
    2435         var diff = text.length - (to - from); 
    2436         for (var i = 0; i < mk.length; ++i) { 
    2437           var mark = mk[i]; 
    2438           mark.clipTo(from == null, from || 0, to_ == null, to, diff); 
    2439           if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);} 
    2440         } 
    2441       } 
    2442     }, 
    2443     // Split a part off a line, keeping styles and markers intact. 
    2444     split: function(pos, textBefore) { 
    2445       var st = [textBefore, null], mk = this.marked; 
    2446       copyStyles(pos, this.text.length, this.styles, st); 
    2447       var taken = new Line(textBefore + this.text.slice(pos), st); 
    2448       if (mk) { 
    2449         for (var i = 0; i < mk.length; ++i) { 
    2450           var mark = mk[i]; 
    2451           var newmark = mark.split(pos, textBefore.length); 
    2452           if (newmark) { 
    2453             if (!taken.marked) taken.marked = []; 
    2454             taken.marked.push(newmark); newmark.attach(taken); 
    2455             if (newmark == mark) mk.splice(i--, 1); 
    2456           } 
    2457         } 
    2458       } 
    2459       return taken; 
    2460     }, 
    2461     append: function(line) { 
    2462       var mylen = this.text.length, mk = line.marked, mymk = this.marked; 
    2463       this.text += line.text; 
    2464       copyStyles(0, line.text.length, line.styles, this.styles); 
    2465       if (mymk) { 
    2466         for (var i = 0; i < mymk.length; ++i) 
    2467           if (mymk[i].to == null) mymk[i].to = mylen; 
    2468       } 
    2469       if (mk && mk.length) { 
    2470         if (!mymk) this.marked = mymk = []; 
    2471         outer: for (var i = 0; i < mk.length; ++i) { 
    2472           var mark = mk[i]; 
    2473           if (!mark.from) { 
    2474             for (var j = 0; j < mymk.length; ++j) { 
    2475               var mymark = mymk[j]; 
    2476               if (mymark.to == mylen && mymark.sameSet(mark)) { 
    2477                 mymark.to = mark.to == null ? null : mark.to + mylen; 
    2478                 if (mymark.isDead()) { 
    2479                   mymark.detach(this); 
    2480                   mk.splice(i--, 1); 
    2481                 } 
    2482                 continue outer; 
    2483               } 
    2484             } 
    2485           } 
    2486           mymk.push(mark); 
    2487           mark.attach(this); 
    2488           mark.from += mylen; 
    2489           if (mark.to != null) mark.to += mylen; 
    2490         } 
    2491       } 
    2492     }, 
    2493     fixMarkEnds: function(other) { 
    2494       var mk = this.marked, omk = other.marked; 
    2495       if (!mk) return; 
    2496       for (var i = 0; i < mk.length; ++i) { 
    2497         var mark = mk[i], close = mark.to == null; 
    2498         if (close && omk) { 
    2499           for (var j = 0; j < omk.length; ++j) 
    2500             if (omk[j].sameSet(mark)) {close = false; break;} 
    2501         } 
    2502         if (close) mark.to = this.text.length; 
    2503       } 
    2504     }, 
    2505     fixMarkStarts: function() { 
    2506       var mk = this.marked; 
    2507       if (!mk) return; 
    2508       for (var i = 0; i < mk.length; ++i) 
    2509         if (mk[i].from == null) mk[i].from = 0; 
    2510     }, 
    2511     addMark: function(mark) { 
    2512       mark.attach(this); 
    2513       if (this.marked == null) this.marked = []; 
    2514       this.marked.push(mark); 
    2515       this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);}); 
     2492    update: function(text, markedSpans) { 
     2493      this.text = text; 
     2494      this.stateAfter = this.styles = null; 
     2495      detachMarkedSpans(this); 
     2496      attachMarkedSpans(this, markedSpans); 
    25162497    }, 
    25172498    // Run the given mode's parser over a line, update the styles 
     
    25192500    // classes. 
    25202501    highlight: function(mode, state, tabSize) { 
    2521       var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0; 
    2522       var changed = false, curWord = st[0], prevWord; 
     2502      var stream = new StringStream(this.text, tabSize), st = this.styles || (this.styles = []); 
     2503      var pos = st.length = 0; 
    25232504      if (this.text == "" && mode.blankLine) mode.blankLine(state); 
    25242505      while (!stream.eol()) { 
    2525         var style = mode.token(stream, state); 
    2526         var substr = this.text.slice(stream.start, stream.pos); 
     2506        var style = mode.token(stream, state), substr = stream.current(); 
    25272507        stream.start = stream.pos; 
    2528         if (pos && st[pos-1] == style) 
     2508        if (pos && st[pos-1] == style) { 
    25292509          st[pos-2] += substr; 
    2530         else if (substr) { 
    2531           if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true; 
     2510        } else if (substr) { 
    25322511          st[pos++] = substr; st[pos++] = style; 
    2533           prevWord = curWord; curWord = st[pos]; 
    25342512        } 
    25352513        // Give up when line is ridiculously long 
     
    25392517        } 
    25402518      } 
    2541       if (st.length != pos) {st.length = pos; changed = true;} 
    2542       if (pos && st[pos-2] != prevWord) changed = true; 
    2543       // Short lines with simple highlights return null, and are 
    2544       // counted as changed by the driver because they are likely to 
    2545       // highlight the same way in various contexts. 
    2546       return changed || (st.length < 5 && this.text.length < 10 ? null : false); 
     2519    }, 
     2520    process: function(mode, state, tabSize) { 
     2521      var stream = new StringStream(this.text, tabSize); 
     2522      if (this.text == "" && mode.blankLine) mode.blankLine(state); 
     2523      while (!stream.eol() && stream.pos <= 5000) { 
     2524        mode.token(stream, state); 
     2525        stream.start = stream.pos; 
     2526      } 
    25472527    }, 
    25482528    // Fetch the parser token for a given character. Useful for hacks 
    25492529    // that want to inspect the mode state (say, for completion). 
    2550     getTokenAt: function(mode, state, ch) { 
    2551       var txt = this.text, stream = new StringStream(txt); 
     2530    getTokenAt: function(mode, state, tabSize, ch) { 
     2531      var txt = this.text, stream = new StringStream(txt, tabSize); 
    25522532      while (stream.pos < ch && !stream.eol()) { 
    25532533        stream.start = stream.pos; 
     
    25632543    // Produces an HTML fragment for the line, taking selection, 
    25642544    // marking, and highlighting into account. 
    2565     getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) { 
    2566       var html = [], first = true, col = 0; 
    2567       function span_(text, style) { 
     2545    getContent: function(tabSize, wrapAt, compensateForWrapping) { 
     2546      var first = true, col = 0, specials = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g; 
     2547      var pre = elt("pre"); 
     2548      function span_(html, text, style) { 
    25682549        if (!text) return; 
    25692550        // Work around a bug where, in some compat modes, IE ignores leading spaces 
    25702551        if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1); 
    25712552        first = false; 
    2572         if (text.indexOf("\t") == -1) { 
     2553        if (!specials.test(text)) { 
    25732554          col += text.length; 
    2574           var escaped = htmlEscape(text); 
     2555          var content = document.createTextNode(text); 
    25752556        } else { 
    2576           var escaped = ""; 
    2577           for (var pos = 0;;) { 
    2578             var idx = text.indexOf("\t", pos); 
    2579             if (idx == -1) { 
    2580               escaped += htmlEscape(text.slice(pos)); 
    2581               col += text.length - pos; 
    2582               break; 
     2557          var content = document.createDocumentFragment(), pos = 0; 
     2558          while (true) { 
     2559            specials.lastIndex = pos; 
     2560            var m = specials.exec(text); 
     2561            var skipped = m ? m.index - pos : text.length - pos; 
     2562            if (skipped) { 
     2563              content.appendChild(document.createTextNode(text.slice(pos, pos + skipped))); 
     2564              col += skipped; 
     2565            } 
     2566            if (!m) break; 
     2567            pos += skipped + 1; 
     2568            if (m[0] == "\t") { 
     2569              var tabWidth = tabSize - col % tabSize; 
     2570              content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); 
     2571              col += tabWidth; 
    25832572            } else { 
    2584               col += idx - pos; 
    2585               var tab = makeTab(col); 
    2586               escaped += htmlEscape(text.slice(pos, idx)) + tab.html; 
    2587               col += tab.width; 
    2588               pos = idx + 1; 
     2573              var token = elt("span", "\u2022", "cm-invalidchar"); 
     2574              token.title = "\\u" + m[0].charCodeAt(0).toString(16); 
     2575              content.appendChild(token); 
     2576              col += 1; 
    25892577            } 
    25902578          } 
    25912579        } 
    2592         if (style) html.push('<span class="', style, '">', escaped, "</span>"); 
    2593         else html.push(escaped); 
     2580        if (style) html.appendChild(elt("span", [content], style)); 
     2581        else html.appendChild(content); 
    25942582      } 
    25952583      var span = span_; 
    25962584      if (wrapAt != null) { 
    2597         var outPos = 0, open = "<span id=\"" + wrapId + "\">"; 
    2598         span = function(text, style) { 
     2585        var outPos = 0, anchor = pre.anchor = elt("span"); 
     2586        span = function(html, text, style) { 
    25992587          var l = text.length; 
    26002588          if (wrapAt >= outPos && wrapAt < outPos + l) { 
    26012589            if (wrapAt > outPos) { 
    2602               span_(text.slice(0, wrapAt - outPos), style); 
     2590              span_(html, text.slice(0, wrapAt - outPos), style); 
    26032591              // See comment at the definition of spanAffectsWrapping 
    2604               if (wrapWBR) html.push("<wbr>"); 
     2592              if (compensateForWrapping) html.appendChild(elt("wbr")); 
    26052593            } 
    2606             html.push(open); 
     2594            html.appendChild(anchor); 
    26072595            var cut = wrapAt - outPos; 
    2608             span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style); 
    2609             html.push("</span>"); 
    2610             if (opera) span_(text.slice(cut + 1), style); 
     2596            span_(anchor, opera ? text.slice(cut, cut + 1) : text.slice(cut), style); 
     2597            if (opera) span_(html, text.slice(cut + 1), style); 
    26112598            wrapAt--; 
    26122599            outPos += l; 
    26132600          } else { 
    26142601            outPos += l; 
    2615             span_(text, style); 
    2616             // Output empty wrapper when at end of line 
    2617             if (outPos == wrapAt && outPos == len) html.push(open + " </span>"); 
     2602            span_(html, text, style); 
     2603            if (outPos == wrapAt && outPos == len) { 
     2604              setTextContent(anchor, eolSpanContent); 
     2605              html.appendChild(anchor); 
     2606            } 
    26182607            // Stop outputting HTML when gone sufficiently far beyond measure 
    26192608            else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){}; 
    26202609          } 
    2621         } 
    2622       } 
    2623  
    2624       var st = this.styles, allText = this.text, marked = this.marked; 
     2610        }; 
     2611      } 
     2612 
     2613      var st = this.styles, allText = this.text, marked = this.markedSpans; 
    26252614      var len = allText.length; 
    26262615      function styleToClass(style) { 
     
    26282617        return "cm-" + style.replace(/ +/g, " cm-"); 
    26292618      } 
    2630  
    26312619      if (!allText && wrapAt == null) { 
    2632         span(" "); 
     2620        span(pre, " "); 
    26332621      } else if (!marked || !marked.length) { 
    26342622        for (var i = 0, ch = 0; ch < len; i+=2) { 
     
    26362624          if (ch + l > len) str = str.slice(0, len - ch); 
    26372625          ch += l; 
    2638           span(str, styleToClass(style)); 
     2626          span(pre, str, styleToClass(style)); 
    26392627        } 
    26402628      } else { 
     2629        marked.sort(function(a, b) { return a.from - b.from; }); 
    26412630        var pos = 0, i = 0, text = "", style, sg = 0; 
    26422631        var nextChange = marked[0].from || 0, marks = [], markpos = 0; 
    2643         function advanceMarks() { 
     2632        var advanceMarks = function() { 
    26442633          var m; 
    26452634          while (markpos < marked.length && 
    26462635                 ((m = marked[markpos]).from == pos || m.from == null)) { 
    2647             if (m.style != null) marks.push(m); 
     2636            if (m.marker.type == "range") marks.push(m); 
    26482637            ++markpos; 
    26492638          } 
    26502639          nextChange = markpos < marked.length ? marked[markpos].from : Infinity; 
    26512640          for (var i = 0; i < marks.length; ++i) { 
    2652             var to = marks[i].to || Infinity; 
     2641            var to = marks[i].to; 
     2642            if (to == null) to = Infinity; 
    26532643            if (to == pos) marks.splice(i--, 1); 
    26542644            else nextChange = Math.min(to, nextChange); 
    26552645          } 
    2656         } 
     2646        }; 
    26572647        var m = 0; 
    26582648        while (pos < len) { 
     
    26632653              var end = pos + text.length; 
    26642654              var appliedStyle = style; 
    2665               for (var j = 0; j < marks.length; ++j) 
    2666                 appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style; 
    2667               span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle); 
     2655              for (var j = 0; j < marks.length; ++j) { 
     2656                var mark = marks[j]; 
     2657                appliedStyle = (appliedStyle ? appliedStyle + " " : "") + mark.marker.style; 
     2658                if (mark.marker.endStyle && mark.to === Math.min(end, upto)) appliedStyle += " " + mark.marker.endStyle; 
     2659                if (mark.marker.startStyle && mark.from === pos) appliedStyle += " " + mark.marker.startStyle; 
     2660              } 
     2661              span(pre, end > upto ? text.slice(0, upto - pos) : text, appliedStyle); 
    26682662              if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} 
    26692663              pos = end; 
     
    26732667        } 
    26742668      } 
    2675       return html.join(""); 
     2669      return pre; 
    26762670    }, 
    26772671    cleanUp: function() { 
    26782672      this.parent = null; 
    2679       if (this.marked) 
    2680         for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this); 
     2673      detachMarkedSpans(this); 
    26812674    } 
    26822675  }; 
    2683   // Utility used by replace and split above 
    2684   function copyStyles(from, to, source, dest) { 
    2685     for (var i = 0, pos = 0, state = 0; pos < to; i+=2) { 
    2686       var part = source[i], end = pos + part.length; 
    2687       if (state == 0) { 
    2688         if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]); 
    2689         if (end >= from) state = 1; 
    2690       } else if (state == 1) { 
    2691         if (end > to) dest.push(part.slice(0, to - pos), source[i+1]); 
    2692         else dest.push(part, source[i+1]); 
    2693       } 
    2694       pos = end; 
    2695     } 
    2696   } 
    26972676 
    26982677  // Data structure that holds the sequence of lines. 
     
    28952874    addChange: function(start, added, old) { 
    28962875      this.undone.length = 0; 
    2897       var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1]; 
     2876      var time = +new Date, cur = lst(this.done), last = cur && lst(cur); 
    28982877      var dtime = time - this.time; 
    28992878 
     
    29442923  function e_target(e) {return e.target || e.srcElement;} 
    29452924  function e_button(e) { 
    2946     if (e.which) return e.which; 
    2947     else if (e.button & 1) return 1; 
    2948     else if (e.button & 2) return 3; 
    2949     else if (e.button & 4) return 2; 
     2925    var b = e.which; 
     2926    if (b == null) { 
     2927      if (e.button & 1) b = 1; 
     2928      else if (e.button & 2) b = 3; 
     2929      else if (e.button & 4) b = 2; 
     2930    } 
     2931    if (mac && e.ctrlKey && b == 1) b = 3; 
     2932    return b; 
    29502933  } 
    29512934 
     
    29762959  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; 
    29772960 
    2978   var gecko = /gecko\/\d{7}/i.test(navigator.userAgent); 
    2979   var ie = /MSIE \d/.test(navigator.userAgent); 
    2980   var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent); 
    2981   var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent); 
    2982   var quirksMode = ie && document.documentMode == 5; 
    2983   var webkit = /WebKit\//.test(navigator.userAgent); 
    2984   var chrome = /Chrome\//.test(navigator.userAgent); 
    2985   var opera = /Opera\//.test(navigator.userAgent); 
    2986   var safari = /Apple Computer/.test(navigator.vendor); 
    2987   var khtml = /KHTML\//.test(navigator.userAgent); 
    2988   var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent); 
    2989  
    29902961  // Detect drag-and-drop 
    29912962  var dragAndDrop = function() { 
     
    29932964    // couldn't get it to work yet. 
    29942965    if (ie_lt9) return false; 
    2995     var div = document.createElement('div'); 
     2966    var div = elt('div'); 
    29962967    return "draggable" in div || "dragDrop" in div; 
    29972968  }(); 
     
    29992970  // Feature-detect whether newlines in textareas are converted to \r\n 
    30002971  var lineSep = function () { 
    3001     var te = document.createElement("textarea"); 
     2972    var te = elt("textarea"); 
    30022973    te.value = "foo\nbar"; 
    30032974    if (te.value.indexOf("\r") > -1) return "\r\n"; 
     
    30313002  } 
    30323003 
    3033   function computedStyle(elt) { 
    3034     if (elt.currentStyle) return elt.currentStyle; 
    3035     return window.getComputedStyle(elt, null); 
    3036   } 
    3037  
    3038   // Find the position of an element by following the offsetParent chain. 
    3039   // If screen==true, it returns screen (rather than page) coordinates. 
    30403004  function eltOffset(node, screen) { 
    3041     var bod = node.ownerDocument.body; 
    3042     var x = 0, y = 0, skipBody = false; 
    3043     for (var n = node; n; n = n.offsetParent) { 
    3044       var ol = n.offsetLeft, ot = n.offsetTop; 
    3045       // Firefox reports weird inverted offsets when the body has a border. 
    3046       if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); } 
    3047       else { x += ol, y += ot; } 
    3048       if (screen && computedStyle(n).position == "fixed") 
    3049         skipBody = true; 
    3050     } 
    3051     var e = screen && !skipBody ? null : bod; 
    3052     for (var n = node.parentNode; n != e; n = n.parentNode) 
    3053       if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;} 
    3054     return {left: x, top: y}; 
    3055   } 
    3056   // Use the faster and saner getBoundingClientRect method when possible. 
    3057   if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) { 
    30583005    // Take the parts of bounding client rect that we are interested in so we are able to edit if need be, 
    30593006    // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page) 
     
    30713018    } 
    30723019    return box; 
    3073   }; 
    3074  
    3075   // Get a node's text content. 
     3020  } 
     3021 
    30763022  function eltText(node) { 
    30773023    return node.textContent || node.innerText || node.nodeValue || ""; 
    30783024  } 
     3025 
     3026  var spaceStrs = [""]; 
     3027  function spaceStr(n) { 
     3028    while (spaceStrs.length <= n) 
     3029      spaceStrs.push(lst(spaceStrs) + " "); 
     3030    return spaceStrs[n]; 
     3031  } 
     3032 
     3033  function lst(arr) { return arr[arr.length-1]; } 
     3034 
    30793035  function selectInput(node) { 
    30803036    if (ios) { // Mobile Safari apparently has a bug where select() is broken. 
     
    30893045  function copyPos(x) {return {line: x.line, ch: x.ch};} 
    30903046 
    3091   var escapeElement = document.createElement("pre"); 
    3092   function htmlEscape(str) { 
    3093     escapeElement.textContent = str; 
    3094     return escapeElement.innerHTML; 
    3095   } 
    3096   // Recent (late 2011) Opera betas insert bogus newlines at the start 
    3097   // of the textContent, so we strip those. 
    3098   if (htmlEscape("a") == "\na") { 
    3099     htmlEscape = function(str) { 
    3100       escapeElement.textContent = str; 
    3101       return escapeElement.innerHTML.slice(1); 
    3102     }; 
    3103   // Some IEs don't preserve tabs through innerHTML 
    3104   } else if (htmlEscape("\t") != "\t") { 
    3105     htmlEscape = function(str) { 
    3106       escapeElement.innerHTML = ""; 
    3107       escapeElement.appendChild(document.createTextNode(str)); 
    3108       return escapeElement.innerHTML; 
    3109     }; 
    3110   } 
    3111   CodeMirror.htmlEscape = htmlEscape; 
     3047  function elt(tag, content, className, style) { 
     3048    var e = document.createElement(tag); 
     3049    if (className) e.className = className; 
     3050    if (style) e.style.cssText = style; 
     3051    if (typeof content == "string") setTextContent(e, content); 
     3052    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); 
     3053    return e; 
     3054  } 
     3055  function removeChildren(e) { 
     3056    e.innerHTML = ""; 
     3057    return e; 
     3058  } 
     3059  function removeChildrenAndAdd(parent, e) { 
     3060    removeChildren(parent).appendChild(e); 
     3061  } 
     3062  function setTextContent(e, str) { 
     3063    if (ie_lt9) { 
     3064      e.innerHTML = ""; 
     3065      e.appendChild(document.createTextNode(str)); 
     3066    } else e.textContent = str; 
     3067  } 
    31123068 
    31133069  // Used to position the cursor after an undo/redo by finding the 
     
    31343090  // alternative way to split lines. 
    31353091  var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { 
    3136     var pos = 0, nl, result = []; 
    3137     while ((nl = string.indexOf("\n", pos)) > -1) { 
    3138       result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl)); 
    3139       pos = nl + 1; 
    3140     } 
    3141     result.push(string.slice(pos)); 
     3092    var pos = 0, result = [], l = string.length; 
     3093    while (pos <= l) { 
     3094      var nl = string.indexOf("\n", pos); 
     3095      if (nl == -1) nl = string.length; 
     3096      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); 
     3097      var rt = line.indexOf("\r"); 
     3098      if (rt != -1) { 
     3099        result.push(line.slice(0, rt)); 
     3100        pos += rt + 1; 
     3101      } else { 
     3102        result.push(line); 
     3103        pos = nl + 1; 
     3104      } 
     3105    } 
    31423106    return result; 
    3143   } : function(string){return string.split(/\r?\n/);}; 
     3107  } : function(string){return string.split(/\r\n?|\n/);}; 
    31443108  CodeMirror.splitLines = splitLines; 
    31453109 
     
    31763140  })(); 
    31773141 
     3142  CodeMirror.version = "2.34 +"; 
     3143 
    31783144  return CodeMirror; 
    31793145})(); 
  • advanced-code-editor/trunk/js/complete.js

    r566232 r607254  
    6868//define editor   
    6969var editor = CodeMirror.fromTextArea(document.getElementById("newcontent"), { 
    70    lineNumbers: true, 
    71    onGutterClick: foldFunc, 
    72    matchBrackets: ace_user.matchBrackets, 
    73    mode: ace_file_type, 
    74    indentUnit: ace_user.indentUnit, 
    75    tabSize: ace_user.tabSize, 
    76    lineWrapping: ace_user.lineWrapping, 
    77    indentWithTabs: true, 
    78    enterMode: "keep", 
    79    tabMode: "shift", 
    80    height: "auto", 
    81    theme: theme, 
     70    theme: theme, 
     71    lineNumbers: true, 
     72    matchBrackets: (ace_user.matchBrackets == 1) ? true : false, 
     73    mode: ace_file_type, 
     74    indentUnit: parseInt(ace_user.indentUnit), 
     75    lineWrapping: (ace_user.lineWrapping == 1) ? true : false, 
     76    tabSize: parseInt(ace_user.tabSize), 
     77    indentWithTabs: true, 
     78    enterMode: "keep", 
     79    tabMode: "shift", 
     80    onGutterClick: foldFunc, 
    8281   extraKeys: {"Ctrl-Q": function(cm){foldFunc(cm, cm.getCursor().line);}}, 
    8382   onKeyEvent: function(i, e) { 
  • advanced-code-editor/trunk/js/css.js

    r518172 r607254  
    11CodeMirror.defineMode("css", function(config) { 
    22  var indentUnit = config.indentUnit, type; 
     3   
     4  var atMediaTypes = keySet([ 
     5    "all", "aural", "braille", "handheld", "print", "projection", "screen", 
     6    "tty", "tv", "embossed" 
     7  ]); 
     8   
     9  var atMediaFeatures = keySet([ 
     10    "width", "min-width", "max-width", "height", "min-height", "max-height", 
     11    "device-width", "min-device-width", "max-device-width", "device-height", 
     12    "min-device-height", "max-device-height", "aspect-ratio", 
     13    "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", 
     14    "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", 
     15    "max-color", "color-index", "min-color-index", "max-color-index", 
     16    "monochrome", "min-monochrome", "max-monochrome", "resolution", 
     17    "min-resolution", "max-resolution", "scan", "grid" 
     18  ]); 
     19 
     20  var propertyKeywords = keySet([ 
     21    "align-content", "align-items", "align-self", "alignment-adjust", 
     22    "alignment-baseline", "anchor-point", "animation", "animation-delay", 
     23    "animation-direction", "animation-duration", "animation-iteration-count", 
     24    "animation-name", "animation-play-state", "animation-timing-function", 
     25    "appearance", "azimuth", "backface-visibility", "background", 
     26    "background-attachment", "background-clip", "background-color", 
     27    "background-image", "background-origin", "background-position", 
     28    "background-repeat", "background-size", "baseline-shift", "binding", 
     29    "bleed", "bookmark-label", "bookmark-level", "bookmark-state", 
     30    "bookmark-target", "border", "border-bottom", "border-bottom-color", 
     31    "border-bottom-left-radius", "border-bottom-right-radius", 
     32    "border-bottom-style", "border-bottom-width", "border-collapse", 
     33    "border-color", "border-image", "border-image-outset", 
     34    "border-image-repeat", "border-image-slice", "border-image-source", 
     35    "border-image-width", "border-left", "border-left-color", 
     36    "border-left-style", "border-left-width", "border-radius", "border-right", 
     37    "border-right-color", "border-right-style", "border-right-width", 
     38    "border-spacing", "border-style", "border-top", "border-top-color", 
     39    "border-top-left-radius", "border-top-right-radius", "border-top-style", 
     40    "border-top-width", "border-width", "bottom", "box-decoration-break", 
     41    "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", 
     42    "caption-side", "clear", "clip", "color", "color-profile", "column-count", 
     43    "column-fill", "column-gap", "column-rule", "column-rule-color", 
     44    "column-rule-style", "column-rule-width", "column-span", "column-width", 
     45    "columns", "content", "counter-increment", "counter-reset", "crop", "cue", 
     46    "cue-after", "cue-before", "cursor", "direction", "display", 
     47    "dominant-baseline", "drop-initial-after-adjust", 
     48    "drop-initial-after-align", "drop-initial-before-adjust", 
     49    "drop-initial-before-align", "drop-initial-size", "drop-initial-value", 
     50    "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", 
     51    "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", 
     52    "float", "float-offset", "font", "font-feature-settings", "font-family", 
     53    "font-kerning", "font-language-override", "font-size", "font-size-adjust", 
     54    "font-stretch", "font-style", "font-synthesis", "font-variant", 
     55    "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", 
     56    "font-variant-ligatures", "font-variant-numeric", "font-variant-position", 
     57    "font-weight", "grid-cell", "grid-column", "grid-column-align", 
     58    "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow", 
     59    "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span", 
     60    "grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens", 
     61    "icon", "image-orientation", "image-rendering", "image-resolution", 
     62    "inline-box-align", "justify-content", "left", "letter-spacing", 
     63    "line-break", "line-height", "line-stacking", "line-stacking-ruby", 
     64    "line-stacking-shift", "line-stacking-strategy", "list-style", 
     65    "list-style-image", "list-style-position", "list-style-type", "margin", 
     66    "margin-bottom", "margin-left", "margin-right", "margin-top", 
     67    "marker-offset", "marks", "marquee-direction", "marquee-loop", 
     68    "marquee-play-count", "marquee-speed", "marquee-style", "max-height", 
     69    "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", 
     70    "nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline", 
     71    "outline-color", "outline-offset", "outline-style", "outline-width", 
     72    "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", 
     73    "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", 
     74    "page", "page-break-after", "page-break-before", "page-break-inside", 
     75    "page-policy", "pause", "pause-after", "pause-before", "perspective", 
     76    "perspective-origin", "pitch", "pitch-range", "play-during", "position", 
     77    "presentation-level", "punctuation-trim", "quotes", "rendering-intent", 
     78    "resize", "rest", "rest-after", "rest-before", "richness", "right", 
     79    "rotation", "rotation-point", "ruby-align", "ruby-overhang", 
     80    "ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header", 
     81    "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", 
     82    "tab-size", "table-layout", "target", "target-name", "target-new", 
     83    "target-position", "text-align", "text-align-last", "text-decoration", 
     84    "text-decoration-color", "text-decoration-line", "text-decoration-skip", 
     85    "text-decoration-style", "text-emphasis", "text-emphasis-color", 
     86    "text-emphasis-position", "text-emphasis-style", "text-height", 
     87    "text-indent", "text-justify", "text-outline", "text-shadow", 
     88    "text-space-collapse", "text-transform", "text-underline-position", 
     89    "text-wrap", "top", "transform", "transform-origin", "transform-style", 
     90    "transition", "transition-delay", "transition-duration", 
     91    "transition-property", "transition-timing-function", "unicode-bidi", 
     92    "vertical-align", "visibility", "voice-balance", "voice-duration", 
     93    "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", 
     94    "voice-volume", "volume", "white-space", "widows", "width", "word-break", 
     95    "word-spacing", "word-wrap", "z-index" 
     96  ]); 
     97 
     98  var colorKeywords = keySet([ 
     99    "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", 
     100    "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua" 
     101  ]); 
     102   
     103  var valueKeywords = keySet([ 
     104    "above", "absolute", "activeborder", "activecaption", "afar", 
     105    "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", 
     106    "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", 
     107    "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background", 
     108    "backwards", "baseline", "below", "bidi-override", "binary", "bengali", 
     109    "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", 
     110    "both", "bottom", "break-all", "break-word", "button", "button-bevel", 
     111    "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", 
     112    "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", 
     113    "cell", "center", "checkbox", "circle", "cjk-earthly-branch", 
     114    "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", 
     115    "col-resize", "collapse", "compact", "condensed", "contain", "content", 
     116    "content-box", "context-menu", "continuous", "copy", "cover", "crop", 
     117    "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", 
     118    "decimal-leading-zero", "default", "default-button", "destination-atop", 
     119    "destination-in", "destination-out", "destination-over", "devanagari", 
     120    "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted", 
     121    "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", 
     122    "element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", 
     123    "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", 
     124    "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", 
     125    "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", 
     126    "ethiopic-halehame-gez", "ethiopic-halehame-om-et", 
     127    "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", 
     128    "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", 
     129    "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed", 
     130    "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes", 
     131    "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", 
     132    "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", 
     133    "help", "hidden", "hide", "higher", "highlight", "highlighttext", 
     134    "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", 
     135    "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", 
     136    "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", 
     137    "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert", 
     138    "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer", 
     139    "landscape", "lao", "large", "larger", "left", "level", "lighter", 
     140    "line-through", "linear", "lines", "list-item", "listbox", "listitem", 
     141    "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", 
     142    "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", 
     143    "lower-roman", "lowercase", "ltr", "malayalam", "match", 
     144    "media-controls-background", "media-current-time-display", 
     145    "media-fullscreen-button", "media-mute-button", "media-play-button", 
     146    "media-return-to-realtime-button", "media-rewind-button", 
     147    "media-seek-back-button", "media-seek-forward-button", "media-slider", 
     148    "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", 
     149    "media-volume-slider-container", "media-volume-sliderthumb", "medium", 
     150    "menu", "menulist", "menulist-button", "menulist-text", 
     151    "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", 
     152    "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", 
     153    "narrower", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", 
     154    "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", 
     155    "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", 
     156    "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", 
     157    "outside", "overlay", "overline", "padding", "padding-box", "painted", 
     158    "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait", 
     159    "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", 
     160    "radio", "read-only", "read-write", "read-write-plaintext-only", "relative", 
     161    "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", 
     162    "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", 
     163    "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield", 
     164    "searchfield-cancel-button", "searchfield-decoration", 
     165    "searchfield-results-button", "searchfield-results-decoration", 
     166    "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", 
     167    "single", "skip-white-space", "slide", "slider-horizontal", 
     168    "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", 
     169    "small", "small-caps", "small-caption", "smaller", "solid", "somali", 
     170    "source-atop", "source-in", "source-out", "source-over", "space", "square", 
     171    "square-button", "start", "static", "status-bar", "stretch", "stroke", 
     172    "sub", "subpixel-antialiased", "super", "sw-resize", "table", 
     173    "table-caption", "table-cell", "table-column", "table-column-group", 
     174    "table-footer-group", "table-header-group", "table-row", "table-row-group", 
     175    "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", 
     176    "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", 
     177    "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", 
     178    "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", 
     179    "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", 
     180    "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", 
     181    "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", 
     182    "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", 
     183    "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", 
     184    "window", "windowframe", "windowtext", "x-large", "x-small", "xor", 
     185    "xx-large", "xx-small", "yellow" 
     186  ]); 
     187 
     188  function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) keys[array[i]] = true; return keys; } 
    3189  function ret(style, tp) {type = tp; return style;} 
    4190 
    5191  function tokenBase(stream, state) { 
    6192    var ch = stream.next(); 
    7     if (ch == "@") {stream.eatWhile(/\w/); return ret("meta", stream.current());} 
     193    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());} 
    8194    else if (ch == "/" && stream.eat("*")) { 
    9195      state.tokenize = tokenCComment; 
     
    21207    } 
    22208    else if (ch == "#") { 
    23       stream.eatWhile(/\w/); 
     209      stream.eatWhile(/[\w\\\-]/); 
    24210      return ret("atom", "hash"); 
    25211    } 
     
    32218      return ret("number", "unit"); 
    33219    } 
    34     else if (/[,.+>*\/]/.test(ch)) { 
     220    else if (ch === "-") { 
     221      if (/\d/.test(stream.peek())) { 
     222        stream.eatWhile(/[\w.%]/); 
     223        return ret("number", "unit"); 
     224      } else if (stream.match(/^[^-]+-/)) { 
     225        return ret("meta", type); 
     226      } 
     227    } 
     228    else if (/[,+>*\/]/.test(ch)) { 
    35229      return ret(null, "select-op"); 
    36230    } 
    37     else if (/[;{}:\[\]]/.test(ch)) { 
     231    else if (ch == "." && stream.match(/^\w+/)) { 
     232      return ret("qualifier", type); 
     233    } 
     234    else if (ch == ":") { 
     235      return ret("operator", ch); 
     236    } 
     237    else if (/[;{}\[\]\(\)]/.test(ch)) { 
    38238      return ret(null, ch); 
    39239    } 
    40240    else { 
    41       stream.eatWhile(/[\w\\\-_]/); 
    42       return ret("variable", "variable"); 
     241      stream.eatWhile(/[\w\\\-]/); 
     242      return ret("property", "variable"); 
    43243    } 
    44244  } 
     
    89289 
    90290    token: function(stream, state) { 
     291       
     292      // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50) 
     293      //  
     294      // rule** or **ruleset: 
     295      // A selector + braces combo, or an at-rule. 
     296      //  
     297      // declaration block: 
     298      // A sequence of declarations. 
     299      //  
     300      // declaration: 
     301      // A property + colon + value combo. 
     302      //  
     303      // property value: 
     304      // The entire value of a property. 
     305      //  
     306      // component value: 
     307      // A single piece of a property value. Like the 5px in 
     308      // text-shadow: 0 0 5px blue;. Can also refer to things that are 
     309      // multiple terms, like the 1-4 terms that make up the background-size 
     310      // portion of the background shorthand. 
     311      //  
     312      // term: 
     313      // The basic unit of author-facing CSS, like a single number (5), 
     314      // dimension (5px), string ("foo"), or function. Officially defined 
     315      //  by the CSS 2.1 grammar (look for the 'term' production) 
     316      //  
     317      //  
     318      // simple selector: 
     319      // A single atomic selector, like a type selector, an attr selector, a 
     320      // class selector, etc. 
     321      //  
     322      // compound selector: 
     323      // One or more simple selectors without a combinator. div.example is 
     324      // compound, div > .example is not. 
     325      //  
     326      // complex selector: 
     327      // One or more compound selectors chained with combinators. 
     328      //  
     329      // combinator: 
     330      // The parts of selectors that express relationships. There are four 
     331      // currently - the space (descendant combinator), the greater-than 
     332      // bracket (child combinator), the plus sign (next sibling combinator), 
     333      // and the tilda (following sibling combinator). 
     334      //  
     335      // sequence of selectors: 
     336      // One or more of the named type of selector chained with commas. 
     337 
    91338      if (stream.eatSpace()) return null; 
    92339      var style = state.tokenize(stream, state); 
    93340 
     341      // Changing style returned based on context 
    94342      var context = state.stack[state.stack.length-1]; 
    95       if (type == "hash" && context == "rule") style = "atom"; 
    96       else if (style == "variable") { 
    97         if (context == "rule") style = "number"; 
    98         else if (!context || context == "@media{") style = "tag"; 
    99       } 
    100  
    101       if (context == "rule" && /^[\{\};]$/.test(type)) 
     343      if (style == "property") { 
     344        if (context == "propertyValue"){ 
     345          if (valueKeywords[stream.current()]) { 
     346            style = "string-2"; 
     347          } else if (colorKeywords[stream.current()]) { 
     348            style = "keyword"; 
     349          } else { 
     350            style = "variable-2"; 
     351          } 
     352        } else if (context == "rule") { 
     353          if (!propertyKeywords[stream.current()]) { 
     354            style += " error"; 
     355          } 
     356        } else if (!context || context == "@media{") { 
     357          style = "tag"; 
     358        } else if (context == "@media") { 
     359          if (atMediaTypes[stream.current()]) { 
     360            style = "attribute"; // Known attribute 
     361          } else if (/^(only|not)$/i.test(stream.current())) { 
     362            style = "keyword"; 
     363          } else if (stream.current().toLowerCase() == "and") { 
     364            style = "error"; // "and" is only allowed in @mediaType 
     365          } else if (atMediaFeatures[stream.current()]) { 
     366            style = "error"; // Known property, should be in @mediaType( 
     367          } else { 
     368            // Unknown, expecting keyword or attribute, assuming attribute 
     369            style = "attribute error"; 
     370          } 
     371        } else if (context == "@mediaType") { 
     372          if (atMediaTypes[stream.current()]) { 
     373            style = "attribute"; 
     374          } else if (stream.current().toLowerCase() == "and") { 
     375            style = "operator"; 
     376          } else if (/^(only|not)$/i.test(stream.current())) { 
     377            style = "error"; // Only allowed in @media 
     378          } else if (atMediaFeatures[stream.current()]) { 
     379            style = "error"; // Known property, should be in parentheses 
     380          } else { 
     381            // Unknown attribute or property, but expecting property (preceded 
     382            // by "and"). Should be in parentheses 
     383            style = "error"; 
     384          } 
     385        } else if (context == "@mediaType(") { 
     386          if (propertyKeywords[stream.current()]) { 
     387            // do nothing, remains "property" 
     388          } else if (atMediaTypes[stream.current()]) { 
     389            style = "error"; // Known property, should be in parentheses 
     390          } else if (stream.current().toLowerCase() == "and") { 
     391            style = "operator"; 
     392          } else if (/^(only|not)$/i.test(stream.current())) { 
     393            style = "error"; // Only allowed in @media 
     394          } else { 
     395            style += " error"; 
     396          } 
     397        } else { 
     398          style = "error"; 
     399        } 
     400      } else if (style == "atom") { 
     401        if(!context || context == "@media{") { 
     402          style = "builtin"; 
     403        } else if (context == "propertyValue") { 
     404          if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { 
     405            style += " error"; 
     406          } 
     407        } else { 
     408          style = "error"; 
     409        } 
     410      } else if (context == "@media" && type == "{") { 
     411        style = "error"; 
     412      } 
     413 
     414      // Push/pop context stack 
     415      if (type == "{") { 
     416        if (context == "@media" || context == "@mediaType") { 
     417          state.stack.pop(); 
     418          state.stack[state.stack.length-1] = "@media{"; 
     419        } 
     420        else state.stack.push("rule"); 
     421      } 
     422      else if (type == "}") { 
    102423        state.stack.pop(); 
    103       if (type == "{") { 
    104         if (context == "@media") state.stack[state.stack.length-1] = "@media{"; 
    105         else state.stack.push("{"); 
    106       } 
    107       else if (type == "}") state.stack.pop(); 
     424        if (context == "propertyValue") state.stack.pop(); 
     425      } 
    108426      else if (type == "@media") state.stack.push("@media"); 
    109       else if (context == "{" && type != "comment") state.stack.push("rule"); 
     427      else if (context == "@media" && /\b(keyword|attribute)\b/.test(style)) 
     428        state.stack.push("@mediaType"); 
     429      else if (context == "@mediaType" && stream.current() == ",") state.stack.pop(); 
     430      else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType("); 
     431      else if (context == "@mediaType(" && type == ")") state.stack.pop(); 
     432      else if (context == "rule" && type == ":") state.stack.push("propertyValue"); 
     433      else if (context == "propertyValue" && type == ";") state.stack.pop(); 
    110434      return style; 
    111435    }, 
     
    114438      var n = state.stack.length; 
    115439      if (/^\}/.test(textAfter)) 
    116         n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; 
     440        n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1; 
    117441      return state.baseIndent + n * indentUnit; 
    118442    }, 
  • advanced-code-editor/trunk/js/htmlmixed.js

    r518172 r607254  
    1 CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { 
     1CodeMirror.defineMode("htmlmixed", function(config) { 
    22  var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true}); 
    33  var jsMode = CodeMirror.getMode(config, "javascript"); 
     
    2020  function maybeBackup(stream, pat, style) { 
    2121    var cur = stream.current(); 
    22     var close = cur.search(pat); 
     22    var close = cur.search(pat), m; 
    2323    if (close > -1) stream.backUp(cur.length - close); 
     24    else if (m = cur.match(/<\/?$/)) { 
     25      stream.backUp(cur[0].length); 
     26      if (!stream.match(pat, false)) stream.match(cur[0]); 
     27    } 
    2428    return style; 
    2529  } 
     
    2731    if (stream.match(/^<\/\s*script\s*>/i, false)) { 
    2832      state.token = html; 
    29       state.curState = null; 
     33      state.localState = null; 
    3034      return html(stream, state); 
    3135    } 
     
    4650    startState: function() { 
    4751      var state = htmlMode.startState(); 
    48       return {token: html, localState: null, htmlState: state}; 
     52      return {token: html, localState: null, mode: "html", htmlState: state}; 
    4953    }, 
    5054 
     
    5256      if (state.localState) 
    5357        var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState); 
    54       return {token: state.token, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; 
     58      return {token: state.token, localState: local, mode: state.mode, 
     59              htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; 
    5560    }, 
    5661 
     
    6873    }, 
    6974 
    70     electricChars: "/{}:" 
    71   } 
    72 }); 
     75    electricChars: "/{}:", 
     76 
     77    innerMode: function(state) { 
     78      var mode = state.token == html ? htmlMode : state.token == javascript ? jsMode : cssMode; 
     79      return {state: state.localState || state.htmlState, mode: mode}; 
     80    } 
     81  }; 
     82}, "xml", "javascript", "css"); 
    7383 
    7484CodeMirror.defineMIME("text/html", "htmlmixed"); 
  • advanced-code-editor/trunk/js/javascript.js

    r518172 r607254  
    1212      "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, 
    1313      "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, 
    14       "var": kw("var"), "function": kw("function"), "catch": kw("catch"), 
     14      "var": kw("var"), "const": kw("var"), "let": kw("var"), 
     15      "function": kw("function"), "catch": kw("catch"), 
    1516      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), 
    1617      "in": operator, "typeof": operator, "instanceof": operator, 
     
    5253    else if (ch == "0" && stream.eat(/x/i)) { 
    5354      stream.eatWhile(/[\da-f]/i); 
    54       return ret("number", "atom"); 
     55      return ret("number", "number"); 
    5556    }       
    56     else if (/\d/.test(ch)) { 
    57       stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/); 
    58       return ret("number", "atom"); 
     57    else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { 
     58      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); 
     59      return ret("number", "number"); 
    5960    } 
    6061    else if (ch == "/") { 
     
    6970        nextUntilUnescaped(stream, "/"); 
    7071        stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla 
    71         return ret("regexp", "string"); 
     72        return ret("regexp", "string-2"); 
    7273      } 
    7374      else { 
     
    7677      } 
    7778    } 
     79    else if (ch == "#") { 
     80        stream.skipToEnd(); 
     81        return ret("error", "error"); 
     82    } 
    7883    else if (isOperatorChar.test(ch)) { 
    7984      stream.eatWhile(isOperatorChar); 
     
    8388      stream.eatWhile(/[\w\$_]/); 
    8489      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; 
    85       return known ? ret(known.type, known.style, word) : 
     90      return (known && state.kwAllowed) ? ret(known.type, known.style, word) : 
    8691                     ret("variable", "variable", word); 
    8792    } 
     
    171176  var defaultVars = {name: "this", next: {name: "arguments"}}; 
    172177  function pushcontext() { 
    173     if (!cx.state.context) cx.state.localVars = defaultVars; 
    174178    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; 
     179    cx.state.localVars = defaultVars; 
    175180  } 
    176181  function popcontext() { 
     
    181186    var result = function() { 
    182187      var state = cx.state; 
    183       state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info) 
     188      state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info); 
    184189    }; 
    185190    result.lex = true; 
     
    225230    if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator); 
    226231    if (type == "function") return cont(functiondef); 
    227     if (type == "keyword c") return cont(expression); 
    228     if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator); 
     232    if (type == "keyword c") return cont(maybeexpression); 
     233    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator); 
    229234    if (type == "operator") return cont(expression); 
    230235    if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator); 
     
    232237    return cont(); 
    233238  } 
     239  function maybeexpression(type) { 
     240    if (type.match(/[;\}\)\],]/)) return pass(); 
     241    return pass(expression); 
     242  } 
     243     
    234244  function maybeoperator(type, value) { 
    235245    if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator); 
    236     if (type == "operator") return cont(expression); 
     246    if (type == "operator" && value == "?") return cont(expression, expect(":"), expression); 
    237247    if (type == ";") return; 
    238248    if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator); 
     
    275285  } 
    276286  function forspec1(type) { 
    277     if (type == "var") return cont(vardef1, forspec2); 
    278     if (type == ";") return pass(forspec2); 
     287    if (type == "var") return cont(vardef1, expect(";"), forspec2); 
     288    if (type == ";") return cont(forspec2); 
    279289    if (type == "variable") return cont(formaybein); 
    280     return pass(forspec2); 
     290    return cont(forspec2); 
    281291  } 
    282292  function formaybein(type, value) { 
     
    307317        tokenize: jsTokenBase, 
    308318        reAllowed: true, 
     319        kwAllowed: true, 
    309320        cc: [], 
    310321        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), 
    311         localVars: null, 
    312         context: null, 
     322        localVars: parserConfig.localVars, 
     323        context: parserConfig.localVars && {vars: parserConfig.localVars}, 
    313324        indented: 0 
    314325      }; 
     
    324335      var style = state.tokenize(stream, state); 
    325336      if (type == "comment") return style; 
    326       state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/); 
     337      state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/)); 
     338      state.kwAllowed = type != '.'; 
    327339      return parseJS(state, style, type, content, stream); 
    328340    }, 
    329341 
    330342    indent: function(state, textAfter) { 
     343      if (state.tokenize == jsTokenComment) return CodeMirror.Pass; 
    331344      if (state.tokenize != jsTokenBase) return 0; 
    332       var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, 
    333           type = lexical.type, closing = firstChar == type; 
     345      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; 
     346      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; 
     347      var type = lexical.type, closing = firstChar == type; 
    334348      if (type == "vardef") return lexical.indented + 4; 
    335349      else if (type == "form" && firstChar == "{") return lexical.indented; 
  • advanced-code-editor/trunk/js/overlay.js

    r518172 r607254  
    77// the styles are combined. 
    88 
    9 CodeMirror.overlayParser = function(base, overlay, combine) { 
     9// overlayParser is the old, deprecated name 
     10CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) { 
    1011  return { 
    1112    startState: function() { 
     
    4445    }, 
    4546     
    46     indent: function(state, textAfter) { 
     47    indent: base.indent && function(state, textAfter) { 
    4748      return base.indent(state.base, textAfter); 
    4849    }, 
    49     electricChars: base.electricChars 
     50    electricChars: base.electricChars, 
     51 
     52    innerMode: function(state) { return {state: state.base, mode: base}; } 
    5053  }; 
    5154}; 
  • advanced-code-editor/trunk/js/php.js

    r518172 r607254  
    55    return obj; 
    66  } 
    7   var phpKeywords = 
    8     keywords("abstract and array as break case catch cfunction class clone const continue declare " + 
    9              "default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " + 
    10              "final for foreach function global goto if implements interface instanceof namespace " + 
    11              "new or private protected public static switch throw try use var while xor"); 
    12   var phpConfig = {name: "clike", keywords: phpKeywords, multiLineStrings: true, $vars: true}; 
     7  function heredoc(delim) { 
     8    return function(stream, state) { 
     9      if (stream.match(delim)) state.tokenize = null; 
     10      else stream.skipToEnd(); 
     11      return "string"; 
     12    }; 
     13  } 
     14  var phpConfig = { 
     15    name: "clike", 
     16    keywords: keywords("abstract and array as break case catch class clone const continue declare default " + 
     17                       "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " + 
     18                       "for foreach function global goto if implements interface instanceof namespace " + 
     19                       "new or private protected public static switch throw trait try use var while xor " + 
     20                       "die echo empty exit eval include include_once isset list require require_once return " + 
     21                       "print unset __halt_compiler self static parent"), 
     22    blockKeywords: keywords("catch do else elseif for foreach if switch try while"), 
     23    atoms: keywords("true false null TRUE FALSE NULL"), 
     24    multiLineStrings: true, 
     25    hooks: { 
     26      "$": function(stream, state) { 
     27        stream.eatWhile(/[\w\$_]/); 
     28        return "variable-2"; 
     29      }, 
     30      "<": function(stream, state) { 
     31        if (stream.match(/<</)) { 
     32          stream.eatWhile(/[\w\.]/); 
     33          state.tokenize = heredoc(stream.current().slice(3)); 
     34          return state.tokenize(stream, state); 
     35        } 
     36        return false; 
     37      }, 
     38      "#": function(stream, state) { 
     39        while (!stream.eol() && !stream.match("?>", false)) stream.next(); 
     40        return "comment"; 
     41      }, 
     42      "/": function(stream, state) { 
     43        if (stream.eat("/")) { 
     44          while (!stream.eol() && !stream.match("?>", false)) stream.next(); 
     45          return "comment"; 
     46        } 
     47        return false; 
     48      } 
     49    } 
     50  }; 
    1351 
    1452  CodeMirror.defineMode("php", function(config, parserConfig) { 
    15     var htmlMode = CodeMirror.getMode(config, "text/html"); 
    16     var jsMode = CodeMirror.getMode(config, "text/javascript"); 
    17     var cssMode = CodeMirror.getMode(config, "text/css"); 
     53    var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true}); 
     54    var jsMode = CodeMirror.getMode(config, "javascript"); 
     55    var cssMode = CodeMirror.getMode(config, "css"); 
    1856    var phpMode = CodeMirror.getMode(config, phpConfig); 
    1957 
    2058    function dispatch(stream, state) { // TODO open PHP inside text/css 
     59      var isPHP = state.curMode == phpMode; 
     60      if (stream.sol() && state.pending != '"') state.pending = null; 
    2161      if (state.curMode == htmlMode) { 
    22         var style = htmlMode.token(stream, state.curState); 
    23         if (style == "meta" && /^<\?/.test(stream.current())) { 
     62        if (stream.match(/^<\?\w*/)) { 
    2463          state.curMode = phpMode; 
    2564          state.curState = state.php; 
    26           state.curClose = /^\?>/; 
     65          state.curClose = "?>"; 
     66          return "meta"; 
    2767        } 
    28         else if (style == "tag" && stream.current() == ">" && state.curState.context) { 
     68        if (state.pending == '"') { 
     69          while (!stream.eol() && stream.next() != '"') {} 
     70          var style = "string"; 
     71        } else if (state.pending && stream.pos < state.pending.end) { 
     72          stream.pos = state.pending.end; 
     73          var style = state.pending.style; 
     74        } else { 
     75          var style = htmlMode.token(stream, state.curState); 
     76        } 
     77        state.pending = null; 
     78        var cur = stream.current(), openPHP = cur.search(/<\?/); 
     79        if (openPHP != -1) { 
     80          if (style == "string" && /\"$/.test(cur) && !/\?>/.test(cur)) state.pending = '"'; 
     81          else state.pending = {end: stream.pos, style: style}; 
     82          stream.backUp(cur.length - openPHP); 
     83        } else if (style == "tag" && stream.current() == ">" && state.curState.context) { 
    2984          if (/^script$/i.test(state.curState.context.tagName)) { 
    3085            state.curMode = jsMode; 
     
    3590            state.curMode = cssMode; 
    3691            state.curState = cssMode.startState(htmlMode.indent(state.curState, "")); 
    37             state.curClose =  /^<\/\s*style\s*>/i; 
     92            state.curClose = /^<\/\s*style\s*>/i; 
    3893          } 
    3994        } 
    4095        return style; 
    41       } 
    42       else if (stream.match(state.curClose, false)) { 
     96      } else if ((!isPHP || state.php.tokenize == null) && 
     97                 stream.match(state.curClose, isPHP)) { 
    4398        state.curMode = htmlMode; 
    4499        state.curState = state.html; 
    45100        state.curClose = null; 
    46         return dispatch(stream, state); 
     101        if (isPHP) return "meta"; 
     102        else return dispatch(stream, state); 
     103      } else { 
     104        return state.curMode.token(stream, state.curState); 
    47105      } 
    48       else return state.curMode.token(stream, state.curState); 
    49106    } 
    50107 
     
    54111        return {html: html, 
    55112                php: phpMode.startState(), 
    56                 curMode: htmlMode, 
    57                 curState: html, 
    58                 curClose: null} 
     113                curMode: parserConfig.startOpen ? phpMode : htmlMode, 
     114                curState: parserConfig.startOpen ? phpMode.startState() : html, 
     115                curClose: parserConfig.startOpen ? /^\?>/ : null, 
     116        mode: parserConfig.startOpen ? "php" : "html", 
     117                pending: null}; 
    59118      }, 
    60119 
     
    65124        else if (state.curState == php) cur = phpNew; 
    66125        else cur = CodeMirror.copyState(state.curMode, state.curState); 
    67         return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, curClose: state.curClose}; 
     126        return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, 
     127                curClose: state.curClose, mode: state.mode, 
     128                pending: state.pending}; 
    68129      }, 
    69130 
     
    77138      }, 
    78139 
    79       electricChars: "/{}:" 
    80     } 
    81   }); 
     140      electricChars: "/{}:", 
     141 
     142      innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } 
     143    }; 
     144  }, "xml", "clike", "javascript", "css"); 
    82145  CodeMirror.defineMIME("application/x-httpd-php", "php"); 
     146  CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true}); 
    83147  CodeMirror.defineMIME("text/x-php", phpConfig); 
    84148})(); 
  • advanced-code-editor/trunk/js/runmode.js

    r518172 r607254  
    1 CodeMirror.runMode = function(string, modespec, callback) { 
    2   var mode = CodeMirror.getMode({indentUnit: 2}, modespec); 
     1CodeMirror.runMode = function(string, modespec, callback, options) { 
     2  function esc(str) { 
     3    return str.replace(/[<&]/, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; }); 
     4  } 
     5 
     6  var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); 
    37  var isNode = callback.nodeType == 1; 
     8  var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; 
    49  if (isNode) { 
    5     var node = callback, accum = []; 
    6     callback = function(string, style) { 
    7       if (string == "\n") 
     10    var node = callback, accum = [], col = 0; 
     11    callback = function(text, style) { 
     12      if (text == "\n") { 
    813        accum.push("<br>"); 
    9       else if (style) 
    10         accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + CodeMirror.htmlEscape(string) + "</span>"); 
     14        col = 0; 
     15        return; 
     16      } 
     17      var escaped = ""; 
     18      // HTML-escape and replace tabs 
     19      for (var pos = 0;;) { 
     20        var idx = text.indexOf("\t", pos); 
     21        if (idx == -1) { 
     22          escaped += esc(text.slice(pos)); 
     23          col += text.length - pos; 
     24          break; 
     25        } else { 
     26          col += idx - pos; 
     27          escaped += esc(text.slice(pos, idx)); 
     28          var size = tabSize - col % tabSize; 
     29          col += size; 
     30          for (var i = 0; i < size; ++i) escaped += " "; 
     31          pos = idx + 1; 
     32        } 
     33      } 
     34 
     35      if (style)  
     36        accum.push("<span class=\"cm-" + esc(style) + "\">" + escaped + "</span>"); 
    1137      else 
    12         accum.push(CodeMirror.htmlEscape(string)); 
    13     } 
     38        accum.push(escaped); 
     39    }; 
    1440  } 
    1541  var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode); 
     
    1945    while (!stream.eol()) { 
    2046      var style = mode.token(stream, state); 
    21       callback(stream.current(), style); 
     47      callback(stream.current(), style, i, stream.start); 
    2248      stream.start = stream.pos; 
    2349    } 
  • advanced-code-editor/trunk/js/search.js

    r566232 r607254  
    4141        state.query = parseQuery(query); 
    4242        if (cm.lineCount() < 2000) { // This is too expensive on big documents. 
    43           for (var cursor = getSearchCursor(cm, query); cursor.findNext();) 
     43          for (var cursor = getSearchCursor(cm, state.query); cursor.findNext();) 
    4444            state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching")); 
    4545        } 
     
    5858    cm.setSelection(cursor.from(), cursor.to()); 
    5959    state.posFrom = cursor.from(); state.posTo = cursor.to(); 
    60   })} 
     60  });} 
    6161  function clearSearch(cm) {cm.operation(function() { 
    6262    var state = getSearchState(cm); 
     
    6565    for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); 
    6666    state.marked.length = 0; 
    67   })} 
     67  });} 
    6868 
    6969  var replaceQueryDialog = 
     
    8484              } else cursor.replace(text); 
    8585            } 
    86           })}); 
     86          });}); 
    8787        } else { 
    8888          clearSearch(cm); 
  • advanced-code-editor/trunk/js/searchcursor.js

    r566232 r607254  
    1111    // describing the next occurrence of the query, or null if no 
    1212    // more matches were found. 
    13     if (typeof query != "string") // Regexp match 
     13    if (typeof query != "string") { // Regexp match 
     14      if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g"); 
    1415      this.matches = function(reverse, pos) { 
    1516        if (reverse) { 
    16           var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0; 
     17          query.lastIndex = 0; 
     18          var line = cm.getLine(pos.line).slice(0, pos.ch), match = query.exec(line), start = 0; 
    1719          while (match) { 
    18             var ind = line.indexOf(match[0]); 
    19             start += ind; 
    20             line = line.slice(ind + 1); 
    21             var newmatch = line.match(query); 
     20            start += match.index + 1; 
     21        line = line.slice(start); 
     22            query.lastIndex = 0; 
     23            var newmatch = query.exec(line); 
    2224            if (newmatch) match = newmatch; 
    2325            else break; 
    24             start++; 
    2526          } 
    26         } 
    27         else { 
    28           var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query), 
    29           start = match && pos.ch + line.indexOf(match[0]); 
     27          start--; 
     28        } else { 
     29          query.lastIndex = pos.ch; 
     30          var line = cm.getLine(pos.line), match = query.exec(line), 
     31          start = match && match.index; 
    3032        } 
    3133        if (match) 
     
    3436                  match: match}; 
    3537      }; 
    36     else { // String query 
     38    } else { // String query 
    3739      if (caseFold) query = query.toLowerCase(); 
    3840      var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; 
  • advanced-code-editor/trunk/js/simple-hint.js

    r566232 r607254  
    11(function() { 
    2   CodeMirror.simpleHint = function(editor, getHints) { 
    3     // We want a single cursor position. 
    4     if (editor.somethingSelected()) return; 
    5     var result = getHints(editor); 
    6     if (!result || !result.list.length) return; 
    7     var completions = result.list; 
    8     function insert(str) { 
    9       editor.replaceRange(str, result.from, result.to); 
     2  CodeMirror.simpleHint = function(editor, getHints, givenOptions) { 
     3    // Determine effective options based on given values and defaults. 
     4    var options = {}, defaults = CodeMirror.simpleHint.defaults; 
     5    for (var opt in defaults) 
     6      if (defaults.hasOwnProperty(opt)) 
     7        options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; 
     8     
     9    function collectHints(previousToken) { 
     10      // We want a single cursor position. 
     11      if (editor.somethingSelected()) return; 
     12 
     13      var tempToken = editor.getTokenAt(editor.getCursor()); 
     14 
     15      // Don't show completions if token has changed and the option is set. 
     16      if (options.closeOnTokenChange && previousToken != null && 
     17          (tempToken.start != previousToken.start || tempToken.className != previousToken.className)) { 
     18        return; 
     19      } 
     20 
     21      var result = getHints(editor); 
     22      if (!result || !result.list.length) return; 
     23      var completions = result.list; 
     24      function insert(str) { 
     25        editor.replaceRange(str, result.from, result.to); 
     26      } 
     27      // When there is only one completion, use it directly. 
     28      if (completions.length == 1) {insert(completions[0]); return true;} 
     29 
     30      // Build the select widget 
     31      var complete = document.createElement("div"); 
     32      complete.className = "CodeMirror-completions"; 
     33      var sel = complete.appendChild(document.createElement("select")); 
     34      // Opera doesn't move the selection when pressing up/down in a 
     35      // multi-select, but it does properly support the size property on 
     36      // single-selects, so no multi-select is necessary. 
     37      if (!window.opera) sel.multiple = true; 
     38      for (var i = 0; i < completions.length; ++i) { 
     39        var opt = sel.appendChild(document.createElement("option")); 
     40        opt.appendChild(document.createTextNode(completions[i])); 
     41      } 
     42      sel.firstChild.selected = true; 
     43      sel.size = Math.min(10, completions.length); 
     44      var pos = editor.cursorCoords(); 
     45      complete.style.left = pos.x + "px"; 
     46      complete.style.top = pos.yBot + "px"; 
     47      document.body.appendChild(complete); 
     48      // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. 
     49      var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); 
     50      if(winW - pos.x < sel.clientWidth) 
     51        complete.style.left = (pos.x - sel.clientWidth) + "px"; 
     52      // Hack to hide the scrollbar. 
     53      if (completions.length <= 10) 
     54        complete.style.width = (sel.clientWidth - 1) + "px"; 
     55 
     56      var done = false; 
     57      function close() { 
     58        if (done) return; 
     59        done = true; 
     60        complete.parentNode.removeChild(complete); 
     61      } 
     62      function pick() { 
     63        insert(completions[sel.selectedIndex]); 
     64        close(); 
     65        setTimeout(function(){editor.focus();}, 50); 
     66      } 
     67      CodeMirror.connect(sel, "blur", close); 
     68      CodeMirror.connect(sel, "keydown", function(event) { 
     69        var code = event.keyCode; 
     70        // Enter 
     71        if (code == 13) {CodeMirror.e_stop(event); pick();} 
     72        // Escape 
     73        else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} 
     74        else if (code != 38 && code != 40 && code != 33 && code != 34 && !CodeMirror.isModifierKey(event)) { 
     75          close(); editor.focus(); 
     76          // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. 
     77          editor.triggerOnKeyDown(event); 
     78          // Don't show completions if the code is backspace and the option is set. 
     79          if (!options.closeOnBackspace || code != 8) { 
     80            setTimeout(function(){collectHints(tempToken);}, 50); 
     81          } 
     82        } 
     83      }); 
     84      CodeMirror.connect(sel, "dblclick", pick); 
     85 
     86      sel.focus(); 
     87      // Opera sometimes ignores focusing a freshly created node 
     88      if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100); 
     89      return true; 
    1090    } 
    11     // When there is only one completion, use it directly. 
    12     if (completions.length == 1) {insert(completions[0]); return true;} 
    13  
    14     // Build the select widget 
    15     var complete = document.createElement("div"); 
    16     complete.className = "CodeMirror-completions"; 
    17     var sel = complete.appendChild(document.createElement("select")); 
    18     // Opera doesn't move the selection when pressing up/down in a 
    19     // multi-select, but it does properly support the size property on 
    20     // single-selects, so no multi-select is necessary. 
    21     if (!window.opera) sel.multiple = true; 
    22     for (var i = 0; i < completions.length; ++i) { 
    23       var opt = sel.appendChild(document.createElement("option")); 
    24       opt.appendChild(document.createTextNode(completions[i])); 
    25     } 
    26     sel.firstChild.selected = true; 
    27     sel.size = Math.min(10, completions.length); 
    28     var pos = editor.cursorCoords(); 
    29     complete.style.left = pos.x + "px"; 
    30     complete.style.top = pos.yBot + "px"; 
    31     document.body.appendChild(complete); 
    32     // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. 
    33     var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); 
    34     if(winW - pos.x < sel.clientWidth) 
    35       complete.style.left = (pos.x - sel.clientWidth) + "px"; 
    36     // Hack to hide the scrollbar. 
    37     if (completions.length <= 10) 
    38       complete.style.width = (sel.clientWidth - 1) + "px"; 
    39  
    40     var done = false; 
    41     function close() { 
    42       if (done) return; 
    43       done = true; 
    44       complete.parentNode.removeChild(complete); 
    45     } 
    46     function pick() { 
    47       insert(completions[sel.selectedIndex]); 
    48       close(); 
    49       setTimeout(function(){editor.focus();}, 50); 
    50     } 
    51     CodeMirror.connect(sel, "blur", close); 
    52     CodeMirror.connect(sel, "keydown", function(event) { 
    53       var code = event.keyCode; 
    54       // Enter 
    55       if (code == 13) {CodeMirror.e_stop(event); pick();} 
    56       // Escape 
    57       else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} 
    58       else if (code != 38 && code != 40) { 
    59         close(); editor.focus(); 
    60         // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. 
    61         editor.triggerOnKeyDown(event); 
    62         setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50); 
    63       } 
    64     }); 
    65     CodeMirror.connect(sel, "dblclick", pick); 
    66  
    67     sel.focus(); 
    68     // Opera sometimes ignores focusing a freshly created node 
    69     if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100); 
    70     return true; 
     91    return collectHints(); 
     92  }; 
     93  CodeMirror.simpleHint.defaults = { 
     94    closeOnBackspace: true, 
     95    closeOnTokenChange: false 
    7196  }; 
    7297})(); 
  • advanced-code-editor/trunk/js/xml.js

    r518172 r607254  
    22  var indentUnit = config.indentUnit; 
    33  var Kludges = parserConfig.htmlMode ? { 
    4     autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true, 
    5                       "meta": true, "col": true, "frame": true, "base": true, "area": true}, 
    6     doNotIndent: {"pre": true, "!cdata": true}, 
    7     allowUnquoted: true 
    8   } : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, allowUnquoted: false}; 
     4    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, 
     5                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, 
     6                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, 
     7                      'track': true, 'wbr': true}, 
     8    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, 
     9                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, 
     10                       'th': true, 'tr': true}, 
     11    contextGrabbers: { 
     12      'dd': {'dd': true, 'dt': true}, 
     13      'dt': {'dd': true, 'dt': true}, 
     14      'li': {'li': true}, 
     15      'option': {'option': true, 'optgroup': true}, 
     16      'optgroup': {'optgroup': true}, 
     17      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, 
     18            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, 
     19            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, 
     20            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, 
     21            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, 
     22      'rp': {'rp': true, 'rt': true}, 
     23      'rt': {'rp': true, 'rt': true}, 
     24      'tbody': {'tbody': true, 'tfoot': true}, 
     25      'td': {'td': true, 'th': true}, 
     26      'tfoot': {'tbody': true}, 
     27      'th': {'td': true, 'th': true}, 
     28      'thead': {'tbody': true, 'tfoot': true}, 
     29      'tr': {'tr': true} 
     30    }, 
     31    doNotIndent: {"pre": true}, 
     32    allowUnquoted: true, 
     33    allowMissing: true 
     34  } : { 
     35    autoSelfClosers: {}, 
     36    implicitlyClosed: {}, 
     37    contextGrabbers: {}, 
     38    doNotIndent: {}, 
     39    allowUnquoted: false, 
     40    allowMissing: false 
     41  }; 
    942  var alignCDATA = parserConfig.alignCDATA; 
    1043 
     
    2659        } 
    2760        else if (stream.match("--")) return chain(inBlock("comment", "-->")); 
    28         else if (stream.match("DOCTYPE")) { 
     61        else if (stream.match("DOCTYPE", true, true)) { 
    2962          stream.eatWhile(/[\w\._\-]/); 
    30           return chain(inBlock("meta", ">")); 
     63          return chain(doctype(1)); 
    3164        } 
    3265        else return null; 
     
    4881    } 
    4982    else if (ch == "&") { 
    50       stream.eatWhile(/[^;]/); 
    51       stream.eat(";"); 
    52       return "atom"; 
     83      var ok; 
     84      if (stream.eat("#")) { 
     85        if (stream.eat("x")) { 
     86          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");           
     87        } else { 
     88          ok = stream.eatWhile(/[\d]/) && stream.eat(";"); 
     89        } 
     90      } else { 
     91        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); 
     92      } 
     93      return ok ? "atom" : "error"; 
    5394    } 
    5495    else { 
     
    101142      } 
    102143      return style; 
     144    }; 
     145  } 
     146  function doctype(depth) { 
     147    return function(stream, state) { 
     148      var ch; 
     149      while ((ch = stream.next()) != null) { 
     150        if (ch == "<") { 
     151          state.tokenize = doctype(depth + 1); 
     152          return state.tokenize(stream, state); 
     153        } else if (ch == ">") { 
     154          if (depth == 1) { 
     155            state.tokenize = inText; 
     156            break; 
     157          } else { 
     158            state.tokenize = doctype(depth - 1); 
     159            return state.tokenize(stream, state); 
     160          } 
     161        } 
     162      } 
     163      return "meta"; 
    103164    }; 
    104165  } 
     
    128189 
    129190  function element(type) { 
    130     if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));} 
    131     else if (type == "closeTag") {popContext(); return cont(endclosetag);} 
    132     else if (type == "string") { 
    133       if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); 
    134       if (curState.tokenize == inText) popContext(); 
    135       return cont(); 
    136     } 
    137     else return cont(); 
     191    if (type == "openTag") { 
     192      curState.tagName = tagName; 
     193      return cont(attributes, endtag(curState.startOfLine)); 
     194    } else if (type == "closeTag") { 
     195      var err = false; 
     196      if (curState.context) { 
     197        if (curState.context.tagName != tagName) { 
     198          if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) { 
     199            popContext(); 
     200          } 
     201          err = !curState.context || curState.context.tagName != tagName; 
     202        } 
     203      } else { 
     204        err = true; 
     205      } 
     206      if (err) setStyle = "error"; 
     207      return cont(endclosetag(err)); 
     208    } 
     209    return cont(); 
    138210  } 
    139211  function endtag(startOfLine) { 
    140212    return function(type) { 
    141213      if (type == "selfcloseTag" || 
    142           (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) 
     214          (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) { 
     215        maybePopContext(curState.tagName.toLowerCase()); 
    143216        return cont(); 
    144       if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();} 
     217      } 
     218      if (type == "endTag") { 
     219        maybePopContext(curState.tagName.toLowerCase()); 
     220        pushContext(curState.tagName, startOfLine); 
     221        return cont(); 
     222      } 
    145223      return cont(); 
    146224    }; 
    147225  } 
    148   function endclosetag(type) { 
    149     if (type == "endTag") return cont(); 
    150     return pass(); 
     226  function endclosetag(err) { 
     227    return function(type) { 
     228      if (err) setStyle = "error"; 
     229      if (type == "endTag") { popContext(); return cont(); } 
     230      setStyle = "error"; 
     231      return cont(arguments.callee); 
     232    }; 
     233  } 
     234  function maybePopContext(nextTagName) { 
     235    var parentTagName; 
     236    while (true) { 
     237      if (!curState.context) { 
     238        return; 
     239      } 
     240      parentTagName = curState.context.tagName.toLowerCase(); 
     241      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || 
     242          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { 
     243        return; 
     244      } 
     245      popContext(); 
     246    } 
    151247  } 
    152248 
    153249  function attributes(type) { 
    154     if (type == "word") {setStyle = "attribute"; return cont(attributes);} 
     250    if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);} 
     251    if (type == "endTag" || type == "selfcloseTag") return pass(); 
     252    setStyle = "error"; 
     253    return cont(attributes); 
     254  } 
     255  function attribute(type) { 
    155256    if (type == "equals") return cont(attvalue, attributes); 
    156     return pass(); 
     257    if (!Kludges.allowMissing) setStyle = "error"; 
     258    return (type == "endTag" || type == "selfcloseTag") ? pass() : cont(); 
    157259  } 
    158260  function attvalue(type) { 
     261    if (type == "string") return cont(attvaluemaybe); 
    159262    if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();} 
    160     if (type == "string") return cont(); 
    161     return pass(); 
     263    setStyle = "error"; 
     264    return (type == "endTag" || type == "selfCloseTag") ? pass() : cont(); 
     265  } 
     266  function attvaluemaybe(type) { 
     267    if (type == "string") return cont(attvaluemaybe); 
     268    else return pass(); 
    162269  } 
    163270 
     
    176283      setStyle = type = tagName = null; 
    177284      var style = state.tokenize(stream, state); 
    178       if ((style || type) && style != "xml-comment") { 
     285      state.type = type; 
     286      if ((style || type) && style != "comment") { 
    179287        curState = state; 
    180288        while (true) { 
     
    187295    }, 
    188296 
    189     indent: function(state, textAfter) { 
     297    indent: function(state, textAfter, fullLine) { 
    190298      var context = state.context; 
    191       if (context && context.noIndent) return 0; 
     299      if ((state.tokenize != inTag && state.tokenize != inText) || 
     300          context && context.noIndent) 
     301        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; 
    192302      if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0; 
    193303      if (context && /^<\//.test(textAfter)) 
     
    203313}); 
    204314 
     315CodeMirror.defineMIME("text/xml", "xml"); 
    205316CodeMirror.defineMIME("application/xml", "xml"); 
    206 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); 
     317if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) 
     318  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); 
  • advanced-code-editor/trunk/readme.txt

    r583191 r607254  
    44Tags: code, theme editor, plugin editor, code editor, WordPress IDE 
    55Requires at least: 3.0 
    6 Tested up to: 3.4.1 
    7 Stable tag: 2.1.4 
     6Tested up to: 3.5 
     7Stable tag: 2.1.5 
    88 
    99Enables syntax highlighting in the integrated themes and plugins source code editors with line numbers, AutoComplete and much more. Supports PHP, HTML, CSS and JS. 
     
    8484 
    8585== Changelog == 
     862.1.5 
     87updated codemirror lib to 2.34. 
     88Fixed New File, New Directory bug in theme editor. 
     89Fixed The auto-formatting has gone crazy issue, I think :) 
     90Cleaned up some CSS code. 
     91 
    86922.1.4 
    8793updated toolbar icons to a more WordPressish look. thanks to Farvig of http://codeshare.bakadesign.dk/ for designing them for us. 
  • advanced-code-editor/trunk/themes/default.css

    r462219 r607254  
    1 .cm-s-default{background-color: #fff;} 
    21.cm-s-default span.cm-keyword {color: #708;} 
    32.cm-s-default span.cm-atom {color: #219;} 
     
    65.cm-s-default span.cm-variable {color: black;} 
    76.cm-s-default span.cm-variable-2 {color: #05a;} 
    8 .cm-s-default span.cm-variable-3 {color: #0a5;} 
     7.cm-s-default span.cm-variable-3 {color: #085;} 
    98.cm-s-default span.cm-property {color: black;} 
    109.cm-s-default span.cm-operator {color: black;} 
    1110.cm-s-default span.cm-comment {color: #a50;} 
    1211.cm-s-default span.cm-string {color: #a11;} 
     12.cm-s-default span.cm-string-2 {color: #f50;} 
    1313.cm-s-default span.cm-meta {color: #555;} 
    1414.cm-s-default span.cm-error {color: #f00;} 
    1515.cm-s-default span.cm-qualifier {color: #555;} 
    1616.cm-s-default span.cm-builtin {color: #30a;} 
    17 .cm-s-default span.cm-bracket {color: #cc7;} 
     17.cm-s-default span.cm-bracket {color: #997;} 
    1818.cm-s-default span.cm-tag {color: #170;} 
    1919.cm-s-default span.cm-attribute {color: #00c;} 
     20.cm-s-default span.cm-header {color: blue;} 
     21.cm-s-default span.cm-quote {color: #090;} 
     22.cm-s-default span.cm-hr {color: #999;} 
     23.cm-s-default span.cm-link {color: #00c;} 
  • advanced-code-editor/trunk/themes/eclipse.css

    r504904 r607254  
    1 .cm-s-eclipse{background-color: #fff;} 
    21.cm-s-eclipse span.cm-meta {color: #FF1717;} 
    3 .cm-s-eclipse span.cm-keyword { font-weight: bold; color: #7F0055; } 
     2.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } 
    43.cm-s-eclipse span.cm-atom {color: #219;} 
    54.cm-s-eclipse span.cm-number {color: #164;} 
     
    2221 
    2322.cm-s-eclipse .CodeMirror-matchingbracket { 
    24 border:1px solid grey; 
    25 color:black !important;; 
     23    border:1px solid grey; 
     24    color:black !important;; 
    2625} 
  • advanced-code-editor/trunk/themes/elegant.css

    r462219 r607254  
    1 .cm-s-elegant{background-color: #fff;} 
    21.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;} 
    3 .cm-s-elegant span.cm-comment {color: #262;font-style: italic;} 
    4 .cm-s-elegant span.cm-meta {color: #555;font-style: italic;} 
     2.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;} 
     3.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;} 
    54.cm-s-elegant span.cm-variable {color: black;} 
    65.cm-s-elegant span.cm-variable-2 {color: #b11;} 
     
    98.cm-s-elegant span.cm-builtin {color: #30a;} 
    109.cm-s-elegant span.cm-error {background-color: #fdd;} 
     10.cm-s-elegant span.cm-link {color: #762;} 
  • advanced-code-editor/trunk/themes/monokai.css

    r504904 r607254  
     1/* Based on Sublime Text's Monokai theme */ 
     2 
    13.cm-s-monokai {background: #272822; color: #f8f8f2;} 
    24.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;} 
  • advanced-code-editor/trunk/themes/neat.css

    r462219 r607254  
    1 .cm-s-neat{background-color: #fff;} 
    21.cm-s-neat span.cm-comment { color: #a86; } 
    3 .cm-s-neat span.cm-keyword { font-weight: bold; color: blue; } 
     2.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } 
    43.cm-s-neat span.cm-string { color: #a22; } 
    5 .cm-s-neat span.cm-builtin { font-weight: bold; color: #077; } 
    6 .cm-s-neat span.cm-special { font-weight: bold; color: #0aa; } 
     4.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } 
     5.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } 
    76.cm-s-neat span.cm-variable { color: black; } 
    87.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } 
    98.cm-s-neat span.cm-meta {color: #555;} 
     9.cm-s-neat span.cm-link { color: #3a3; } 
  • advanced-code-editor/trunk/themes/night.css

    r406416 r607254  
    22 
    33.cm-s-night { background: #0a001f; color: #f8f8f8; } 
    4 .cm-s-night span.CodeMirror-selected { background: #a8f !important; } 
     4.cm-s-night div.CodeMirror-selected { background: #447 !important; } 
    55.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; } 
    66.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; } 
     
    99.cm-s-night span.cm-comment { color: #6900a1; } 
    1010.cm-s-night span.cm-atom { color: #845dc4; } 
    11 .cm-s-night span.cm-number { color: #ffd500; } 
     11.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; } 
    1212.cm-s-night span.cm-keyword { color: #599eff; } 
    1313.cm-s-night span.cm-string { color: #37f14a; } 
    1414.cm-s-night span.cm-meta { color: #7678e2; } 
    15 .cm-s-night span.cm-variable-2 { color: #99b2ff; } 
    16 .cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { white; } 
     15.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; } 
     16.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; } 
    1717.cm-s-night span.cm-error { color: #9d1e15; } 
    1818.cm-s-night span.cm-bracket { color: #8da6ce; } 
    1919.cm-s-night span.cm-comment { color: #6900a1; } 
    2020.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; } 
     21.cm-s-night span.cm-link { color: #845dc4; } 
  • advanced-code-editor/trunk/themes/rubyblue.css

    r504904 r607254  
    1 .cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */ 
     1.cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; }  /* - customized editor font - */ 
    22 
    33.cm-s-rubyblue { background: #112435; color: white; } 
    4 .cm-s-rubyblue div.CodeMirror-selected { background: #0000FF !important; } 
     4.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; } 
    55.cm-s-rubyblue .CodeMirror-gutter { background: #1F4661; border-right: 7px solid #3E7087; min-width:2.5em; } 
    66.cm-s-rubyblue .CodeMirror-gutter-text { color: white; } 
    77.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; } 
    88 
    9 .cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; } 
     9.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } 
    1010.cm-s-rubyblue span.cm-atom { color: #F4C20B; } 
    1111.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } 
Note: See TracChangeset for help on using the changeset viewer.