March 27th, 2008

Recursively grep for a substring, open all results in TextPad with cursor positioned appropriately

I’ve been using Ext-JS on a new project, recently. It’s pretty neat, and the examples are impressive, but the documentation leaves a lot to be desired. I needed to make a section of a we page collapsible, and it seemed like the Ext.Panel class was the way to do that, but I was having trouble figuring out exactly how to get my existing HTML content into a collapsible Ext.Panel. Almost as a last resort, I ended up grepping my local ext-2.0/examples directory tree to find examples that instantiate Ext.Panel objects:

$ grep -Ri “new Ext.Panel” *
code-display.js: var panel = new Ext.Panel({
core/templates.js: var p = new Ext.Panel({
core/templates.js: var p2 = new Ext.Panel({
feed-viewer/MainPanel.js: this.preview = new Ext.Panel({
feed-viewer/MainPanel.js: tab = new Ext.Panel({z
[…]

This was not very useful. I needed to see the whole constructor invocation for each of those cases. So, I decided to grep again, showing just the filenames (using the -l parameter), so I could open all of those files in TextPad. The first part of that (showing just the filenames) was the easy part:

$ grep -Rli “new Ext.Panel” *
code-display.js
core/templates.js
feed-viewer/MainPanel.js
form/combos.js
form/custom.js
[…]

Next, I needed to change those file paths from cygwin/unix-style paths to windows paths, so they could be passed to TextPad on the command-line. Time for a for loop:

$ for f in `grep -Rli “new Ext.Panel” *`; do cygpath -w -a $f; done
c:\api\js\ext-2.0\examples\code-display.js
c:\api\js\ext-2.0\examples\core\templates.js
c:\api\js\ext-2.0\examples\feed-viewer\MainPanel.js
c:\api\js\ext-2.0\examples\form\combos.js
c:\api\js\ext-2.0\examples\form\custom.js
[…]

Okay, so I could have probably built an environment variable as I was looping through and converting these paths, but if I ever wanted to run this on a longer path, with more search results, that command-line could get extremely long.

So, I checked the TextPad help to see if I could pass in the name of a file containing full file paths for TextPad to open. Sure enough:

@filename
Open all the files that are listed, one per line, in the specified file. This overrides the option to load the workspace, specified on the General page of the Preferences dialog box.

You just need to put an at sign (@) before the filename, and TextPad will look at that file to find a list of files to open. So, I decided to create a temporary file, output the filenames found and converted by my set of commands (above) into that temporary file, and then run TextPad, passing the temporary filename preceded by an @ sign.

But wait! I noticed something else in the TextPad help that seemed like a cool idea:

Notes:

  • [...]
  • If the filename to be edited (not printed) is followed by “(
    <line>[,<col>])”, with no intervening spaces, the file will be opened with the cursor at that position. If
    <line> is a hex number (eg. 0×1a22), a hex view of the file will be created, with the cursor at that address.
eg. TEXTPAD.EXE -ac "Read me.txt"(51,20)
In this example TextPad will start up and open "Read me.txt" at line 51, column 20 and display it in a cascaded window.

So, I decided to figure out a way to put the filenames to open, as well as the row and column number to position the cursor at within each of those files, into the temporary file that I was going to pass to TextPad. I already knew how to get grep to output line numbers (using the -n parameter), so I thought that would be the easy part.

However, it seems that you can’t specify both the -l (show filenames) and -n (show line numbers) parameters on the grep commandline. No, -l does more than simply tell it to show the filename next to each matching line (-H does that). -l tells it to ONLY show the filenames. Here’s the -l parameter definition from the grep man page:

-l, --files-with-matches
Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match.

As far as I could tell, if I wanted line numbers and filenames, I needed to use -n and -H, and deal with the fact that the output would also include the text of the matching line. I also threw in -m 1 to limit the output to only one result per file, since the cursor can only be positioned in one place for each file. I didn’t need the -m previously, because the -l parameter already limited it to one result per file, since it only showed the filenames of each matching file. Here’s what the grep commandline and output looked like, at this point:

$ grep -RHn -m 1 “new Ext.Panel” *
code-display.js:11: var panel = new Ext.Panel({
core/templates.js:30: var p = new Ext.Panel({
feed-viewer/MainPanel.js:10: this.preview = new Ext.Panel({
form/combos.js:49: new Ext.Panel({
form/custom.js:40: var panel = new Ext.Panel({
[…]

At first, I thought the matching line text was just in my way, so I used sed to filter it out, and to replace the colon (:) between the filename and the line number with an open parenthesis, to prepare it for the format TextPad wanted:

$ grep -RHn -m 1 “new Ext.Panel” * | sed -e ’s/\(^[^:]\+\):\([0-9]\+\):.*$/\1(\2/g’
code-display.js(11
core/templates.js(30
feed-viewer/MainPanel.js(10
form/combos.js(49
form/custom.js(40
[…]

Next, I needed to get the offsets or column numbers for each matching line number that the previous command returned, to tell TextPad exactly where to put the cursor in each file. At first, I thought I could do this with grep, but the closest grep parameter seemed to be -b:

-b, --byte-offset
Print the byte offset within the input file before each line of output

However, -b gives the absolute byte offset starting from the very beginning of the file, rather than the offset within the matching lines. So, I had to find a different way to get the column offset within each matching line. This is when I realized that having the matching line text returned by my grep command could actually be useful. I figured I could just split that text out and count the characters leading up to the matching string with wc -c, among other things.

Anyways, after a lot of trial and error, a lot of re-checking man pages for bash, grep, wc, etc., I ended up with the following set of commands:

textpad $(for g in `for f in \`grep -Rli "new Ext.Panel" *\`; do (grep -Hn -m 1 "new Ext.Panel" $f | sed -e 's/\(^[^:]\+\):\([0-9]\+\):.*$/\1(\2/g'); done`; do echo `cygpath -w -a ${g/\(*/}`\(${g/*\(/},`grep -m 1 "new Ext.Panel" ${g/(*/} | sed -e 's/\t/ /g' -e 's/new Ext.Panel.*$//g' | wc -c`\); done) &

I’m sure this could be done more efficiently, but this was a fun challenge to take on, and I managed to find a way to do what I wanted to do. Feel free to leave a comment if you know a better way of doing this!

November 20th, 2006

JavaScript: list of implicit true/false values

I got tired of sometimes wondering whether I could use a particular JavaScript value effectively in a conditional statement…
For instance, if I’m in the middle of a block of JS code, and am not 100% sure what the value of a variable will be, is it safe to say:

if (foo)

or do I need to explicitly look at the value of foo, like:

if ((typeof foo != 'undefined') &&
(foo != null) &&
(foo != ''))

So, I took a little time one day, recently, and checked how various values are evaluated in JavaScript. I believe I gathered this info using IE6. Hopefully that fact is not important. Might be worth checking in Firefox one of these days, just to be sure.

false false
0 false
0.0 false
null false
false
undefined false
NaN false
true true
Infinity true
‘ ‘ true
1 true
-1 true
2 true
-2 true
0.1 true
‘0′ true
‘1′ true
‘-1′ true
‘null’ true
‘true’ true
‘false’ true
‘TRUE’ true
‘FALSE’ true

October 18th, 2006

javascript functions have a reference to themselves

I needed one of my javascript functions to be able to pass itself as a reference to another function, so I asked a couple friends if they knew if functions have a reference to themselves. They weren’t sure, so I googled it, and learned about arguments.callee:

callee is a property of the arguments local variable available within all function objects. […]

arguments.callee allows anonymous functions to refer to themselves, which is necessary for recursive anonymous functions.

The this keyword does not refer to the currently executing function. Use the callee property to refer to a function within the function body.

Just what I needed!

August 10th, 2006

How to list just directories in bash

This morning, I was trying to find a way to list just the subdirectories in the current directory, in a bash shell script I was writing. I thought it would be simple, but everything I tried seemed to either take an extraordinarily long time, or felt like an ugly hack.

The first thing I tried was:
find . -type d

But this was extremely slow, because it was recursively searching inside every subdirectory as well. I just wanted a list of subdirectories inside the current directory. I won’t bore you/clutter this post up with any more of my less-than-ideal methods.

What follows are a couple of ways of doing what I was trying to do, which I found in a post (and its comments) on the Ubuntu Blog, “List only the directories“:

ls -l | grep ā€œ^dā€

This works, but gives a ‘long’ directory listing, when all I wanted was a list of directory names.


find . -type d -maxdepth 1 -mindepth 1This one was my favorite, since it used the method I originally tried, but it fixed the slowness by using parameters to avoid recursion. It gave me a couple warnings about the order of the parameters, though, so I changed it to this:
find . -maxdepth 1 -mindepth 1 -type d


ls -d */This gave me the same output as the ‘find’ method did, but some timing tests showed me that the ‘find’ method was about 2 times faster.

July 17th, 2006

Name your own price on dental products

  1. go to http://www.dentist.net
  2. find the product you want
  3. enter in address bar:
    javascript:void(document.onmousedown=ra)
  4. firefox web developer toolbar:
    Forms | Display Form Details
    Forms | Make Form Fields Writable
  5. edit text input named ‘price‘.
    click ‘add to cart’ button
  6. laugh



Of course, I would not really proceed through checkout with any cart created inappropriately, but it was fun to play with a little bit.

Ordinarily, I’d contact a company to let them know about a gaping security hole like this, but…

  1. I’m still bitter about them crippling my browser
  2. My blogs don’t have very many readers
  3. I’m confident that they would catch even the slightest modified order parameters, because, “We are Fraud Smart and pursue fraudulent orders to the full extent of the law.” (from checkout page)