diff --git a/Main.sublime-menu b/Main.sublime-menu new file mode 100644 index 0000000..6f1bdab --- /dev/null +++ b/Main.sublime-menu @@ -0,0 +1,34 @@ +[ + { + "caption": "Preferences", + "mnemonic": "n", + "id": "preferences", + "children": + [ + { + "caption": "Package Settings", + "mnemonic": "P", + "id": "package-settings", + "children": + [ + { + "caption": "SublimeAllAutocomplete", + "children": + [ + { + "command": "open_file", + "args": {"file": "${packages}/SublimeAllAutocomplete/SublimeAllAutocomplete.sublime-settings"}, + "caption": "Settings – Default" + }, + { + "command": "open_file", + "args": {"file": "${packages}/User/SublimeAllAutocomplete.sublime-settings"}, + "caption": "Settings – User" + } + ] + } + ] + } + ] + } +] diff --git a/README.md b/README.md index c29a52d..89b6d65 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,42 @@ Extends the default autocomplete to find matches in all open files. By default Sublime only considers words found in the current file. +This is a fork of https://github.com/alienhard/SublimeAllAutocomplete/ + +This fork includes hack to fix SASS and CSS dash bug +https://github.com/alienhard/SublimeAllAutocomplete/issues/18/ +http://sublimetext.userecho.com/topic/222861-/ + Install ------- If you have Package Control installed in Sublime just press ctrl+shift+p (Windows, Linux) or cmd+shift+p (OS X) to open the Command Pallete. -Start typing 'install' to select 'Package Control: Install Package', then search for AllAutocomplete and select it. That's it. + +start typing "Package Control: Add Repository", press Enter and insert + https://github.com/andruhon/SublimeAllAutocomplete +press Enter, start typing "Package Control: Install Package", press Enter, start typing +"All Autocomplete" and select one with "https://github.com/andruhon/SublimeAllAutocomplete" URL You can also install this package manually by entering the Packages directory of Sublime Text 2/3 and issuing on a terminal: - git clone https://github.com/alienhard/SublimeAllAutocomplete + git clone https://github.com/andruhon/SublimeAllAutocomplete + + +Configure +--------- + +Available options (with default values): +{ + "apply_with_dash_hack_syntaxes": ["source.sass","source.css"], + "return_nothing_on_empty_prefix": true, + "do_not_search_in_current_view": false +} + +You can override this settings in user AllAutocomplete.sublime-settings (preferences->package settings->SublimeAllAutoComplete->Settings-User) + +You can also remove dash from "word_separators" option in syntax specific settings for CSS or SASS if you want to see all suggestions, +not only after pressing next dash. (Settings-More->Syntax Specific-User, when file of particular syntax is open) LICENSE diff --git a/SublimeAllAutocomplete.py b/SublimeAllAutocomplete.py index b68f8a3..f9f6588 100644 --- a/SublimeAllAutocomplete.py +++ b/SublimeAllAutocomplete.py @@ -14,9 +14,43 @@ MAX_WORDS_PER_VIEW = 100 MAX_FIX_TIME_SECS_PER_VIEW = 0.01 -class AllAutocomplete(sublime_plugin.EventListener): +#Change this variable to True to se debug output +DEBUG = False + +class SubLimeallautocomplete(sublime_plugin.EventListener): + #default settings + dash_hack_sytaxes = ["source.scss","source.sass","source.css"] + return_nothing_on_empty = True + not_search_in_current = True + + def __init__(self): + if DEBUG: print("initializing Sublimeallautocomplete(SAA) plugin") + + #Loading settings when view is activated + def on_activated(self,view): + if DEBUG: print("\nActivating SAA for view",view) + self.plugin_settings = sublime.load_settings('SublimeAllAutocomplete.sublime-settings') + + dash_hack_sytaxes = self.plugin_settings.get('apply_with_dash_hack_syntaxes') + return_nothing_on_empty = self.plugin_settings.get('return_nothing_on_empty_prefix') + not_search_in_current = self.plugin_settings.get('do_not_search_in_current_view') + if DEBUG: print("SAA: user settings:\n dash_hack_sytaxes:{0}\n return_nothing_on_empty:{1}\n not_search_in_current:{2}".format(dash_hack_sytaxes,return_nothing_on_empty,not_search_in_current)) + + #using default settings + if dash_hack_sytaxes != None: + self.dash_hack_sytaxes = dash_hack_sytaxes + + if return_nothing_on_empty != None: + self.return_nothing_on_empty = return_nothing_on_empty + + if not_search_in_current != None: + self.not_search_in_current = not_search_in_current + + if DEBUG: print("SAA: Merged settings:\n dash_hack_sytaxes:{0}\n return_nothing_on_empty:{1}\n not_search_in_current:{2}\n".format(self.dash_hack_sytaxes,self.return_nothing_on_empty,self.not_search_in_current)) def on_query_completions(self, view, prefix, locations): + + if DEBUG: print("SAA: running completion query '{0}'".format(prefix)) words = [] # Limit number of views but always include the active view. This @@ -24,71 +58,115 @@ def on_query_completions(self, view, prefix, locations): other_views = [v for v in sublime.active_window().views() if v.id != view.id] views = [view] + other_views views = views[0:MAX_VIEWS] + if DEBUG: print("SAA: views to process {0}".format(views)) + + if self.return_nothing_on_empty: + if not prefix: + if DEBUG: print("SAA: returning nothing on empty query") + return words; for v in views: + view_words = [] + location = 0 + # Hacking around dash auto-completion bug + # https://github.com/alienhard/Sublimeallautocomplete/issues/18 + + # Sublime probably already works fine with suggestions from current view + if self.not_search_in_current and v.id == view.id: + continue + if len(locations) > 0 and v.id == view.id: - view_words = v.extract_completions(prefix, locations[0]) + location = locations[0] + + if self.is_need_to_be_hacked(v, self.dash_hack_sytaxes): + # apply hack for css and sass only + view_words = self.extract_completions_wdash(v,prefix); else: - view_words = v.extract_completions(prefix) - view_words = filter_words(view_words) - view_words = fix_truncation(v, view_words) + view_words = v.extract_completions(prefix, location) + + view_words = self.filter_words(view_words) + view_words = self.fix_truncation(v, view_words) words += view_words - words = without_duplicates(words) + words = self.without_duplicates(words) + if DEBUG: print("SAA: {0} words found".format(len(words))) + matches = [(w, w.replace('$', '\\$')) for w in words] return matches -def filter_words(words): - words = words[0:MAX_WORDS_PER_VIEW] - return [w for w in words if MIN_WORD_SIZE <= len(w) <= MAX_WORD_SIZE] - -# keeps first instance of every word and retains the original order -# (n^2 but should not be a problem as len(words) <= MAX_VIEWS*MAX_WORDS_PER_VIEW) -def without_duplicates(words): - result = [] - for w in words: - if w not in result: - result.append(w) - return result - - -# Ugly workaround for truncation bug in Sublime when using view.extract_completions() -# in some types of files. -def fix_truncation(view, words): - fixed_words = [] - start_time = time.time() - - for i, w in enumerate(words): - #The word is truncated if and only if it cannot be found with a word boundary before and after - - # this fails to match strings with trailing non-alpha chars, like - # 'foo?' or 'bar!', which are common for instance in Ruby. - match = view.find(r'\b' + re.escape(w) + r'\b', 0) - truncated = is_empty_match(match) - if truncated: - #Truncation is always by a single character, so we extend the word by one word character before a word boundary - extended_words = [] - view.find_all(r'\b' + re.escape(w) + r'\w\b', 0, "$0", extended_words) - if len(extended_words) > 0: - fixed_words += extended_words + def is_need_to_be_hacked(self, v, dash_hack_sytaxes): + for syntax in dash_hack_sytaxes: + if v.scope_name(0).find(syntax) >= 0: + return True + return False + + # extract auto-completions with dash + # see https://github.com/alienhard/Sublimeallautocomplete/issues/18 + def extract_completions_wdash(self, v,prefix): + if DEBUG: print("SAA: extracting words with dashes") + word_regions = v.find_all(prefix,0) + words = [] + + for wr in word_regions: + word = v.substr(v.word(wr)) + words.append(word) + + if DEBUG: print("SAA: {0} dash-words found".format(len(words))) + + return words + + def filter_words(self, words): + words = words[0:MAX_WORDS_PER_VIEW] + return [w for w in words if MIN_WORD_SIZE <= len(w) <= MAX_WORD_SIZE] + + # keeps first instance of every word and retains the original order + # (n^2 but should not be a problem as len(words) <= MAX_VIEWS*MAX_WORDS_PER_VIEW) + def without_duplicates(self, words): + if DEBUG: print("SAA: cleaning duplicates") + result = [] + for w in words: + if w not in result: + result.append(w) + return result + + + # Ugly workaround for truncation bug in Sublime when using view.extract_completions() + # in some types of files. + def fix_truncation(self, view, words): + if DEBUG: print("SAA: fixing turncation") + fixed_words = [] + start_time = time.time() + + for i, w in enumerate(words): + #The word is truncated if and only if it cannot be found with a word boundary before and after + + # this fails to match strings with trailing non-alpha chars, like + # 'foo?' or 'bar!', which are common for instance in Ruby. + match = view.find(r'\b' + re.escape(w) + r'\b', 0) + truncated = self.is_empty_match(match) + if truncated: + #Truncation is always by a single character, so we extend the word by one word character before a word boundary + extended_words = [] + view.find_all(r'\b' + re.escape(w) + r'\w\b', 0, "$0", extended_words) + if len(extended_words) > 0: + fixed_words += extended_words + else: + # to compensate for the missing match problem mentioned above, just + # use the old word if we didn't find any extended matches + fixed_words.append(w) else: - # to compensate for the missing match problem mentioned above, just - # use the old word if we didn't find any extended matches + #Pass through non-truncated words fixed_words.append(w) + + # if too much time is spent in here, bail out, + # and don't bother fixing the remaining words + if time.time() - start_time > MAX_FIX_TIME_SECS_PER_VIEW: + return fixed_words + words[i+1:] + + return fixed_words + + def is_empty_match(self, match): + if sublime.version() >= '3000': + return match.empty() else: - #Pass through non-truncated words - fixed_words.append(w) - - # if too much time is spent in here, bail out, - # and don't bother fixing the remaining words - if time.time() - start_time > MAX_FIX_TIME_SECS_PER_VIEW: - return fixed_words + words[i+1:] - - return fixed_words - -if sublime.version() >= '3000': - def is_empty_match(match): - return match.empty() -else: - def is_empty_match(match): - return match is None + return match is None diff --git a/SublimeAllAutocomplete.sublime-settings b/SublimeAllAutocomplete.sublime-settings new file mode 100644 index 0000000..05f3a4c --- /dev/null +++ b/SublimeAllAutocomplete.sublime-settings @@ -0,0 +1,5 @@ +{ + "apply_with_dash_hack_syntaxes": ["source.scss","source.sass","source.css"], + "return_nothing_on_empty_prefix": true, + "do_not_search_in_current_view": false +} \ No newline at end of file