I added the following to my javascript bundle, over the normal function detection code (but that wouldn't make any difference, right?)
{ name = "meta.function.js"; match = "^\s*([a-zA-Z_]\w*):\s*(function)\s*\(([^)] *)\)"; captures = { 1 = { name = "entity.name.function.js"; }; 2 = { name = "storage.type.function.js"; }; 3 = { name = "variable.parameter.function.js"; }; }; },
{ name = "meta.function.js"; match = "^\s*(var\b)?\s*this\.([a-zA-Z_]\w*)\s*=\ \s*(function)\s*\(([^)]*)\)"; captures = { 1 = { name = "storage.type.js"; }; 2 = { name = "entity.name.function.js"; }; 3 = { name = "storage.type.function.js"; }; 4 = { name = "variable.parameter.function.js"; }; }; },
the first should match functions like
functionName: function(arguments) { ... }
and the second
(var) this.functionName = function(arguments) { ... } with the first var being optional.
Is it correct? It seems to work but I don't dare trust my RegExp skills ;) Any other comments?
Andreas
(var) this.functionName = function(arguments) { ... }
Knowing nothing of javascript... if there are parens around var you didn't include them in the regex.
On matching the contents of the parens you can also use a non-greedy match:
\((.*?)\)
Yours of course will work fine, I just wish I'd figured out non- greedy matches faster when I was learning ;)
On Sep 18, 2005, at 18:07 , Michael Sheets wrote:
(var) this.functionName = function(arguments) { ... }
Knowing nothing of javascript... if there are parens around var you didn't include them in the regex.
On matching the contents of the parens you can also use a non- greedy match:
\((.*?)\)
Yours of course will work fine, I just wish I'd figured out non- greedy matches faster when I was learning ;)
By parens I take it you mean paranthesis? My bad, they aren't supposed to be there, I used them to emphasise that you can skip the var part and thus have either this.functionName = function(arguments) { ... } or var this.functionName = function(arguments) { ... }
On a side note, again ... when do you use non-greedy matches and what are they good for?
Andreas
On a side note, again ... when do you use non-greedy matches and what are they good for?
Regex will look for the biggest match possible, so:
(this) is a (test)
With "\(.*\)" would match the whole string at once. Making it non- greedy *? does the reverse, ends the match as soon as possible. Making the match "(this)", what was intended.
On Sep 18, 2005, at 12:01 PM, Andreas Wahlin wrote:
By parens I take it you mean paranthesis? My bad, they aren't supposed to be there, I used them to emphasise that you can skip the var part and thus have either this.functionName = function(arguments) { ... } or var this.functionName = function(arguments) { ... }
FWIW, the second is not valid JS. The first is valid, as is: var functionName = function( ... ){ ... }, but 'var' must not be followed by a dereferenced object.
On Sep 19, 2005, at 1:23 , Gavin Kistner wrote:
On Sep 18, 2005, at 12:01 PM, Andreas Wahlin wrote:
By parens I take it you mean paranthesis? My bad, they aren't supposed to be there, I used them to emphasise that you can skip the var part and thus have either this.functionName = function(arguments) { ... } or var this.functionName = function(arguments) { ... }
FWIW, the second is not valid JS. The first is valid, as is: var functionName = function( ... ){ ... }, but 'var' must not be followed by a dereferenced object.
Hupps, you're absolutely right, can't believe I wrote that, I blame my not having any private functions in the object I was looking at :) It's supposed to be
var functionName = function(arguments) { ... } right?
back to the old drawing board Andreas
FWIW, the second is not valid JS. The first is valid, as is: var functionName = function( ... ){ ... }, but 'var' must not be followed by a dereferenced object.
I then had to split it up into two
{ name = "meta.function.js"; match = "^\s*this\.([a-zA-Z_]\w*)\s*=\s*(function)\ \s*\(([^)]*)\)"; captures = { 1 = { name = "entity.name.function.js"; }; 2 = { name = "storage.type.function.js"; }; 3 = { name = "variable.parameter.function.js"; }; }; }, { name = "meta.function.js"; match = "^\s*(var\b)?\s*([a-zA-Z_]\w*)\s=\s* (function)\s*\(([^)]*)\)"; captures = { 1 = { name = "storage.type.js"; }; 2 = { name = "entity.name.function.js"; }; 3 = { name = "storage.type.function.js"; }; 4 = { name = "variable.parameter.function.js"; }; }; },
is there a better way?
Then I realized that you can also do it by prototype, thusly object.prototype.functionName = function(arguments) { ... } and made the following
{ name = "meta.function.js"; match = "^\s*[a-zA-Z_]\w*\.(prototype)\.([a-zA-Z_]\ \w*)\s=\s*(function)\s*\(([^)]*)\)"; captures = { 1 = { name = "support.constant.js"; }; 2 = { name = "entity.name.function.js"; }; 3 = { name = "storage.type.function.js"; }; 4 = { name = "variable.parameter.function.js"; }; }; },
only problem here, is that the "object" isn't catched. For istance, I have Array.prototype.get = function(get) { ... } but Array does not get the support.class.js scope, how would one solve this?
Andreas
{ name = "meta.function.js"; match = "^\\s*(var\\b)?\\s*([a-zA-Z_]\\w*)\\s=\\s*
(function)\s*\(([^)]*)\)"; captures = { 1 = { name = "storage.type.js"; }; 2 = { name = "entity.name.function.js"; }; 3 = { name = "storage.type.function.js"; }; 4 = { name = "variable.parameter.function.js"; }; }; },
Ar, I'll never get it right! The question mark up there near var should of course be removed, thus match = "^\s*(var\b)\s*([a-zA-Z_]\w*)\s=\s* (function)\s*\(([^)]*)\)";
hope someone finds this useful :)
Andreas
On 19/09/2005, at 10.53, Andreas Wahlin wrote:
I then had to split it up into two [...] is there a better way?
You can use alternation: (foo|bar). So combined it'd be:
match = "^\s*(?:this\.|(var\b)?\s*)([a-zA-Z_]\w*)\s*=\s* (function)\s*\(([^)]*)\)";
I used the (?:foo|bar) form to avoid making it a capture. It is btw possible to prefix the expression with (?x) to enter “extended’ mode where whitespace and comments are ignored, so we can pretty print it:
match = "(?x) ^\s* # begin-of-line + leading space (?: this\. # literal this. | (var\s+) # -> or literal var (capture #1) | # -> or nothing ) ([a-zA-Z_]\w*)\s* # actual function name (capture #2) =\s* # literal = (function)\s* # function keyword (capture #3) \(([^)]*)\) # the parameters (capture #4) ";
Don't know if you find that more readable or not…
You can use alternation: (foo|bar). So combined it'd be:
match = "^\\s*(?:this\\.|(var\\b)?\\s*)([a-zA-Z_]\\w*)\\s*=\\s*
(function)\s*\(([^)]*)\)";
I used the (?:foo|bar) form to avoid making it a capture. It is btw possible to prefix the expression with (?x) to enter “extended’ mode where whitespace and comments are ignored, so we can pretty print it:
match = "(?x) ^\\s* # begin-of-line + leading space (?: this\\. # literal this. | (var\\s+) # -> or literal var (capture #1) | # -> or nothing ) ([a-zA-Z_]\\w*)\\s* # actual function name (capture #2) =\\s* # literal = (function)\\s* # function keyword (capture #3) \\(([^)]*)\\) # the parameters (capture #4) ";
Don't know if you find that more readable or not…
"That'll work to" - Jet Li's The One :)
<That page shows 'private' functions, 'privileged' functions, and public functions. If the examples don't answer your question, feel free to contact me off-list (as I fear we're straying far from TextMate topics. ;)>
Thanks a lot Gavin, great page! I got the idea from Crockford from the beginning, but this seems a bit more comprehensive.
Andreas
On Sep 19, 2005, at 8:14 AM, Allan Odgaard wrote:
I used the (?:foo|bar) form to avoid making it a capture. It is btw possible to prefix the expression with (?x) to enter “extended’ mode where whitespace and comments are ignored, so we can pretty print it:
FINALLY! :-)
Any chance of getting the expanded JavaScript function detection added to the default bundle? Reason I ask is that *blush* I managed to misplace my originals, and apart from that I also want to be as "standard compatible" as possible, meaning to have as little customized stuff as possible, preferably limiting my customization to snippets only. There's no big rush though ...
Andreas
The effects were mainly that of all the possible ways for JavaScript to declare functions, covered in part by Gavin here http://phrogz.net/JS/Classes/OOPinJS.html
I believe all are
function funcName(arg) { .. } this.funcName = function(arg) { ... }; var funcName = function(arg) { ... }; object.prototype.funcName = function(arg) { ... };
and then instead of function(arg) { ... }; you can have new Function("arg", "..."); so for example this.funcName = new Function("arg1", "arg2", "alert (arg1+arg2);");
If anyone could confirm this it would be quite nice :)
Andreas
On Oct 9, 2005, at 10:51 , Allan Odgaard wrote:
On 08/10/2005, at 18.03, Andreas Wahlin wrote:
Any chance of getting the expanded JavaScript function detection added to the default bundle?
What was the consensus on these? I seem to recall several versions with comments?!?
For new threads USE THIS: textmate@lists.macromates.com (threading gets destroyed and the universe will collapse if you don't) http://lists.macromates.com/mailman/listinfo/textmate
On Oct 9, 2005, at 3:56 AM, Andreas Wahlin wrote:
The effects were mainly that of all the possible ways for JavaScript to declare functions, covered in part by Gavin here http://phrogz.net/JS/Classes/OOPinJS.html
I believe all are
function funcName(arg) { .. } this.funcName = function(arg) { ... }; var funcName = function(arg) { ... }; object.prototype.funcName = function(arg) { ... };
and then instead of function(arg) { ... }; you can have new Function("arg", "..."); so for example this.funcName = new Function("arg1", "arg2", "alert (arg1+arg2);");
If anyone could confirm this it would be quite nice :)
Those are all correct; slightly missing is the fact that any of the function literals (using the function keyword) can be followed by funcName, and a couple other ways you could create a named function (anywhere you can assign a value to a variable, you can use a function literal). So, in addition to the above:
this.funcName = function funcLabel ( args ) { ... } var functName = function funcLabel ( args ) { ... }
obj[ 'funcName' ] = function ( args ) { ... } obj[ 'funcName' ] = function funcLabel ( args ) { ... }
var foo = { count : 1, toString : function( ) { return this.count } } var foo = { count : 1, toString : function funcName ( ) { return this.count } } var foo = [ function ( ) { ... }, function ( ) { ... }, function ( ) { ... } ] var foo = [ function foo ( ) { ... }, function bar ( ) { ... }, function jammy ( ) { ... } ]
... and all the above with the new Function constructor as well.
Though it would be possible to account for all of the above explicitly, if *I* were writing the syntax highlighting regexp, I think I'd be lazy and simply do:
{ name = 'meta.function.js'; match = '\b(function)(\s+[a-zA-Z_]\w*)?\s*((.*?))'; captures = { 1 = { name = 'storage.type.function.js'; }; 2 = { name = 'entity.name.function.js'; }; 3 = { name = 'variable.parameter.function.js'; }; }; },
and leave all the numerous ways that you can store pointers to this object without the benefit of an explicit "entity.name.function.js" label for the variable. (And leave Function to be handled under the current support.function.js).
On 09/10/2005, at 16.11, Gavin Kistner wrote:
[...] if *I* were writing the syntax highlighting regexp, I think I'd be lazy and simply do:
Thanks, so I'll be committing this patch:
Index: JavaScript.plist =================================================================== --- JavaScript.plist (revision 1895) +++ JavaScript.plist (working copy) @@ -39,7 +39,7 @@ </dict> </dict> <key>match</key> - <string>^\s*(function)\s+([a-zA-Z_]\w*)\s*(([^)]*))</string> + <string>\b(function)(\s+[a-zA-Z_]\w*)?\s*((.*?))</string> <key>name</key> <string>meta.function.js</string> </dict>
Sadly, the below does not allow for symbol navigation on the more fancy function declarations, it's not at all critical, but it would be somewhat nice :) However, it does capture the scopes of stuff correctly, so syntax colouring is better, yay!
Andreas
[...] if *I* were writing the syntax highlighting regexp, I think I'd be lazy and simply do:
Thanks, so I'll be committing this patch:
Index: JavaScript.plist
--- JavaScript.plist (revision 1895) +++ JavaScript.plist (working copy) @@ -39,7 +39,7 @@ </dict> </dict> <key>match</key>
<string>^\s*(function)\s+([a-zA-Z_]\w*)\s*\(([^)]*)\)</
string>
<string>\b(function)(\s+[a-zA-Z_]\w*)?\s*\((.*?)\)</string> <key>name</key> <string>meta.function.js</string> </dict>
On Sep 19, 2005, at 2:19 AM, Andreas Wahlin wrote:
On Sep 19, 2005, at 1:23 , Gavin Kistner wrote:
FWIW, the second is not valid JS. The first is valid, as is: var functionName = function( ... ){ ... }, but 'var' must not be followed by a dereferenced object.
Hupps, you're absolutely right, can't believe I wrote that, I blame my not having any private functions in the object I was looking at :) It's supposed to be
var functionName = function(arguments) { ... } right?
Yup, that would create a local variable pointing to the functionName object. (The exact same functionality as using simply: function functionName(arguments){ ... }
On Sep 19, 2005, at 6:57 AM, Andreas Wahlin wrote:
Yup, that would create a local variable pointing to the functionName object. (The exact same functionality as using simply: function functionName(arguments){ ... }
How do you make those declarations public?
http://phrogz.net/JS/Classes/OOPinJS.html
That page shows 'private' functions, 'privileged' functions, and public functions. If the examples don't answer your question, feel free to contact me off-list (as I fear we're straying far from TextMate topics. ;)