Sublime Forum

Beta Plugin to send/run selected code in R, Stata or iTerm

#1

Hi, I just wrote a small Mac OS plugin that takes the selected code and sends it to R, Stata or iTerm. Any suggestions are welcome. SendSelectionCommand calls R or stata depending on the extension of the file and SendSelectionIterm always sends stuff to iterm (I am using this for cloud computing).
I will work with this for a while and put it on the plugin list when there are no bugs…

R, and iTerm work flawlessly. Stata is a little annoying because you first have to save the code in a file and then open the .do file with Stata. Doing this, however, changes the stata working directory. Currently, I call a second file which just runs “cd ‘$job’” to change to the working dir to the global $job. So if you define such a global, stata always changes back. Suggestions for alternative implementations are welcome! You might also have to change ‘StataMP’ to ‘StataSE’ depending on the version of stata you have.

Key bindings

{ "keys": "super+e"], "command": "send_selection" }, { "keys": "super+shift+e"], "command": "send_selection_iterm" }
Send-Selection.py (copy to /Packages/User)

[code]import sublime, sublime_plugin
import os, subprocess, string

#https://sites.google.com/site/josefmontag/programs

to test strings:

#self.view.insert(edit, 0, cmd)

class SendSelectionCommand(sublime_plugin.TextCommand):
def run(self, edit):
# get selection
selection = “”
for region in self.view.sel():
selection+=self.view.substr(region) + “\n”

	# only proceed if selection is not empty
	if(selection!="\n"):
		extension = os.path.splitext(self.view.file_name())[1]

		# R file
		if(extension.lower()==".r"):
			# define osascript command
			cmd = """osascript -e 'tell app "R" to activate' """
			cmd+= """-e 'tell app "R" to cmd \"""" + string.replace(selection,"\"","\\\"") + """\"' """ 
			# run and reactivate Sublime Text 2
			os.system(cmd)
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

		# Stata file
		if(extension.lower()==".do"):
			# define location of do file
			file=sublime.packages_path() + "/User/sublime2stata.do"
			file_restore=sublime.packages_path() + "/User/sublime2stata_restore.do"
			# copy selection into file
			os.system("echo '" + selection + "' > '" + file + "'")
			os.system("""echo 'qui cd \"$job\"' > '""" + file_restore + "'")
			# define osascript command and run
			cmd_run = """osascript -e 'tell app "StataMP" to activate' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file + """\"' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file_restore + """\"' """
			os.system(cmd_run)

os.system(“rm '” + file + “’”)

os.system(“rm '” + file_restore + “’”)

			# restore stata working directory from global $job
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

class SendSelectionItermCommand(sublime_plugin.TextCommand):
def run(self, edit):
selection = “”
for region in self.view.sel():
selection+=self.view.substr(region) + “\n”

	if(selection!="\n"):
		# define location of shell script with selection as argument
		script="sh '" + sublime.packages_path() + "/User/send-selection-iterm.sh' \"" + string.replace(selection,"\"","\\\"") + "\""
		# run shell script and reactivate Sublime Text 2
		os.system(script)
		subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)[/code]

shell script for iTerm: send-selection-iterm.sh (copy to /Packages/User)

[code]#!/bin/sh

PASTE=$(echo “$@” | sed 's/////g’ | sed ‘s/"/\"/g’ | sed ‘s/ //g’ | sed -n '1h
1!{
# if the sought-after regex is not found, append the pattern space to hold space
//*.
*// !H
# copy hold space into pattern space
g
# if the regex is found, then…
//*.*// {
# the regular expression
s//*.
*// /g
# print
p
# read the next line into the pattern space
n
# copy the pattern space into the hold space
h
}
# copy pattern buffer into hold buffer
h
}

if the last line then print

$p
')

osascript << END
tell application “iTerm”
activate
tell current terminal
tell current session
write text “$PASTE”
end tell
end tell
end tell
#tell application “Sublime Text 2”

activate

#end tell
#END[/code]

0 Likes

How do I send/run/execute selected code?
Linux: preview, terminal, appcenter questions
#2

There doesn’t really seem to be a lot of interest but this HAS TO work flawlessly to get people from the statistics community interested in ST
So here is an update…
I am sure there are better ways to do this (presumably directly from Python) but I build on my existing shell scripts from Textmate. Currently, these scripts fail when there are backslashes in the code you want to send… :frowning:

[code]import sublime, sublime_plugin
import os, subprocess, string, pipes

class SendSelectionCommand(sublime_plugin.TextCommand):
@staticmethod
def cleanString(str):
#str=string.replace(str,’\’,’\\’)
str=string.replace(str,’"’,’\"’)
return str

def run(self, edit):
	# get selection	
	selection = ""
	for region in self.view.sel():
		selection+=self.view.substr(region) + "\n"
	selection = (selection::-1].replace('\n'::-1], '', 1))::-1]

	# only proceed if selection is not empty
	if(selection!=""):
		extension = os.path.splitext(self.view.file_name())[1]

		# R file
		if(extension.lower()==".r"):
			cmd = 'osascript<<-END\n'
			cmd+= '  tell app "R"\n'
			cmd+= '  activate\n'
			selection=self.cleanString(selection).split("\n")
			for part in selection:
				cmd+= '  cmd "' + part + '"\n'					
			cmd+= '  end tell\nEND'			
			self.view.insert(edit, 0, cmd)		
			os.system(cmd)
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

		# Stata file
		if(extension.lower()==".do"):
			# define location of do file
			file=sublime.packages_path() + "/User/sublime2stata.do"
			file_restore=sublime.packages_path() + "/User/sublime2stata_restore.do"
			# copy selection into file
			os.system("echo '" + selection + "' > '" + file + "'")
			os.system("""echo 'qui cd \"$job\"' > '""" + file_restore + "'")
			# define osascript command and run
			cmd_run = """osascript -e 'tell app "StataMP" to activate' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file + """\"' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file_restore + """\"' """
			os.system(cmd_run)

			# restore stata working directory from global $job
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

class SendSelectionIterm(sublime_plugin.TextCommand):
@staticmethod
def cleanString(str):
str=string.replace(str,’\’,’\\’)
str=string.replace(str,""","\"")
str = (str::-1].replace(’\n’::-1], ‘’, 1))::-1]
return str

def run(self, edit):
	selection = ""
	for region in self.view.sel():
		selection+=self.view.substr(region) + "\n"
	selection=self.cleanString(selection)
	
	if(selection!="\n"):
		# define location of shell script with selection as argument
		script='sh "' + sublime.packages_path() + '/User/send-selection-iterm.sh" "' + selection + '"'
		# run shell script and reactivate Sublime Text 2
		os.system(script)
		subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

[/code]

0 Likes

#3

Hi gregor!

I’m very interested in your nice work.
Please, keep it up!

:smile:


bblue

0 Likes

#4

Here is an update to the SendSelection function that should work for R with almost all code (special characters, quotes etc). The previous version had some serious problems with certain special characters…

[code]class SendSelectionCommand(sublime_plugin.TextCommand):
@staticmethod
def cleanString(str):
str=string.replace(str,’"’,’\"’)
return str

def run(self, edit):
	# get selection	
	selection = ""
	for region in self.view.sel():
		selection+=self.view.substr(region) + "\n"
	selection = (selection::-1].replace('\n'::-1], '', 1))::-1]

	# only proceed if selection is not empty
	if(selection!=""):
		extension = os.path.splitext(self.view.file_name())[1]

		# R file
		if(extension.lower()==".r"):
			# define list of arguments
			args='osascript','-e','tell app "R" to activate']
			# split selection into lines
			selection=self.cleanString(selection).split("\n")
			# add code lines to list of arguments
			for part in selection:
				args.extend('-e', 'tell app "R" to cmd "' + part + '"\n']) 
			# execute code and activate ST2
			p = subprocess.Popen(args)
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

			# args='osascript','-e','tell app "R" to activate','-e',"""tell app "R" to cmd "cty.data$\\"terror1980d\\"" """]
			# p = subprocess.Popen(args)
			#subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

		# Stata file
		if(extension.lower()==".do"):
			# define location of do file
			file=sublime.packages_path() + "/User/sublime2stata.do"
			file_restore=sublime.packages_path() + "/User/sublime2stata_restore.do"
			# copy selection into file
			os.system("echo '" + selection + "' > '" + file + "'")
			os.system("""echo 'qui cd \"$job\"' > '""" + file_restore + "'")
			# define osascript command and run
			cmd_run = """osascript -e 'tell app "StataMP" to activate' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file + """\"' """
			cmd_run+= """-e 'tell app "StataMP" to open POSIX file \"""" + file_restore + """\"' """
			os.system(cmd_run)

os.system(“rm '” + file + “’”)

os.system(“rm '” + file_restore + “’”)

			# restore stata working directory from global $job
			subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)

[/code]

0 Likes

#5

Also add the line

str=string.replace(str,'\\','\\\\')

to the cleanString function.

Here is the same function for iTerm

[code]class SendSelectionIterm(sublime_plugin.TextCommand):
@staticmethod
def cleanString(str):
str=string.replace(str,’\’,’\\’)
str=string.replace(str,’"’,’\"’)
return str

def run(self, edit):
	selection = ""
	for region in self.view.sel():
		selection+=self.view.substr(region) + "\n"
	selection = (selection::-1].replace('\n'::-1], '', 1))::-1]		

	# only proceed if selection is not empty
	if(selection!=""):
		extension = os.path.splitext(self.view.file_name())[1]

		# define list of arguments
		args='osascript','-e','tell app "iTerm" to activate']
		# split selection into lines
		selection=self.cleanString(selection).split("\n")
		# add code lines to list of arguments
		for part in selection:
			args.extend('-e', 'tell app "iTerm" to tell current terminal to tell current session to write text "' + part + '"\n']) 
		# execute code and activate ST2
		p = subprocess.Popen(args)
		subprocess.Popen("""osascript -e 'tell app "Sublime Text 2" to activate' """, shell=True)[/code]
0 Likes

#6

I just started using sublime text a few hours ago. I am a statistician and use R. Where exactly do I copy these functions?
Into a separate file in my packages/R folder?
or do I paste the function into one of my user settings files?

thanks

0 Likes

Help with sending code from ST2 to R
#7

This is a plugin, so you can go: Tools > New Plugin. Copy and paste the code. Save the file in your User folder (Packages > User should be the default folder open when you press save as).

0 Likes

#8

I managed to make it work. The downside is that it wont send any selection to R unless i save the file as something.r
This sucks because I often test chunks of code that I don’t write to disk (so I’ll use an unsaved file) but there seems no way around it.

0 Likes

#9

I see someone already updated the plugin to account for odd string behavior – thanks.

0 Likes

#10

Anyone have ideas on how to make this work on multi line selections? For some reason it only works if I select one line at a time.
thanks

0 Likes

#11

I also use R and Stata and would love to use them together with Sublime Text 2. Anyway we can get a Windows version? Thanks for the contribution.

0 Likes

#12

You could try SublimeREPL. It works with R on all three platforms and allows you to send multiple lines (F2, L) or selections (F2, s) to the running interpreter.
I don’t use or know R at all, so if something is missing or feels wrong let me know and we’ll try to fix it.

0 Likes

#13

Hi All
I have hacked the textmate bundle (github.com/steve3001/stata) for stata.
Hope this helps. I’ll post updates at drstevok.tumblr.com/
Steve

0 Likes