Newbie: Scripting a better HOME button?

170 views
Skip to first unread message

offtone

unread,
Jul 29, 2010, 4:37:52 PM7/29/10
to BBEdit Talk
I'm more of a web developer and am brand new to OS X/Apple as of last
month. My PC editors had a sorely-missed feature that basically
enabled the HOME button on my keyboard to intelligently go to the
"real" beginning of the line I was on. That is, it would place the
insertion point after ^\s+ on that line, essentially.

The problem: I have no idea where to start on this... I have a feeling
that once I get started in Apple Script for BBEdit, I'm going to be
making all kinds of handy things, but this feature is the one I miss
most, so it's my first.

Anyone have any advice to get me started? Haha. Don't write it for
me... No fun in that. I'm just not sure how to access the active line,
or how to move the insertion point. I think from there, I'd be well on
my way.

Thanks!

Kendall Conrad

unread,
Jul 29, 2010, 5:51:13 PM7/29/10
to BBEdit Talk
From AppleScript Editor you can open dictionaries for each
application. Check out BBEdit's and look for the pieces that let you
look at the current line, then you can make use of the regex you gave
combined with grep search and you should be on your way pretty
quickly. Getting use to the Applescript language will be the biggest
hurdle.

-Kendall

Alex Satrapa

unread,
Jul 29, 2010, 6:24:14 PM7/29/10
to bbe...@googlegroups.com
BBEdit User Manual -> Use Numeric Keypad for Cursor Movement

No need to script stuff that already works.

Alex Satrapa | web.mac.com/alexsatrapa | Ph: 0407 705 332

Gabriel Roth

unread,
Jul 29, 2010, 6:28:19 PM7/29/10
to bbe...@googlegroups.com
> BBEdit User Manual -> Use Numeric Keypad for Cursor Movement
>
> No need to script stuff that already works.

The original poster wants to be able to move the cursor to a position
immediately before the first non-whitespace character of the current
line. The best the numeric keypad option can do is move it to the very
start of the line.

>
> Alex Satrapa | web.mac.com/alexsatrapa | Ph: 0407 705 332
>
> On 30/07/2010, at 6:37, offtone <aar...@gmail.com> wrote:
>
>> My PC editors had a sorely-missed feature that basically
>> enabled the HOME button on my keyboard to intelligently go to the
>> "real" beginning of the line I was on.
>

> --
> You received this message because you are subscribed to the
> "BBEdit Talk" discussion group on Google Groups.
> To post to this group, send email to bbe...@googlegroups.com
> To unsubscribe from this group, send email to
> bbedit+un...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/bbedit?hl=en
> If you have a feature request or would like to report a problem,
> please email "sup...@barebones.com" rather than posting to the group.

Alex Satrapa

unread,
Jul 29, 2010, 7:07:16 PM7/29/10
to bbe...@googlegroups.com
On 30/07/2010, at 08:28 , Gabriel Roth wrote:

>> BBEdit User Manual -> Use Numeric Keypad for Cursor Movement
>>
>> No need to script stuff that already works.
>
> The original poster wants to be able to move the cursor to a position
> immediately before the first non-whitespace character of the current
> line. The best the numeric keypad option can do is move it to the very
> start of the line.

whoops - my bad!

Toadling

unread,
Jul 29, 2010, 7:07:57 PM7/29/10
to bbe...@googlegroups.com
On Jul 29, 2010, at 3:28 PM, Gabriel Roth wrote:

> The original poster wants to be able to move the cursor to a position
> immediately before the first non-whitespace character of the current
> line. The best the numeric keypad option can do is move it to the very
> start of the line.

I think the best you could do *without* a script is two key combinations: Command-Left Arrow to move the cursor to the beginning of the line, followed by an Option-Right Arrow to move to the position of the first non-whitespace character (this can also be done with the numeric keypad or emacs key bindings).

To do it with a single key combination, however, I think a script is required. Try something like this:

1. Read about scripting searches in the BBEdit User Manual (page 316). You can open the manual from BBEdit's Help menu.

2. In your script, tell BBEdit to move the cursor to the beginning of the current line.

3. Tell BBEdit to perform a scripted grep search for the first non-whitespace character (\S).

4. If a match is found, tell BBEdit to position the cursor before the matching character (select insertion point before...).

5. Test for fringe cases and debug as necessary.

6. Save your new script to ~/Library/Application Support/BBEdit/Scripts/.

7. Assign a key combination using the Scripts palette (Window -> Palettes -> Scripts).

Hope this helps.

-Dennis

John Delacour

unread,
Jul 29, 2010, 7:30:14 PM7/29/10
to bbe...@googlegroups.com
At 14:51 -0700 29/7/10, Kendall Conrad wrote:

> From AppleScript Editor you can open dictionaries for each
>application. Check out BBEdit's and look for the pieces that let you
>look at the current line, then you can make use of the regex you gave
>combined with grep search and you should be on your way pretty
>quickly. Getting use to the Applescript language will be the biggest
>hurdle.

You bet! for someone who's only had a Mac for a month. Likely to send
a man howling back to Windows!

First it's worth pointing out that command+leftarrow take the
insertion point to the beginning of the line in any Mac editor and
adding the shift key selects all text from the insertion point to the
beginning of the line.

But to answer the question...

... if you paste the script below into Script Editor or Smile and
save it (as script) in your BBEdit Scripts folder, which you will
locate using the Scripts menu (scroll thing) in BBEdit...


tell application "BBEdit"
set _n to startLine of selection
tell the front document
set _line to contents of line _n
set _chars to characters of _line
repeat with _i from 1 to count _chars
if item _i of _chars is not in {space, tab} then
set _start to _i
exit repeat
end if
end repeat
select insertion point before character _start of line _n
end tell
end tell

then you will be able to do what you want from the menu, which will
be a pain. so you will then do menu Window::Palettes-> and check
Scripts, where you will see your new script listed. Select it and
click the Set Key button. You will then be able to assign whatever
key combination you want to the script (including command+leftarrow
if you like).

JD

Roland Küffner

unread,
Jul 30, 2010, 8:34:20 AM7/30/10
to bbe...@googlegroups.com
> The original poster wants to be able to move the cursor to a position
> immediately before the first non-whitespace character of the current
> line. The best the numeric keypad option can do is move it to the very
> start of the line.

Here is another quick applescript solution. As another poster pointed out The two shortcuts Cmd + left and Option + right will bring your cursor to the desired position. You can glue this two shortcuts together with applescript using System Events. After that you can assign a single shortcut to this script in BBEdit.

tell application "BBEdit"
activate
tell application "System Events"
key code 123 using command down
key code 124 using option down
end tell
end tell

System Events allow you to simulate keyboard and GUI events in applescript. To work properly you must turn on the option "Enable access for assistive devices" in the Universal Access System Preference pane of your mac. Tables of key codes should be easily found with a search engine of your choice.

Another tip: If you are fed up fiddling around with Applescript you might consider using a macro software like Keyboard Maestro. It fulfills most of my tweaking desires much faster than spluttering my way to the correct Applescript pronunciation.

happy keyboarding
Roland

offtone

unread,
Jul 30, 2010, 1:45:57 PM7/30/10
to BBEdit Talk
Why isn't this working? For some reason _current_point and
_smart_point never match... Even when I run it with the cursor before
the first non-whitespace character (at the smart point, basically).

And how would I go about getting the startColumn of a character in the
line? Is there a shortcut for that, or would I have to iterate each
character and basically count a "tab" as 4 columns (which may even
change depending on user preferences...)?

What I have so far (Frankensteined from posts above):

tell application "BBEdit"
activate

set _current_line_number to startLine of selection
set _current_point to insertion point

-- Get the column number of the first non-whitespace character
tell the front document
set _line_contents to contents of line _current_line_number
set _chars to characters of _line_contents
repeat with _i from 1 to count _chars
if item _i of _chars is not in {space, tab} then
set _first_non_whitespace_char to _i
exit repeat
end if
end repeat
set _smart_point to (get insertion point before character
_first_non_whitespace_char of line _current_line_number)
end tell

tell application "System Events"
if _current_point is equal to _smart_point then
-- Just go to start of line
key code 123 using command down
else
-- Go to start of line, then skip over whitespace
key code 123 using {shift down, command down}
key code 124 using {shift down, option down}
end if
end tell
end tell

offtone

unread,
Jul 30, 2010, 11:52:07 AM7/30/10
to BBEdit Talk
Thanks, all, for the flood of helpfulness! I didn't know about the CMD
+ LEFT / OPTION + RIGHT trick. Would definitely be simpler to just
emulate those two keypresses and bind them to my HOME key. There is
another level of complexity that I'd like to eventually add, which is
supported by the Windows editors:

Firstly, the key has two functions. Pressed the first time, it goes to
the "smarter" beginning of the line (insertion point before first non-
whitespace character), but pressed a second time, it will jump to the
start of the line as normal. Pressed again, back to the "smart" start
of line, and so on. I don't think that'll be that tricky though, as
I'd just have to put a conditional for the current location of the
insertion point; if it's already at the smart location, go to column
0. Otherwise, go to the smart location.

The next one is not so simple, I don't think? SHIFT + HOME will select
to the beginning of the line (minus the leading whitespace). A second
press of SHIFT + HOME will extend the selection to the beginning of
the line, with whitespace. And again, a third press would deselect the
leading whitespace, and so on. Maybe this is easier than I'm guessing,
depending on how selections are made with AppleScript.

I'll tinker around! Some solutions have already been posted, and
they're helpful starts for sure. I'm surprised this functionality
isn't an option in BBEdit already... Does every just use the two-key
method to get to the first character of the line, or does it just not
come up? Maybe I wouldn't miss it so much if I'd never had it in the
first place. Haha.

Thanks again!

Rich Siegel

unread,
Jul 30, 2010, 8:03:59 PM7/30/10
to bbe...@googlegroups.com
On Friday, July 30, 2010, offtone <aar...@gmail.com> wrote:

>Thanks, all, for the flood of helpfulness! I didn't know about the CMD
>+ LEFT / OPTION + RIGHT trick. Would definitely be simpler to just
>emulate those two keypresses and bind them to my HOME key.

Simpler still: go to the Editing:Keyboard preferences and change
the preference setting under "Home" and "End" keys:

( ) Scroll to beginning and end of document

( o ) Move cursor to beginning and end of current line

This does not address your need for a "smarter" version as
you've described, but it seems like you're well on your way to
scripting that.

Enjoy,

R.
--
Rich Siegel Bare Bones Software, Inc.
<sie...@barebones.com> <http://www.barebones.com/>

Someday I'll look back on all this and laugh... until they
sedate me.

Kendall Conrad

unread,
Jul 31, 2010, 8:32:09 AM7/31/10
to BBEdit Talk
I reworked your code some and got it to work properly as far as my
testing found.

-------------------------------------
tell application "BBEdit"
activate

set _current_line_number to startLine of selection
-- Find the character offset for the cursor position
set aaa to (characterOffset of line (startLine of selection)) of
front window
set zzz to (characterOffset of selection)
set _current_point to zzz - aaa

-- Get the column number of the first non-whitespace character
set _line_contents to contents of line _current_line_number of front
window
set _chars to characters of _line_contents
repeat with _i from 1 to count _chars
if item _i of _chars is not in {space, tab} then
set _first_non_whitespace_char to _i
exit repeat
end if
end repeat
set _smart_point to _first_non_whitespace_char
select (character (_smart_point) of line (startLine of selection) of
front window)
select insertion point before selection of front window
tell application "System Events"
if _current_point is equal to (_smart_point - 1) then
-- Just go to start of line
key code 123 using command down
end if
end tell
end tell
--------------------------------------

-Kendall

John Delacour

unread,
Jul 31, 2010, 9:30:34 AM7/31/10
to bbe...@googlegroups.com
At 08:52 -0700 30/7/10, offtone wrote:

>I'll tinker around! Some solutions have already been posted, and
>they're helpful starts for sure.

The script I posted is more than a "helpful start"; it is a full
solution. Have you tried it?!

JD

Kendall Conrad

unread,
Jul 31, 2010, 3:25:55 PM7/31/10
to BBEdit Talk
Well, offtone was wanting the script to first go to the smart home
position, and if done again, would go to the start of the line, and if
already at the start of the line, would go to the smart home. The same
behavior often found in IDEs like NetBeans when using the home key.
Your script only went to the smart home, so it was not a "full
solution" to his problem. It should be obvious he tried your script as
he used most of it in the script he posted.

-Kendall

Kendall Conrad

unread,
Jul 31, 2010, 6:47:16 PM7/31/10
to BBEdit Talk
With more testing I found there were some cases where the script
didn't work so I have made further improvements. Below is the new
script. I set command+left to be the shortcut for it, which works out
pretty well.

---------------------------------
tell application "BBEdit"
-- Find the character offset for the cursor position
set aaa to (characterOffset of line (startLine of selection)) of
front window
set zzz to (characterOffset of selection)
set _cursor to zzz - aaa
set _smart to 0

-- Get the column number of the first non-whitespace character
set _line to contents of line (startLine of selection) of front
window
-- Ensure line is not empty
if (count _line) = 0 then return

-- Go through content of line looking for smart home position
set _len to count (_line as text)
repeat with _i from 1 to _len
if item _i of _line is not in {space, tab} then
set _smart to _i - 1
exit repeat
end if
end repeat

-- Check if we never found non-whitespace
if item _i of _line is in {space, tab} then set _smart to _len

-- Only true if there was no starting whitespace
if _smart = 0 then
set _smart to 1
set _cursor to 1
end if

-- Check if not at smart position already
if _cursor is not equal to (_smart) then -- Go to smart home
select insertion point after (character (_smart) of line (startLine
of selection) of front window)
else -- Just go to start of line
select insertion point before (character (1) of line (startLine of
selection) of front window)
end if
end tell
---------------------------------

-Kendall

Gabriel Roth

unread,
Jul 31, 2010, 7:23:04 PM7/31/10
to bbe...@googlegroups.com
I never would have thought of this feature if not for this thread, but
I really like it. Thanks to the original poster, and to everyone who
contributed to this script, which I've now got bound to Command-Left.

John Delacour

unread,
Jul 31, 2010, 10:10:42 PM7/31/10
to bbe...@googlegroups.com
At 15:47 -0700 31/7/10, Kendall Conrad wrote:

>With more testing I found there were some cases where the script
>didn't work so I have made further improvements. Below is the new
>script. I set command+left to be the shortcut for it, which works out
>pretty well.

Applescript is verbose enough without any help at all! Here's a
trimmed down version that takes account of the no-break space.

tell application "BBEdit" to tell front window
tell the selection to set {_n, _selectionstart} to {startLine,
characterOffset}
tell line _n to set {_linestart, _line} to {characterOffset, contents}
set _cursor to _selectionstart - _linestart
set _smart to 0
set _linelength to count _line
if _linelength = 0 then return
repeat with _i from 1 to _linelength
if item _i of _line is not in {space, tab, ASCII character 202} then


set _smart to _i - 1
exit repeat

else
set _smart to _linelength
end if
end repeat


if _smart = 0 then
set _smart to 1
set _cursor to 1
end if

if _cursor is not _smart then
select insertion point after character _smart of line _n
else
select insertion point before line _n

offtone

unread,
Aug 4, 2010, 10:10:24 PM8/4/10
to BBEdit Talk
Ah, Delacour's and Conrad's solution seems to be pretty much spot on.
I've been wrestling with it a bit and still can't get the bugger to
behave the same when the SHIFT key is held down -- that is, using the
same "Smart Home" behaviour while trying to SELECT to the start of the
line. It ought to first select to the intelligent beginning of the
line, and then another press ought to extend it to include any
whitespace, and then susequent presses would flip-flop between the two
as this script is doing now (wonderfully).

And Mr. Roth, I'm glad you've found it helpful! Thanks again to
everyone who's contributed; wouldn't be working if it weren't for
them. Clearly I'm incapable. Haha. And hopefully more people discover
this discussion and find it useful, too. I was shocked to have found
it missing from BBEdit, as it seems to do most everything else, and
then some!

Kendall Conrad

unread,
Aug 5, 2010, 9:11:16 PM8/5/10
to BBEdit Talk
I had some time, so I worked on this. It's very close to the other
script and doesn't replace it, so a different keyboard shortcut should
be used, like the one you suggest, which is what I was practicing
with.

-----
tell application "BBEdit" to tell front window
-- Grab line number and offset of text cursor
tell the selection to set {_n, _selectionstart} to {startLine,
characterOffset}
set _selectLength to length of (contents of selection as text)
if (_selectLength) > 0 then
set _selectionstart to _selectionstart + _selectLength
end if
-- Grab offset of line in the document and the contents of the line
tell line _n to set {_linestart, _line} to {characterOffset,
contents}
set _cursor to _selectionstart - _linestart
if _cursor = 0 then return
set _smart to 0
-- Go through content of line looking for smart home position
set _len to count _line
-- Ensure line is not empty
if _len = 0 then return
-- Traverse line to find first non-whitespace
repeat with _i from 1 to _len
if item _i of _line is not in {space, tab, ASCII character 202} then
set _smart to _i - 1
exit repeat
else
set _smart to _len
end if
end repeat
-- Ensure smart is not past cursor
if _smart > _cursor then set _smart to _cursor
-- Check if not at smart position already
if (_selectLength = 0 or _selectLength = _cursor) and _smart is not
_cursor then
select characters (_smart + 1) through _cursor of line _n
else -- Just go to start of line
select characters 1 through _cursor of line _n
end if
end tell
-----

-Kendall

offtone

unread,
Aug 6, 2010, 10:54:56 AM8/6/10
to BBEdit Talk
Thank you, Kendall, for that. It's nearly perfect (throws an error if
more than one line is selected). Both are now bound to CMD+LEFT and CMD
+SHIFT+LEFT respectively, and working pretty much identically to those
other IDEs and text editors! I may need to buy a book on Apple Script,
I think. Haha. The "library" seems totally insufficient for learning
it on its own. Did you learn it through experimentation, or books,
or...? I'm a graphic designer and I have a feeling I could do some
pretty sweet things with Illustrator and Photoshop too, if I could
just get a grip on the language.

I may fire off an e-mail to Bare Bones with a link to this thread. I'm
sure they'd be willing to implement this on their own.

Thanks again!

Kendall Conrad

unread,
Aug 6, 2010, 2:26:48 PM8/6/10
to BBEdit Talk
I've learned AppleScript over the years casually from online resources
mostly and downloading other people's code, such as picking up some
new things from John's code that he provided. I'm good with other
programming languages, but Applescript was a very different kind of
language.

I hadn't tested the code with multiple lines. I guess the desired
effect would just to ignore it possible in order to avoid the errror,
maybe. I'll have to think about it.

-Kendall

Kendall Conrad

unread,
Aug 6, 2010, 7:15:12 PM8/6/10
to BBEdit Talk
I fixed the issue of multiple lines being selected when you use it. I
think some of the math can be simplified, but I wasn't up for it as
everything seemed to work right.

------------
-- Check if smart position is where cursor is, if so select from
start of line
if _smart is _cursor or (_cursor - _selectLength = _smart) then
select (characters (_selectionstart - _cursor) through
(_selectionstart - 1))
else -- Select from smart position
select (characters (_selectionstart - _cursor + _smart) through
(_selectionstart - 1))
end if
end tell
------------

-Kendall


On Aug 6, 10:54 am, offtone <aaro...@gmail.com> wrote:

John Delacour

unread,
Aug 7, 2010, 2:52:17 AM8/7/10
to bbe...@googlegroups.com
At 03:10 +0100 01/08/2010, I wrote:

> repeat with _i from 1 to _linelength
> if item _i of _line is not in {space, tab, ASCII character 202} then

I've just realized that's not very clever. Should be:

set _nbsp to ASCII character 202


repeat with _i from 1 to _linelength

if item _i of _line is not in {space, tab, _nbsp} then

otherwise time is wasted calling the OSAX at each iteration.

JD

Reply all
Reply to author
Forward
0 new messages