Skip to content

Commit dcdef5b

Browse files
committedJun 10, 2014
Use os.walk instead of recursion which runs a zillion of time much faster, as it scans sequentially. Also deduplicate folders.
1 parent fa8b6fa commit dcdef5b

File tree

2 files changed

+108
-57
lines changed

2 files changed

+108
-57
lines changed
 

‎mysign.py

+79-41
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717

1818
global debug
19-
debug = True
19+
debug = False
2020

2121
class MySign:
2222

@@ -115,34 +115,66 @@ def run(self):
115115
Pref.folders = list(folders) # this is the "cache id" to know when to rescan the whole thing again
116116
# add also as folders, the dirname of the current opened files
117117
folders += [norm_path(dirname(file)) for file in files]
118-
118+
# deduplicate
119119
folders = list(set(folders))
120+
_folders = []
121+
for folder in folders:
122+
_folders = deduplicate_crawl_folders(_folders, folder)
123+
folders = _folders
124+
120125
if debug:
121126
print('Folders to scan:')
122127
print("\n".join(folders))
123-
for folder in folders:
124-
self.get_files(folder, files)
125128

126-
files = list(set(files))
127-
if debug:
128-
print('Files to parse:')
129-
print("\n".join(files))
129+
# pasing
130+
files_seen = 0
131+
files_js = 0
132+
files_cache_miss = 0
133+
files_cache_hit = 0
134+
files_failed_parsing = 0
130135

136+
# parse files with priority
131137
for file in files:
132-
if time.time() - Pref.scan_started > Pref.scan_timeout:
133-
Pref.scan_aborted = True
138+
if should_abort():
134139
break
140+
files_seen += 1
141+
files_js += 1
135142
if file not in MySign.files:
136143
try:
137144
self.parse_functions(file)
145+
files_cache_miss += 1
138146
except:
139-
pass # the file may be unreachable/unreadable
147+
files_failed_parsing += 1# the file may be unreachable/unreadable
140148
else:
141-
if debug:
142-
print('Skipping parsing of already indexed file')
149+
files_cache_hit += 1
150+
151+
# now parse folders
152+
for folder in folders:
153+
if should_abort():
154+
break
155+
for dir, dnames, files in os.walk(folder):
156+
if should_abort():
157+
break
158+
for f in files:
159+
if should_abort():
160+
break
161+
files_seen += 1
162+
file = os.path.join(dir, f)
163+
if not should_exclude(file) and is_javascript_file(file):
164+
files_js += 1
165+
file = norm_path(file)
166+
if file not in MySign.files:
167+
try:
168+
self.parse_functions(file)
169+
files_cache_miss += 1
170+
except:
171+
files_failed_parsing += 1# the file may be unreachable/unreadable
172+
else:
173+
files_cache_hit += 1
143174

144175
if debug:
145-
print('Scan done in '+str(time.time()-Pref.scan_started)+' seconds - Scan was aborted: '+str(Pref.scan_aborted)+' - Relevant Files:'+str(len(files)))
176+
print('Scan done in '+str(time.time()-Pref.scan_started)+' seconds - Scan was aborted: '+str(Pref.scan_aborted))
177+
print('Files Seen:'+str(files_seen)+', Files JS:'+str(files_js)+', Cache Miss:'+str(files_cache_miss)+', Cache Hit:'+str(files_cache_hit)+', Failed Parsing:'+str(files_failed_parsing))
146178

147179
Pref.scan_running = False
148180
Pref.scan_aborted = False
@@ -158,18 +190,6 @@ def parse_functions(self, file):
158190
functions.append(matches)
159191
MySign.save_functions(file, functions)
160192

161-
def get_files(self, dir, files):
162-
if time.time() - Pref.scan_started > Pref.scan_timeout:
163-
Pref.scan_aborted = True
164-
return
165-
for file in os.listdir(dir):
166-
file = os.path.join(dir, file)
167-
if os.path.isfile(file) and not should_exclude(file):
168-
if is_javascript_file(file):
169-
files.append(norm_path(file))
170-
elif os.path.isdir(file) and not should_exclude(file):
171-
self.get_files(file, files)
172-
173193
class MySignEventListener(sublime_plugin.EventListener):
174194

175195
def on_post_save(self, view):
@@ -181,7 +201,7 @@ def on_load(self, view):
181201
if norm_path(view.file_name()) not in MySign.files: # only if it is not indexed
182202
MySignCollectorThread(view.file_name()).start()
183203

184-
def on_deactivated(self, view):
204+
def on_activated(self, view):
185205
update_folders()
186206

187207
def on_query_completions(self, view, prefix, locations):
@@ -209,6 +229,35 @@ def norm_path_string(file):
209229
def should_exclude(file):
210230
return len([1 for exclusion in Pref.excluded_files_or_folders if exclusion in file])
211231

232+
def update_folders():
233+
folders = list(set([norm_path(folder) for w in sublime.windows() for folder in w.folders() if folder and not should_exclude(norm_path(folder))]))
234+
_folders = []
235+
for folder in folders:
236+
_folders = deduplicate_crawl_folders(_folders, folder)
237+
_folders.sort()
238+
Pref.updated_folders = _folders
239+
Pref.updated_files = [norm_path(v.file_name()) for w in sublime.windows() for v in w.views() if v.file_name() and is_javascript_file(v.file_name()) and not should_exclude(norm_path(v.file_name()))]
240+
241+
def should_abort():
242+
if time.time() - Pref.scan_started > Pref.scan_timeout:
243+
Pref.scan_aborted = True
244+
return Pref.scan_aborted
245+
246+
# returns folders without child subfolders
247+
def deduplicate_crawl_folders(items, item):
248+
new_list = []
249+
add = True
250+
for i in items:
251+
if i.find(item+'\\') == 0 or i.find(item+'/') == 0:
252+
continue
253+
else:
254+
new_list.append(i)
255+
if (item+'\\').find(i+'\\') == 0 or (item+'/').find(i+'/') == 0:
256+
add = False
257+
if add:
258+
new_list.append(item)
259+
return new_list
260+
212261
class Pref():
213262

214263
def load(self):
@@ -232,7 +281,7 @@ def load(self):
232281
Pref.scan_running = False # to avoid multiple scans at the same time
233282
Pref.scan_aborted = False # for debuging purposes
234283
Pref.scan_started = 0
235-
Pref.scan_timeout = 30 # seconds
284+
Pref.scan_timeout = 60 # seconds
236285

237286
update_folders()
238287

@@ -242,14 +291,8 @@ def load(self):
242291
def MySign_folder_change_watcher():
243292
while True:
244293
time.sleep(5)
245-
if not Pref.scan_running:
246-
folders = list(set(Pref.updated_folders))
247-
folders.sort()
248-
249-
Pref.folders = list(set(Pref.folders))
250-
Pref.folders.sort()
251-
if Pref.folders != folders:
252-
MySignCollectorThread().start()
294+
if not Pref.scan_running and Pref.updated_folders != Pref.folders:
295+
MySignCollectorThread().start()
253296

254297
def plugin_loaded():
255298
global Pref, s
@@ -263,10 +306,5 @@ def plugin_loaded():
263306
running_MySign_folder_change_watcher = True
264307
thread.start_new_thread(MySign_folder_change_watcher, ())
265308

266-
def update_folders():
267-
Pref.updated_folders = [norm_path(folder) for w in sublime.windows() for folder in w.folders() if folder and not should_exclude(norm_path(folder))]
268-
Pref.updated_files = [norm_path(v.file_name()) for w in sublime.windows() for v in w.views() if v.file_name() and is_javascript_file(v.file_name()) and not should_exclude(norm_path(v.file_name()))]
269-
270-
271309
if int(sublime.version()) < 3000:
272310
plugin_loaded()

‎readme.md

+29-16
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1-
MySignature - Sublime text 2/3 plugin
2-
-------------------------------------
3-
4-
MySignature plugin is very lightweight plugin for sublime which improve the sublime text autocomplete functionality.
5-
6-
Each method in the autocomplete pop-up box is presented with its signature (method name and arguments) using SublimeText's "auto_complete" box. (You can usually make this box show up with Ctrl+Space.)
7-
8-
This plugin works on save: when you save any file in your project, the plugin maps all your javascript methods of the form `var name = function() {}` and `name: function() {}`. When the complete box is opened (ctrl+space or by the editor), it shows the methods in your project files with the signature. (It currently does not support minified files since the method used is a line-by-line search.)
9-
10-
This plugin is for Javascript Developers only.
11-
12-
Please read more about the plugin and its development at http://www.eladyarkoni.com/2012/09/sublime-text-auto-complete-plugin.html.
13-
14-
Enjoy!
15-
16-
Elad Yarkoni.
1+
# MySignature - Sublime Text Package
2+
3+
Wide JavaScript autocomplete functionality for [Sublime Text][] with `method/function` signature (arguments) and `var` completion. (You can usually make the completion box show up with Ctrl+Space in a js file.)
4+
5+
The package will keep an index of methods/functions seen in .js files doing a dumb parsing: it looks for `name = function(...)` and `name: function(...)`. It does not evaluate objects.
6+
7+
Since version 2, files are parsed only the first time these are seen and then will only reparse a file if you save it (to keep the index up to date.)
8+
9+
As source for its index will look into:
10+
11+
- All the js files of the current opened projects/folders. (this includes all the windows and scans for changes periodically in an optimized way, a file is only parsed in case of a cache miss)
12+
13+
- If you open a js file that is outside the current project, it will scan the folder where this file resides.
14+
15+
- Completion of methods/functions in unsaved files, and completion of `var`s for the current file are generated on the fly, with the incredible fast API of Sublime Text.
16+
17+
Will trigger its magic in js files and js scopes (eg in a script tag of an HTML file.)
18+
19+
For the original development read about at <http://www.eladyarkoni.com/2012/09/sublime-text-auto-complete-plugin.html>
20+
21+
For the performance improvements take a look to https://github.com/eladyarkoni/MySignaturePlugin/pull/7
22+
23+
Enjoy!
24+
25+
2012 Elad Yarkoni
26+
27+
2014 Tito Bouzout \<tito.bouzout@gmail.com\>
28+
29+
[Sublime Text]: http://www.sublimetext.com/3

0 commit comments

Comments
 (0)
Please sign in to comment.