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 | 333 | #frame, lineno = frame_lineno |
|
334 | 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 | 342 | def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3): |
|
337 | 343 | import linecache, repr |
|
338 | 344 | |
@@ -496,6 +502,12 b' class Pdb(OldPdb):' | |||
|
496 | 502 | last = first + 10 |
|
497 | 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 | 511 | do_l = do_list |
|
500 | 512 | |
|
501 | 513 | def do_pdef(self, arg): |
@@ -53,10 +53,12 b' from pprint import PrettyPrinter' | |||
|
53 | 53 | |
|
54 | 54 | # List here all the default hooks. For now it's just the editor functions |
|
55 | 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 | 58 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', |
|
58 | 59 | 'generate_prompt', 'generate_output_prompt','shell_hook', |
|
59 | 60 | 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook'] |
|
61 | # vds: << | |
|
60 | 62 | |
|
61 | 63 | pformat = PrettyPrinter().pformat |
|
62 | 64 | |
@@ -107,6 +109,10 b' def fix_error_editor(self,filename,linenum,column,msg):' | |||
|
107 | 109 | finally: |
|
108 | 110 | t.close() |
|
109 | 111 | |
|
112 | # vds: >> | |
|
113 | def synchronize_with_editor(self, filename, linenum, column): | |
|
114 | pass | |
|
115 | # vds: << | |
|
110 | 116 | |
|
111 | 117 | class CommandChainDispatcher: |
|
112 | 118 | """ Dispatch calls to a chain of commands until some func can handle it |
@@ -490,6 +490,11 b' class ListTB(TBTools):' | |||
|
490 | 490 | Colors.Normal, s)) |
|
491 | 491 | else: |
|
492 | 492 | list.append('%s\n' % str(stype)) |
|
493 | ||
|
494 | # vds:>> | |
|
495 | __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0) | |
|
496 | # vds:<< | |
|
497 | ||
|
493 | 498 | return list |
|
494 | 499 | |
|
495 | 500 | def _some_str(self, value): |
@@ -801,6 +806,15 b' class VerboseTB(TBTools):' | |||
|
801 | 806 | for name in names: |
|
802 | 807 | value = text_repr(getattr(evalue, name)) |
|
803 | 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 | 818 | # return all our info assembled as a single string |
|
805 | 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