3838 }
3939
4040"""
41- import os , sys
41+ import os , sys , stat
4242import sublime_plugin , sublime
4343import logging
4444try :
5454from codeintel2 .environment import SimplePrefsEnvironment
5555from codeintel2 .util import guess_lang_from_path
5656
57+ stderr_hdlr = logging .StreamHandler (sys .stderr )
5758codeintel_logger = logging .getLogger ("codeintel" )
58- codeintel_logger .addHandler (logging .StreamHandler (sys .stderr ))
5959
6060cpln_fillup_chars = {
6161 'Ruby' : "~`@#$%^&*(+}[]|\\ ;:,<>/ " ,
@@ -108,22 +108,22 @@ def logger(view, type, msg=None, delay=0, timeout=None, id='CodeIntel'):
108108
109109class PythonCodeIntel (sublime_plugin .EventListener ):
110110 def on_close (self , view ):
111- path = view .file_name () or "<Unsaved>"
111+ path = view .file_name ()
112112 codeintel_cleanup (path )
113113
114114 def on_modified (self , view ):
115115 pos = view .sel ()[0 ].end ()
116116 text = view .substr (sublime .Region (pos - 7 , pos ))
117117
118- path = view .file_name () or "<Unsaved>"
118+ path = view .file_name ()
119+
119120 lang , _ = os .path .splitext (os .path .basename (view .settings ().get ('syntax' )))
120121 try :
121122 lang = lang or guess_lang_from_path (path )
122123 except CodeIntelError :
123124 pass
124125
125126 if text and text [- 1 ] in cpln_fillup_chars .get (lang , '' ):
126- path = view .file_name () or "<Unsaved>"
127127 content = view .substr (sublime .Region (0 , view .size ()))
128128 lang , _ = os .path .splitext (os .path .basename (view .settings ().get ('syntax' )))
129129 pos = view .sel ()[0 ].end ()
@@ -138,6 +138,12 @@ def on_modified(self, view):
138138 elif calltips is not None :
139139 # Triger a tooltip
140140 calltip (view , 'Tip: ' + calltips [0 ])
141+ else :
142+ def scan_callback (path ):
143+ content = view .substr (sublime .Region (0 , view .size ()))
144+ lang , _ = os .path .splitext (os .path .basename (view .settings ().get ('syntax' )))
145+ codeintel_scan (view , path , content , lang )
146+ _ci_scan_callbacks_ [path ] = scan_callback
141147
142148 def on_selection_modified (self , view ):
143149 lineno = view .rowcol (view .sel ()[0 ].end ())[0 ]
@@ -153,11 +159,12 @@ def on_query_completions(self, view, prefix, locations):
153159
154160class GotoPythonDefinition (sublime_plugin .TextCommand ):
155161 def run (self , edit , block = False ):
156- path = self .view .file_name () or '<Unsaved>'
157- content = self .view .substr (sublime .Region (0 , self .view .size ()))
158- lang , _ = os .path .splitext (os .path .basename (self .view .settings ().get ('syntax' )))
159- pos = self .view .sel ()[0 ].end ()
160- defns , = codeintel (self .view , path , content , lang , pos , forms = ('defns' ,))
162+ view = self .view
163+ path = view .file_name ()
164+ content = view .substr (sublime .Region (0 , view .size ()))
165+ lang , _ = os .path .splitext (os .path .basename (view .settings ().get ('syntax' )))
166+ pos = view .sel ()[0 ].end ()
167+ defns , = codeintel (view , path , content , lang , pos , forms = ('defns' ,))
161168 if defns is not None :
162169 defn = defns [0 ]
163170 path = defn .path
@@ -175,21 +182,37 @@ def run(self, edit, block=False):
175182_ci_db_catalog_dirs_ = []
176183_ci_db_import_everything_langs = None
177184_ci_extra_module_dirs_ = None
185+ _ci_scan_callbacks_ = {}
186+ _ci_save_ = 0
187+
188+ def codeintel_scanning (force = False ):
189+ global _ci_save_
190+ for path , callback in _ci_scan_callbacks_ .items ():
191+ del _ci_scan_callbacks_ [path ]
192+ callback (path )
193+ if not force :
194+ sublime .set_timeout (codeintel_scanning , 3000 )
195+ # saving and culling cached parts of the database:
196+ if _ci_mgr_ :
197+ _ci_save_ -= 1
198+ if _ci_save_ == 0 or force :
199+ _ci_mgr_ .db .save ()
200+ _ci_mgr_ .db .cull_mem ()
201+ if _ci_save_ <= 0 :
202+ _ci_save_ = 3
203+ sublime .set_timeout (codeintel_scanning , 3000 )
178204
179205def codeintel_cleanup (path ):
180206 global _ci_mgr_
181207 if path in _ci_envs_ :
182208 del _ci_envs_ [path ]
183209 if not _ci_envs_ :
210+ codeintel_scanning (True )
184211 _ci_mgr_ .finalize ()
185212 _ci_mgr_ = None
186213
187- def codeintel (view , path , content , lang , pos , forms ):
214+ def codeintel_scan (view , path , content , lang ):
188215 global _ci_mgr_
189- cplns = None
190- calltips = None
191- defns = None
192-
193216 try :
194217 lang = lang or guess_lang_from_path (path )
195218 except CodeIntelError :
@@ -221,7 +244,7 @@ def codeintel(view, path, content, lang, pos, forms):
221244 }
222245 _config = {}
223246 tryReadCodeIntelDict (os .path .expanduser (os .path .join ('~' , '.codeintel' , 'config' )), _config )
224- project_dir = find_ropeproject (path , '.codeintel' )
247+ project_dir = path and find_folder (path , '.codeintel' )
225248 if project_dir :
226249 tryReadCodeIntelDict (os .path .join (project_dir , 'config' ), _config )
227250 config .update (_config .get (lang , {}))
@@ -241,47 +264,64 @@ def codeintel(view, path, content, lang, pos, forms):
241264
242265 calltip (view , "" )
243266
244- mgr .env = env
267+ mgr = _ci_mgr_
268+ buf = mgr .buf_from_content (content , lang , env , path or "<Unsaved>" , encoding )
269+ if isinstance (buf , CitadelBuffer ):
270+ if not path or view .is_scratch ():
271+ buf .scan () #FIXME: Always scanning unsaved files (since many tabs can have unsaved files, or find other path as ID)
272+ else :
273+ _dirty = view .is_dirty ()
274+ if _dirty :
275+ mtime = 1
276+ else :
277+ mtime = os .stat (path )[stat .ST_MTIME ]
278+ buf .scan (mtime = mtime , skip_scan_time_check = _dirty )
279+ return buf
280+ return None
281+
282+ def codeintel (view , path , content , lang , pos , forms ):
283+ cplns = None
284+ calltips = None
285+ defns = None
245286
246- buf = mgr . buf_from_content ( content , lang , env , path , encoding )
247- if not isinstance ( buf , CitadelBuffer ) :
287+ buf = codeintel_scan ( view , path , content , lang )
288+ if not buf :
248289 logger (view , "Error" , "`%s' (%s) is not a language that uses CIX" % (path , buf .lang ))
249290 return [None ] * len (forms )
250-
251- if 'cplns' in forms or 'calltips' in forms or 'defns' in forms :
291+
292+ try :
293+ trg = buf .trg_from_pos (pos )
294+ defn_trg = buf .defn_trg_from_pos (pos )
295+ except CodeIntelError :
296+ trg = None
297+ defn_trg = None
298+ else :
299+ eval_log_stream = StringIO ()
300+ hdlr = logging .StreamHandler (eval_log_stream )
301+ fmtr = logging .Formatter ("%(name)s: %(levelname)s: %(message)s" )
302+ hdlr .setFormatter (fmtr )
303+ codeintel_logger .addHandler (hdlr )
304+ ctlr = LogEvalController (codeintel_logger )
252305 try :
253- trg = buf .trg_from_pos (pos )
254- defn_trg = buf .defn_trg_from_pos (pos )
255- except CodeIntelError :
256- trg = None
257- defn_trg = None
258- else :
259- eval_log_stream = StringIO ()
260- hdlr = logging .StreamHandler (eval_log_stream )
261- fmtr = logging .Formatter ("%(name)s: %(levelname)s: %(message)s" )
262- hdlr .setFormatter (fmtr )
263- codeintel_logger .addHandler (hdlr )
264- ctlr = LogEvalController (codeintel_logger )
265- try :
266- if 'cplns' in forms and trg and trg .form == TRG_FORM_CPLN :
267- cplns = buf .cplns_from_trg (trg , ctlr = ctlr )
268- if 'calltips' in forms and trg and trg .form == TRG_FORM_CALLTIP :
269- calltips = buf .calltips_from_trg (trg , ctlr = ctlr )
270- if 'defns' in forms and defn_trg and defn_trg .form == TRG_FORM_DEFN :
271- defns = buf .defns_from_trg (defn_trg , ctlr = ctlr )
272- finally :
273- codeintel_logger .removeHandler (hdlr )
274- msg = eval_log_stream .getvalue ()
275- if msg :
276- logger (view , "Error" , msg )
306+ if 'cplns' in forms and trg and trg .form == TRG_FORM_CPLN :
307+ cplns = buf .cplns_from_trg (trg , ctlr = ctlr )
308+ if 'calltips' in forms and trg and trg .form == TRG_FORM_CALLTIP :
309+ calltips = buf .calltips_from_trg (trg , ctlr = ctlr )
310+ if 'defns' in forms and defn_trg and defn_trg .form == TRG_FORM_DEFN :
311+ defns = buf .defns_from_trg (defn_trg , ctlr = ctlr )
312+ finally :
313+ codeintel_logger .removeHandler (hdlr )
314+ msg = eval_log_stream .getvalue ()
315+ if msg :
316+ logger (view , "Error" , msg )
277317
278318 ret = []
279319 l = locals ()
280320 for f in forms :
281321 ret .append (l .get (f ))
282322 return ret
283323
284- def find_ropeproject (start_at , look_for ):
324+ def find_folder (start_at , look_for ):
285325 start_at = os .path .abspath (start_at )
286326 if not os .path .isdir (start_at ):
287327 start_at = os .path .dirname (start_at )
0 commit comments