fixed bug #7256: highlight matching curly brackets * fixed bug #6834: Wrong syntax...
authorIngo Renner <ingo.renner@typo3.org>
Sat, 26 Jan 2008 10:50:16 +0000 (10:50 +0000)
committerIngo Renner <ingo.renner@typo3.org>
Sat, 26 Jan 2008 10:50:16 +0000 (10:50 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2966 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/t3editor/css/t3editor.css
typo3/sysext/t3editor/jslib/select.js
typo3/sysext/t3editor/jslib/t3editor.js
typo3/sysext/t3editor/jslib/tokenizetyposcript.js

index 49fb8de..df9c8be 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,9 @@
        * made tables in Web->List view fill the whole document by adding css style width of 98%
        * updated prototype to 1.6.0.2
        * fixed bug #7270: Shortcut menu does not load user's shortcuts if user is not admin, credits Stig Nørgaard Færch
+       * fixed bug #7256: highlight matching curly brackets, credits Tobias Liebig
+       * fixed bug #6834: Wrong syntax highlighting in wrong context, credits Tobias Liebig
+       * fixed bug #7255: implement "auto-closing brackets", credits Tobias Liebig
 
 2008-01-26  Oliver Hader  <oh@inpublica.de>
 
index 4c83930..505fe66 100755 (executable)
 }
 
 
-/* Syntax highlighting */
-
-span.part {
-       color: #666;
-}
-
-span.other {
-       color: black;
-}
-
-span.reserved, .t3e_autoCompleteBox ul li span.word_reserved {
-  color: #770088;
-}
-
-span.keyword, .t3e_autoCompleteBox ul li span.word_keyword {
-       color: #0000cc;
-       font-weight: bold;
-       font-size: 0.95em;
-}
-
-span.keyword2, .t3e_autoCompleteBox ul li span.word_keyword2 {
-       color: #0000cc;
-}
-
-span.keyword3, .t3e_autoCompleteBox ul li span.word_keyword3 {
-       color: #0000ff;
-}
-
-
-span.prop {
-       color: #00f;
-}
-
-span.operator {
-       color: #f00;
-}
-span.punctuation {
-       color: #c00;
-}
-
-span.atom {
-  color: #448888;
-}
-
-span.variable {
-  color: black;
-}
-
-/*
-span.variabledef {
-  color: #0000FF;
-}
-
-span.localvariable {
-  color: #004499;
-}
-
-span.property {
-  color: black;
-}
-*/
-
-span.comment {
-  color: #AA7700;
-}
-
-span.string {
-  color: #AA2222;
-}
+/*********************************************
+ * Syntax highlighting
+ *********************************************/
+
+span.other { color: black; }
+.ts-operator { color: black; font-weight: bold; }
+.ts-value { color: #cc0000; }
+.ts-objstr, .keyword, .keyword2, .keyword3, .reserved { color: #0000cc; }
+.ts-value_copy { color: #006600; }
+.ts-value_unset { background-color: #66cc66; }
+.ts-ignored { background-color: #66cc66; }
+.ts-default { background-color: #66cc66; }
+.ts-comment { color: #666; font-style: italic; }
+.ts-condition { background-color: maroon; color: #fff; font-weight: bold; }
+.ts-error { background-color: yellow; border: 1px red dashed; font-weight: bold; }
+.highlight-bracket {background-color: #0c0; color: #fff; }
+.error-bracket {background-color: #d00; color: #fff; }
 
 /* unparsed code */
 pre.code, .editbox {
@@ -90,6 +38,7 @@ pre.code, .editbox {
 }
 
 
+
 /* around the editor */
 .t3e_outerdiv {
        border: 1px solid gray;
index 2cf957c..192f9e2 100755 (executable)
@@ -345,6 +345,18 @@ var select = {};
         selectRange(range, window);
       }
     }; 
+  
+       // added for t3editor
+    select.insertNodeAtCursor = function(window,node) {
+      var selection = window.getSelection();
+      if (selection && selection.rangeCount > 0) {
+        var range = selection.getRangeAt(0);
+        range.insertNode(node);
+        range.setEndAfter(node);
+        range.collapse(false);
+        selectRange(range, window);
+      }
+    }; 
   }
 
   // Search backwards through the top-level nodes until the next BR or
index a358790..93d4319 100755 (executable)
@@ -939,6 +939,7 @@ var t3editor = function(){
     click: function()  {
         if (this.ac === 1){this.ac = 0;this.autoCompleteBox.hide();}
         this.refreshCursorObj();
+        this.checkBracketAtCursor();
     },
 
     // Split a chunk of code into lines, put them in the frame, and
@@ -1065,7 +1066,7 @@ var t3editor = function(){
         this.markCursorDirty();
         this.checkTextModified();
         window.setTimeout('t3e_instances['+this.index+'].checkHistoryChanges();',100);
-         }
+      }
          
        if (this.ac===1){ // if autocomplete now is not finish, but started and continue typing - refresh autocomplete box
             this.getLastWord();
@@ -1083,6 +1084,7 @@ var t3editor = function(){
       }
        
       this.refreshCursorObj();
+      this.checkBracketAtCursor();
     },
        
     refreshCursorObj: function () {
@@ -1165,10 +1167,80 @@ var t3editor = function(){
       return cursor;
     },
 
+       checkBracketAtCursor: function()        {
+               var cursor = new select.Cursor(this.container);
+        this.cursorObj = cursor.start;
+        
+               // remove current highlights
+               Selector.findChildElements(this.doc,$A(['.highlight-bracket','.error-bracket'])).each(function(item) {
+                       item.className = item.className.replace(' highlight-bracket','');
+                       item.className = item.className.replace(' error-bracket','');
+               });
+               
+               if (!cursor.start || !cursor.start.className) return;
+               
+               // if cursor is behint an bracket, we search for the matching one
+               
+               // we have an opening bracket, search forward for a closing bracket
+               if (cursor.start.className.indexOf('curly-bracket-open') != -1) {
+                       var maybeMatch = cursor.start.nextSibling;
+                       var skip = 0;
+                       while(maybeMatch) {
+                               if (maybeMatch.className.indexOf('curly-bracket-open') != -1) {
+                                       skip++;
+                               }
+                               if (maybeMatch.className.indexOf('curly-bracket-close') != -1) {
+                                       if (skip > 0) {
+                                               skip--;
+                                       } else {
+                                               maybeMatch.className += ' highlight-bracket';
+                                               cursor.start.className += ' highlight-bracket';
+                                               break;
+                                       }
+                               }
+                               maybeMatch = maybeMatch.nextSibling;
+                       }
+               }
+               // we have a closing bracket, search backward for an opening bracket
+               if (cursor.start.className.indexOf('curly-bracket-close') != -1) {
+                       var maybeMatch = cursor.start.previousSibling;
+                       var skip = 0;
+                       while(maybeMatch) {
+                               if (maybeMatch.className.indexOf('curly-bracket-close') != -1) {
+                                       skip++;
+                               }
+                               if (maybeMatch.className.indexOf('curly-bracket-open') != -1) {
+                                       if (skip > 0) {
+                                               skip--;
+                                       } else {
+                                               maybeMatch.className += ' highlight-bracket';
+                                               cursor.start.className += ' highlight-bracket';
+                                               break;
+                                       }
+                               }
+                               maybeMatch = maybeMatch.previousSibling;
+                       }
+               }
+               
+               if (cursor.start.className.indexOf('curly-bracket-') != -1
+                     && maybeMatch == null) {
+                       cursor.start.className += ' error-bracket';
+               }
+               
+       },
+       
+       autoCloseBracket: function(prevNode) {
+      if (prevNode && prevNode.className.indexOf('curly-bracket-open') != -1) {
+               select.insertNodeAtCursor(this.win, new Element('BR'));
+               select.insertTextAtCursor(this.win, "}");
+      }
+       },
+       
     // Adjust the amount of whitespace at the start of the line that
     // the cursor is on so that it is indented properly.
     indentAtCursor: function() {
       var cursor = new select.Cursor(this.container);
+      
       // The line has to have up-to-date lexical information, so we
       // highlight it first.
       cursor = this.highlightAtCursor(cursor);
@@ -1180,6 +1252,9 @@ var t3editor = function(){
       // start is the <br> before the current line, or null if this is
       // the first line.
       var start = cursor.startOfLine();
+      
+      this.autoCloseBracket(start.previousSibling);
+      
       // whiteSpace is the whitespace span at the start of the line,
       // or null if there is no such node.
       var whiteSpace = start ? start.nextSibling : this.container.lastChild;
@@ -1298,6 +1373,8 @@ var t3editor = function(){
       select.selectMarked(sel);
          if (start)
         this.scheduleHighlight();
+      
+      this.checkBracketAtCursor();
     }
   }
 
index 0556099..58c25ee 100755 (executable)
@@ -1314,7 +1314,7 @@ var tokenizeTypoScript = function(){
         }
         maybeEnd = (next == "*");
       }
-      return result("comment", "comment");
+      return result("comment", "ts-comment");
     }
 
     // Fetch the next token. Dispatches on first character in the
@@ -1326,33 +1326,64 @@ var tokenizeTypoScript = function(){
       var ch = source.next();
       if (ch == "\n")
         token = {type: "newline", style: "whitespace", value: source.get()};
+        
       else if (this.inComment)
         token = readMultilineComment.call(this, ch);
+      
       else if (isWhiteSpace(ch))
         token = nextWhile(isWhiteSpace) || result("whitespace", "whitespace");
+      
       else if (ch == "\"" || ch == "'")
         token = nextUntilUnescaped(ch) || result("string", "string");
+      
+      else if (ch == "<")
+        token = nextUntilUnescaped("\n") || result("value", "ts-value_copy");
+        
+      else if (ch == ">")
+        token = nextUntilUnescaped("\n") || result("value", "ts-value_unset");
+      
+      else if (ch == "=")
+        token = nextUntilUnescaped("\n") || result("value", "ts-value");
+      
+      else if (ch == "[")
+        token = nextUntilUnescaped("]") || result("condition", "ts-condition");
+        
       // with punctuation, the type of the token is the symbol itself
-      else if (/[\[\]{}\(\),;\:\.]/.test(ch))
-        token = result(ch, "punctuation");
+      else if (/[\[\]\(\),;\:\.]/.test(ch))
+        token = result(ch, "ts-operator");
+        
+      else if (ch == "{")
+        token = result(ch, "ts-operator curly-bracket-open");
+      
+      else if (ch == "}")
+        token = result(ch, "ts-operator curly-bracket-close");
+      
       else if (ch == "0" && (source.peek() == "x" || source.peek() == "X"))
         token = readHexNumber();
+      
       else if (isDigit(ch))
         token = readNumber();
+      
       else if (ch == "/"){
         next = source.peek();
         if (next == "*")
           token = readMultilineComment.call(this, ch);
+      
         else if (next == "/")
-          token = nextUntilUnescaped(null) || result("comment", "comment");
+          token = nextUntilUnescaped(null) || result("comment", "ts-comment");
+      
         else if (this.regexp)
           token = readRegexp();
+      
         else
-          token = nextWhile(isOperatorChar) || result("operator", "operator");
+          token = nextWhile(isOperatorChar) || result("operator", "ts-operator");
+      
       } else if (ch == "#")
-        token = nextUntilUnescaped(null) || result("comment", "comment");
+        token = nextUntilUnescaped(null) || result("comment", "ts-comment");
+      
       else if (isOperatorChar(ch))
-        token = nextWhile(isOperatorChar) || result("operator", "operator");
+        token = nextWhile(isOperatorChar) || result("operator", "ts-operator");
+      
       else
         token = readWord();