|
|
from IPython.core import ipapi
|
|
|
ip = ipapi.get()
|
|
|
|
|
|
import win32api
|
|
|
import win32ui
|
|
|
import win32console
|
|
|
import dde
|
|
|
import os
|
|
|
import scitedirector
|
|
|
|
|
|
# test to write.
|
|
|
|
|
|
def set_hook(synchronize_with_editor):
|
|
|
"""Set the synchronize with editor hook with a callable object.
|
|
|
|
|
|
The callable object will be called with the following arguments when
|
|
|
IPython wants to synchronize with you favorite editor:
|
|
|
|
|
|
- ip: a running IPython instance.
|
|
|
|
|
|
- filename: the path of the file the editor is supposed to display.
|
|
|
|
|
|
- lineno : the line number of the line the editor is supposed to
|
|
|
highlight.
|
|
|
|
|
|
- columnno : the column number of the character the editor is supposed
|
|
|
to highlight.
|
|
|
"""
|
|
|
ip.set_hook("synchronize_with_editor", synchronize_with_editor)
|
|
|
|
|
|
|
|
|
def find_filename(filename):
|
|
|
"""Return the filename to synchronize with based on """
|
|
|
filename = os.path.splitext(filename)
|
|
|
if filename[1] == ".pyc":
|
|
|
filename = (filename[0], ".py")
|
|
|
filename = "".join(filename)
|
|
|
|
|
|
if not os.path.isabs(filename):
|
|
|
filename = os.path.join(os.getcwd(), filename)
|
|
|
|
|
|
if os.path.isfile(filename):
|
|
|
return filename
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
def run_command(path, command, arguments, asynchronous = True):
|
|
|
"""Run a shell command and return the exit code of the command"""
|
|
|
# This is a thin wrapper around os.system that:
|
|
|
# - Let you run command asynchronously.
|
|
|
# - Accept spaces in command path.
|
|
|
# - Dont throw exception if the command don't exist.
|
|
|
line = ''
|
|
|
if asynchronous:
|
|
|
line += 'start '
|
|
|
|
|
|
try:
|
|
|
line += win32api.GetShortPathName(os.path.join(path, command) + ".exe") + " "
|
|
|
except:
|
|
|
print 'could not find: "%s"' % (os.path.join(path, command) + ".exe")
|
|
|
return -1
|
|
|
|
|
|
line += arguments
|
|
|
r = os.system(line)
|
|
|
return r
|
|
|
|
|
|
|
|
|
def sleep(milliseconds):
|
|
|
"""Wait some milliseconds."""
|
|
|
# This is used to make sure the editor did its job before we reset the focus on the console.
|
|
|
win32api.Sleep(milliseconds)
|
|
|
|
|
|
|
|
|
def restore_console_focus():
|
|
|
"""Restore the focus to the IPython console."""
|
|
|
h = win32console.GetConsoleWindow()
|
|
|
console_window = win32ui.CreateWindowFromHandle(h)
|
|
|
console_window.SetForegroundWindow()
|
|
|
|
|
|
|
|
|
# This is the most simple example of hook:
|
|
|
class GVimHook:
|
|
|
def __init__(self, path, wakeup_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
run_command(self.path, 'gvim', '--remote-silent +%d "%s"' % (lineno, filename))
|
|
|
|
|
|
sleep(self.wakeup_duration)
|
|
|
|
|
|
restore_console_focus()
|
|
|
|
|
|
|
|
|
def gvim(path = r"C:\Program Files\vim\vim71", wakeup_duration = 100):
|
|
|
synchronize_with_editor = GVimHook(path, wakeup_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|
|
|
|
|
|
class EmacsHook:
|
|
|
def __init__(self, path, wakeup_duration, start_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
self.start_duration = start_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
r = run_command(self.path, "emacsclient", '-n +%d:%d "%s" 2>nul' % (lineno, columnno, filename), False)
|
|
|
if r != 0:
|
|
|
run_command(self.path, 'runemacs', '--quick -f server-start +%d:%d "%s"' % (lineno, columnno, filename))
|
|
|
sleep(self.start_duration)
|
|
|
else:
|
|
|
sleep(self.wakeup_duration)
|
|
|
|
|
|
restore_console_focus()
|
|
|
|
|
|
|
|
|
def emacs(path = r"C:\Program Files\emacs\bin", wakeup_duration = 100, start_duration = 2000):
|
|
|
synchronize_with_editor = EmacsHook(path, wakeup_duration, start_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|
|
|
|
|
|
class SciteHook:
|
|
|
def __init__(self, path, wakeup_duration, start_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
self.start_duration = start_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
scites = scitedirector.findWindows()
|
|
|
if not scites:
|
|
|
run_command(self.path, "scite", '"-open:%s" -goto:%d' % (filename.replace("\\", "/"), lineno))
|
|
|
|
|
|
sleep(self.start_duration)
|
|
|
restore_console_focus()
|
|
|
else:
|
|
|
scite = scites[0]
|
|
|
scitedirector.sendCommand(scite, 'open:%s' % filename.replace("\\", "/"))
|
|
|
scitedirector.sendCommand(scite, "goto:%d" % lineno)
|
|
|
|
|
|
|
|
|
def scite(path = r"C:\Program Files\SciTE Source Code Editor", wakeup_duration = 100, start_duration = 500):
|
|
|
synchronize_with_editor = SciteHook(path, wakeup_duration, start_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|
|
|
|
|
|
class NodePadPlusPlusHook:
|
|
|
def __init__(self, path, wakeup_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
run_command(self.path, "notepad++", '"%s" -n%d' % (filename, lineno))
|
|
|
|
|
|
sleep(self.wakeup_duration)
|
|
|
|
|
|
restore_console_focus()
|
|
|
|
|
|
|
|
|
def notepadplusplus(path = r"C:\Program Files\Notepad++", wakeup_duration = 100):
|
|
|
synchronize_with_editor = NodePadPlusPlusHook(path, wakeup_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|
|
|
|
|
|
class PsPadHook:
|
|
|
def __init__(self, path, wakeup_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
run_command(self.path, "pspad", '"%s" -%d' % (filename, lineno))
|
|
|
|
|
|
sleep(self.wakeup_duration)
|
|
|
|
|
|
restore_console_focus()
|
|
|
|
|
|
|
|
|
def pspad(path = r"C:\Program Files\PSPad editor", wakeup_duration = 100):
|
|
|
synchronize_with_editor = PsPadHook(path, wakeup_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|
|
|
|
|
|
# This is an example of DDE hook:
|
|
|
class UltraEditHook:
|
|
|
def __init__(self, path, wakeup_duration, start_duration):
|
|
|
self.path = path
|
|
|
self.wakeup_duration = wakeup_duration
|
|
|
self.start_duration = start_duration
|
|
|
|
|
|
def __call__(self, ip, filename, lineno, columnno):
|
|
|
filename = find_filename(filename)
|
|
|
|
|
|
if not filename:
|
|
|
return
|
|
|
|
|
|
server = dde.CreateServer()
|
|
|
server.Create("myddeserver")
|
|
|
conversation = dde.CreateConversation(server)
|
|
|
try:
|
|
|
conversation.ConnectTo("uedit32", "System")
|
|
|
conversation.Exec(r'[open("%s/%d"])' % (filename, lineno))
|
|
|
|
|
|
sleep(self.wakeup_duration)
|
|
|
except:
|
|
|
run_command(self.path, 'uedit32', '"%s/%d"' % (filename, lineno))
|
|
|
|
|
|
sleep(self.start_duration)
|
|
|
|
|
|
server.Shutdown()
|
|
|
|
|
|
restore_console_focus()
|
|
|
|
|
|
|
|
|
def ultraedit(path = r"C:\Program Files\IDM Computer Solutions\UltraEdit-32", wakeup_duration = 10, start_duration = 2000):
|
|
|
synchronize_with_editor = UltraEditHook(path, wakeup_duration, start_duration)
|
|
|
set_hook(synchronize_with_editor)
|
|
|
|