##// END OF EJS Templates
Merge Vivan De Smedt's branch on editor synchronization.
Fernando Perez -
r1532:52970849 merge
parent child Browse files
Show More
@@ -0,0 +1,242 b''
1 import IPython.ipapi
2 ip = IPython.ipapi.get()
3
4 import win32api
5 import win32ui
6 import win32console
7 import dde
8 import os
9 import scitedirector
10
11 # test to write.
12
13 def set_hook(synchronize_with_editor):
14 """Set the synchronize with editor hook with a callable object.
15
16 The callable object will be called with the following arguments when
17 IPython wants to synchronize with you favorite editor:
18
19 - ip: a running IPython instance.
20
21 - filename: the path of the file the editor is supposed to display.
22
23 - lineno : the line number of the line the editor is supposed to
24 highlight.
25
26 - columnno : the column number of the character the editor is supposed
27 to highlight.
28 """
29 ip.set_hook("synchronize_with_editor", synchronize_with_editor)
30
31
32 def find_filename(filename):
33 """Return the filename to synchronize with based on """
34 filename = os.path.splitext(filename)
35 if filename[1] == ".pyc":
36 filename = (filename[0], ".py")
37 filename = "".join(filename)
38
39 if not os.path.isabs(filename):
40 filename = os.path.join(os.getcwd(), filename)
41
42 if os.path.isfile(filename):
43 return filename
44
45 return ""
46
47
48 def run_command(path, command, arguments, asynchronous = True):
49 """Run a shell command and return the exit code of the command"""
50 # This is a thin wrapper around os.system that:
51 # - Let you run command asynchronously.
52 # - Accept spaces in command path.
53 # - Dont throw exception if the command don't exist.
54 line = ''
55 if asynchronous:
56 line += 'start '
57
58 try:
59 line += win32api.GetShortPathName(os.path.join(path, command) + ".exe") + " "
60 except:
61 print 'could not find: "%s"' % (os.path.join(path, command) + ".exe")
62 return -1
63
64 line += arguments
65 r = os.system(line)
66 return r
67
68
69 def sleep(milliseconds):
70 """Wait some milliseconds."""
71 # This is used to make sure the editor did its job before we reset the focus on the console.
72 win32api.Sleep(milliseconds)
73
74
75 def restore_console_focus():
76 """Restore the focus to the IPython console."""
77 h = win32console.GetConsoleWindow()
78 console_window = win32ui.CreateWindowFromHandle(h)
79 console_window.SetForegroundWindow()
80
81
82 # This is the most simple example of hook:
83 class GVimHook:
84 def __init__(self, path, wakeup_duration):
85 self.path = path
86 self.wakeup_duration = wakeup_duration
87
88 def __call__(self, ip, filename, lineno, columnno):
89 filename = find_filename(filename)
90
91 if not filename:
92 return
93
94 run_command(self.path, 'gvim', '--remote-silent +%d "%s"' % (lineno, filename))
95
96 sleep(self.wakeup_duration)
97
98 restore_console_focus()
99
100
101 def gvim(path = r"C:\Program Files\vim\vim71", wakeup_duration = 100):
102 synchronize_with_editor = GVimHook(path, wakeup_duration)
103 set_hook(synchronize_with_editor)
104
105
106 class EmacsHook:
107 def __init__(self, path, wakeup_duration, start_duration):
108 self.path = path
109 self.wakeup_duration = wakeup_duration
110 self.start_duration = start_duration
111
112 def __call__(self, ip, filename, lineno, columnno):
113 filename = find_filename(filename)
114
115 if not filename:
116 return
117
118 r = run_command(self.path, "emacsclient", '-n +%d:%d "%s" 2>nul' % (lineno, columnno, filename), False)
119 if r != 0:
120 run_command(self.path, 'runemacs', '--quick -f server-start +%d:%d "%s"' % (lineno, columnno, filename))
121 sleep(self.start_duration)
122 else:
123 sleep(self.wakeup_duration)
124
125 restore_console_focus()
126
127
128 def emacs(path = r"C:\Program Files\emacs\bin", wakeup_duration = 100, start_duration = 2000):
129 synchronize_with_editor = EmacsHook(path, wakeup_duration, start_duration)
130 set_hook(synchronize_with_editor)
131
132
133 class SciteHook:
134 def __init__(self, path, wakeup_duration, start_duration):
135 self.path = path
136 self.wakeup_duration = wakeup_duration
137 self.start_duration = start_duration
138
139 def __call__(self, ip, filename, lineno, columnno):
140 filename = find_filename(filename)
141
142 if not filename:
143 return
144
145 scites = scitedirector.findWindows()
146 if not scites:
147 run_command(self.path, "scite", '"-open:%s" -goto:%d' % (filename.replace("\\", "/"), lineno))
148
149 sleep(self.start_duration)
150 restore_console_focus()
151 else:
152 scite = scites[0]
153 scitedirector.sendCommand(scite, 'open:%s' % filename.replace("\\", "/"))
154 scitedirector.sendCommand(scite, "goto:%d" % lineno)
155
156
157 def scite(path = r"C:\Program Files\SciTE Source Code Editor", wakeup_duration = 100, start_duration = 500):
158 synchronize_with_editor = SciteHook(path, wakeup_duration, start_duration)
159 set_hook(synchronize_with_editor)
160
161
162 class NodePadPlusPlusHook:
163 def __init__(self, path, wakeup_duration):
164 self.path = path
165 self.wakeup_duration = wakeup_duration
166
167 def __call__(self, ip, filename, lineno, columnno):
168 filename = find_filename(filename)
169
170 if not filename:
171 return
172
173 run_command(self.path, "notepad++", '"%s" -n%d' % (filename, lineno))
174
175 sleep(self.wakeup_duration)
176
177 restore_console_focus()
178
179
180 def notepadplusplus(path = r"C:\Program Files\Notepad++", wakeup_duration = 100):
181 synchronize_with_editor = NodePadPlusPlusHook(path, wakeup_duration)
182 set_hook(synchronize_with_editor)
183
184
185 class PsPadHook:
186 def __init__(self, path, wakeup_duration):
187 self.path = path
188 self.wakeup_duration = wakeup_duration
189
190 def __call__(self, ip, filename, lineno, columnno):
191 filename = find_filename(filename)
192
193 if not filename:
194 return
195
196 run_command(self.path, "pspad", '"%s" -%d' % (filename, lineno))
197
198 sleep(self.wakeup_duration)
199
200 restore_console_focus()
201
202
203 def pspad(path = r"C:\Program Files\PSPad editor", wakeup_duration = 100):
204 synchronize_with_editor = PsPadHook(path, wakeup_duration)
205 set_hook(synchronize_with_editor)
206
207
208 # This is an example of DDE hook:
209 class UltraEditHook:
210 def __init__(self, path, wakeup_duration, start_duration):
211 self.path = path
212 self.wakeup_duration = wakeup_duration
213 self.start_duration = start_duration
214
215 def __call__(self, ip, filename, lineno, columnno):
216 filename = find_filename(filename)
217
218 if not filename:
219 return
220
221 server = dde.CreateServer()
222 server.Create("myddeserver")
223 conversation = dde.CreateConversation(server)
224 try:
225 conversation.ConnectTo("uedit32", "System")
226 conversation.Exec(r'[open("%s/%d"])' % (filename, lineno))
227
228 sleep(self.wakeup_duration)
229 except:
230 run_command(self.path, 'uedit32', '"%s/%d"' % (filename, lineno))
231
232 sleep(self.start_duration)
233
234 server.Shutdown()
235
236 restore_console_focus()
237
238
239 def ultraedit(path = r"C:\Program Files\IDM Computer Solutions\UltraEdit-32", wakeup_duration = 10, start_duration = 2000):
240 synchronize_with_editor = UltraEditHook(path, wakeup_duration, start_duration)
241 set_hook(synchronize_with_editor)
242 No newline at end of file
@@ -0,0 +1,26 b''
1 import win32api
2 import win32gui
3 import win32con
4
5 import struct
6 import array
7
8 def findWindows():
9 ret = []
10 sdi = win32api.RegisterWindowMessage("SciTEDirectorInterface")
11 w = win32gui.GetWindow(win32gui.GetDesktopWindow(), win32con.GW_CHILD)
12 while w:
13 res = win32gui.SendMessage(w, sdi, 0, 0)
14 if res == sdi:
15 ret.append(w)
16 w = win32gui.GetWindow(w, win32con.GW_HWNDNEXT)
17
18 return ret
19
20 def sendCommand(w, message):
21 CopyDataStruct = "IIP"
22 char_buffer = array.array('c', message)
23 char_buffer_address = char_buffer.buffer_info()[0]
24 char_buffer_size = char_buffer.buffer_info()[1]
25 cds = struct.pack(CopyDataStruct, 0, char_buffer_size, char_buffer_address)
26 win32gui.SendMessage(w, win32con.WM_COPYDATA, 0, cds)
@@ -333,6 +333,12 b' class Pdb(OldPdb):'
333 #frame, lineno = frame_lineno
333 #frame, lineno = frame_lineno
334 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
334 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
335
335
336 # vds: >>
337 frame, lineno = frame_lineno
338 filename = frame.f_code.co_filename
339 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
340 # vds: <<
341
336 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
342 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
337 import linecache, repr
343 import linecache, repr
338
344
@@ -496,6 +502,12 b' class Pdb(OldPdb):'
496 last = first + 10
502 last = first + 10
497 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
503 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
498
504
505 # vds: >>
506 lineno = first
507 filename = self.curframe.f_code.co_filename
508 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
509 # vds: <<
510
499 do_l = do_list
511 do_l = do_list
500
512
501 def do_pdef(self, arg):
513 def do_pdef(self, arg):
@@ -53,10 +53,12 b' from pprint import PrettyPrinter'
53
53
54 # List here all the default hooks. For now it's just the editor functions
54 # List here all the default hooks. For now it's just the editor functions
55 # but over time we'll move here all the public API for user-accessible things.
55 # but over time we'll move here all the public API for user-accessible things.
56 __all__ = ['editor', 'fix_error_editor', 'result_display',
56 # vds: >>
57 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
57 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
58 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
58 'generate_prompt', 'generate_output_prompt','shell_hook',
59 'generate_prompt', 'generate_output_prompt','shell_hook',
59 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook']
60 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook']
61 # vds: <<
60
62
61 pformat = PrettyPrinter().pformat
63 pformat = PrettyPrinter().pformat
62
64
@@ -107,6 +109,10 b' def fix_error_editor(self,filename,linenum,column,msg):'
107 finally:
109 finally:
108 t.close()
110 t.close()
109
111
112 # vds: >>
113 def synchronize_with_editor(self, filename, linenum, column):
114 pass
115 # vds: <<
110
116
111 class CommandChainDispatcher:
117 class CommandChainDispatcher:
112 """ Dispatch calls to a chain of commands until some func can handle it
118 """ Dispatch calls to a chain of commands until some func can handle it
@@ -490,6 +490,11 b' class ListTB(TBTools):'
490 Colors.Normal, s))
490 Colors.Normal, s))
491 else:
491 else:
492 list.append('%s\n' % str(stype))
492 list.append('%s\n' % str(stype))
493
494 # vds:>>
495 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
496 # vds:<<
497
493 return list
498 return list
494
499
495 def _some_str(self, value):
500 def _some_str(self, value):
@@ -801,6 +806,15 b' class VerboseTB(TBTools):'
801 for name in names:
806 for name in names:
802 value = text_repr(getattr(evalue, name))
807 value = text_repr(getattr(evalue, name))
803 exception.append('\n%s%s = %s' % (indent, name, value))
808 exception.append('\n%s%s = %s' % (indent, name, value))
809
810 # vds: >>
811 if records:
812 frame, file, lnum, func, lines, index = records[-1]
813 #print "file:", str(file), "linenb", str(lnum)
814 file = abspath(file)
815 __IPYTHON__.hooks.synchronize_with_editor(file, lnum, 0)
816 # vds: <<
817
804 # return all our info assembled as a single string
818 # return all our info assembled as a single string
805 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
819 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
806
820
General Comments 0
You need to be logged in to leave comments. Login now