Move line up / down


(Phil Stokes) #1

Correct me if I’m wrong, but SD doesn’t have a ‘move line up’ / ‘move line down’ command like Xcode, BBEdit (and even MS Word).

I use this feature a lot in other editors, and really miss not having it available in SD.


(Phil Stokes) #2

Anyone know if this made it into SD7?

I’m thinking I should be able to add something to the scripts menu if not, but don’t want to reinvent the wheel if so.


(Shane Stanley) #3

No, it’s not built-in. here are a couple of alternatives:

tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set theText to source text
		set {loc, len} to character range of selection
	end tell
end tell
set parNo to count of paragraphs of text 1 thru loc of theText
set startIndex to (count of characters of text 1 thru paragraph (parNo - 1) of theText) + 1
set endIndex to (count of characters of text 1 thru paragraph parNo of theText) + 1
set parText to text startIndex thru endIndex of theText
set newIndex to count of characters of text 1 thru paragraph (parNo - 2) of theText
tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set character range of selection to {startIndex, endIndex - startIndex}
		set contents of selection to ""
		set character range of selection to {newIndex + 2, 0}
		set contents of selection to parText
	end tell
end tell

Or:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set theText to source text
		set {loc, len} to character range of selection
	end tell
end tell
set theText to current application's NSString's stringWithString:theText
set parRange to theText's paragraphRangeForRange:{loc - 1, len}
set parText to theText's substringWithRange:parRange
set prevParRange to theText's paragraphRangeForRange:{(location of parRange) - 1, 0}
tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set selection to {(location of parRange) + 1, |length| of parRange}
		set contents of selection to ""
		set selection to {(location of prevParRange) + 1, 0}
		set contents of selection to (parText as text)
	end tell
end tell

(Jim Underwood) #4

Thanks, Shane.

The 2nd script works fine for me – it moves UP.

Change Request:

  • Move down by default
  • Move UP if OPT key is down
  • I would do this myself if I could figure out your script. :blush:

The 1st script doesn’t work for me:

  • Leaves a blank line
  • Moves the wrong line after the first move

(Shane Stanley) #5

They were really top-of-the-head rainy-Sunday-morning jobs. I’m not sure of the problem with the first — I only wrote it to compare speeds — but your comment about “Moves the wrong line” suggests you’re expecting it to do something it doesn’t, which is select the moved line.

Anyway, this should go close:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

-- check for option key
set theFlag to current application's NSEvent's modifierFlags()
set optionDown to ((theFlag div (get current application's NSAlternateKeyMask)) mod 2) = 1

tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set theText to source text
		set {loc, len} to character range of selection
	end tell
end tell

-- get range of paragraph(s) containing selection
set theText to current application's NSString's stringWithString:theText
set parRange to theText's paragraphRangeForRange:{loc - 1, len}
set parText to theText's substringWithRange:parRange
if optionDown then
	-- otherParRange = range of previous paragraph
	set otherParRange to theText's paragraphRangeForRange:{(location of parRange) - 1, 0}
	set insertLoc to (location of otherParRange) + 1 -- + 1 for 1-based indexes
	set newSelLoc to loc - (|length| of otherParRange)
else
	-- otherParRange = range of following paragraph
	set otherParRange to theText's paragraphRangeForRange:{(current application's NSMaxRange(parRange)) + 1, 0}
	set insertLoc to (current application's NSMaxRange(otherParRange)) - (|length|() of parText) + 1
	set newSelLoc to loc + (|length| of otherParRange)
end if
set parText to parText as text -- convert outside tell block
tell application id "com.latenightsw.ScriptDebugger7" -- Script Debugger.app
	tell document 1
		set selection to {(location of parRange) + 1, |length| of parRange} -- select full paragraphs
		set contents of selection to "" -- delete
		set character range of selection to {insertLoc, 0} -- select where to insert
		set contents of selection to parText -- insert text
		set selection to {newSelLoc, len} -- reset selection
	end tell
end tell

(Jim Underwood) #6

No problem.

Thanks for the new script.

This script works when triggered from the SD scripts menu.
But fails when triggered from FastScripts or Keyboard Maestro.

Running:
• macOS 10.12.6
• Keyboard Maestro 8.2 (8.2)
• Script Debugger 7 7.0 (7A40)
• FastScripts Version 2.6.11 (580)

I get this error from FastScripts:

Error Number: -1700
Can’t make «class ocid» id «data optr00000000E078020080600000» into type text.

Also, it deletes the line, but does not put back, either up or down.

SD7-Move-Line-Script-Demo-AN

Any ideas on how to fix?


(Shane Stanley) #7

I’ve edited it to fix the problem.


(Phil Stokes) #8

Thx for this Shane. I’m sure you had better things to do today, and I was going to do it myself (though it wouldn’t have been so good, obv!).

I chopped it up into two separate scripts, one for up and one for down, put them in SDs (6, 7) script folders and assigned them the same shortcuts as I use in BBEdit in SDs key bindings. Lovely!

Works great on SD7. I haven’t looked at it yet, but I will later, for some reason gives an out of bounds error on SD6.

00


(Shane Stanley) #9

You did change the application ID in both places for SD6?


(Phil Stokes) #10

Heheh. I. did. not. :roll_eyes:


(Phil Stokes) #11

I guess this is a display bug. I assign control-arrow, which shows correctly in the key bindings pane, but in the menu it shows fn-arrow. Control-arrow does execute the script as expected. This shot is in SD7, but it also occurs in SD6:

53


(Shane Stanley) #12

This is fixed in 7.0.1, but you will need to reassign the shortcut. (Yes, when you press control-down, the modifier key mask does include the function key — weird.)


(Jim Underwood) #13

Phil, I think you should check the “Solved” checkbox in Shane’s last script:


(Phil Stokes) #14

No, this is a feature request for SD which we still don’t have. Although I appreciate as always Shane’s willingness to write scripts for us, that wasn’t the purpose or aim of the thread.


(Jim Underwood) #15

Well, since it is your topic, I suppose the decision is up to you (unless, of course, the mods or owner chooses to override :smile: ).

From a practical POV, I don’t see the difference, whether the SD team chooses to implement in the app, or via a script. The result is the same. I’m always happy to just get a solution.

In fact one of the huge advantages of an app being scriptable is that it can often be easily extended without requiring the expensive process of making a formal app change.


(Phil Stokes) #16

There’s a huge difference.

i. speed & reliability – the script is good, but it’s still a script not native code, with all that that implies

ii. discoverability – hopefully, SD7 is bringing in chunks of new users. New users won’t necessarily think or expect that it’s something they have to implement themselves, nor necessarily know (how) to look for such a script here.

iii. professionalism – Anyone used to other professional-grade text editors / IDEs would expect to find a move line up / down command in the Edit menu. It’s a common feature. The only other one I know of that lacks it is Scrivener (which also sadly lacks scripting support). The lack of it isn’t a deal breaker, but it doesn’t look great either.


(Jim Underwood) #17

I suppose huge is in the eye of the beholder. LOL

Perhaps I’m not professional enough, but this is not a feature that I’ve ever missed, or even knowing about it now, will use very often. When I want to move something, it is almost always multiple lines, and it usually means moving it many lines away (like into a handler). A simple cut/paste does the job the few times that happens.

I can think of many, many other features that I could really use before I’d want Late Night SW to waste spend time on this, especially now that Shane has given us a very acceptable solution.

SD could easily enough include it in the Scripts menu, very discoverable.

I sincerely doubt that lack of this minor feature will result in loss of even one sale of SD.

From previous experience, we clearly have different thought processes, so I’ll not pursue this any further.


(Phil Stokes) #18

I wasn’t trying to convince you, Jim; only the developers.

When I want to move something, it is almost always multiple lines

Shane’s script - and the usual feature in most text editors - will move an entire block/selection, up or down, not only a single line.

Perhaps I’m not professional enough

The developers have to cater to users with multiple needs, not just yours or mine; they market SD as a “professional” tool and as such, it’s worth their considering adding the kind of tools that other professional IDEs have. That’s why this is a feature request and not a ‘problem’ in need of a (marked) ‘solution’.

Thanks.