diff --git a/Commands/Complete.tmCommand b/Commands/Complete.tmCommand index b1cc7ef..2b5fe25 100644 --- a/Commands/Complete.tmCommand +++ b/Commands/Complete.tmCommand @@ -6,7 +6,7 @@ nop command #!/usr/bin/env ruby -require ENV['TM_SUPPORT_PATH'] + '/lib/tm/complete' +require ENV['TM_BUNDLE_SUPPORT'] + '/lib/tm/complete' TextMate::Complete.new.complete! input diff --git a/Commands/Documentation for Word : Selection (tool tip).tmCommand b/Commands/Documentation for Word : Selection (tool tip).tmCommand index 28a263b..239ac9b 100644 --- a/Commands/Documentation for Word : Selection (tool tip).tmCommand +++ b/Commands/Documentation for Word : Selection (tool tip).tmCommand @@ -6,7 +6,7 @@ nop command #!/usr/bin/env ruby -require ENV['TM_SUPPORT_PATH'] + '/lib/tm/complete' +require ENV['TM_BUNDLE_SUPPORT'] + '/lib/tm/complete' TextMate::Complete.new.tip! fallbackInput diff --git a/Support/lib/current_word.rb b/Support/lib/current_word.rb new file mode 100644 index 0000000..84d97c7 --- /dev/null +++ b/Support/lib/current_word.rb @@ -0,0 +1,176 @@ +# When creating a custom regex for Word.current_word, you need to keep a few things in mind: +# The regex matches from your caret, so your caret position will always be the beginning of the line +# Everything before your caret is reversed for the match, so the left of your caret will also match your caret position as ^ +# You must use a capture group () for the text you're trying to match +# You must use a capture group () for the text before/after your match +# +# EG: /(^[a-z]*)(.*$)/ +# The first capture group in that regex will match from your caret out until it can't find anymore lowercase letters. +# Then it'll match everything else in the line as the before/after match part. +# You can currently only use a single regex to match before and after your caret. +# +# Since your regex matches what's before your caret in reverse, you'll have to reverse specific stuff in your regex, eg: +# /(.*):/ wouldn't match 'color' in ` color: `, but /:(.*)/ would. +# It's reversed you see +# +module Word + def self.current_word(pat='a-zA-Z0-9', direction=:both) + word = ENV['TM_SELECTED_TEXT'] + + if word.nil? or word.empty? + line, col = ENV['TM_CURRENT_LINE'], ENV['TM_LINE_INDEX'].to_i + + if pat.kind_of? Regexp + @reg = pat + else + @reg = /(^[#{pat}]*)(.*$\r?\n?)/ + end + + left, before_match = *( line[0...col].reverse.match(@reg) ||[])[1..2] + right, after_match = *( line[col..-1] .match(@reg) ||[])[1..2] + + (before_match||='').reverse! + (left||='').reverse! + + # p before_match, left, right, after_match + + case direction + when :both then word = [left, right].join('') + when :left then word = left + when :right then word = right + when :hash then word = { + :line => [before_match, left, right, after_match].join(''), + :before_match => before_match, + :left => left, + :right => right, + :after_match => after_match, + } + end + end + + word + end +end + +if __FILE__ == $0 + require "test/unit" + class TestWord < Test::Unit::TestCase +# =begin + def test_with_spaces + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + BeforeAfter + EOF + ENV['TM_LINE_INDEX'] = '10' + ENV['TM_TAB_SIZE'] = '2' + assert_equal 'BeforeAfter', Word.current_word + assert_equal 'Before', Word.current_word('a-zA-Z0-9',:left) + assert_equal 'After', Word.current_word('a-zA-Z0-9',:right) + + assert_equal ' Before', Word.current_word(" a-zA-Z",:left) + assert_equal 'After ', Word.current_word(" a-zA-Z",:right) + end + + def test_with_tabs + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + BeforeAfter + EOF + ENV['TM_LINE_INDEX'] = '8' + ENV['TM_TAB_SIZE'] = '2' + assert_equal 'BeforeAfter', Word.current_word + assert_equal 'Before', Word.current_word('a-zA-Z0-9',:left) + assert_equal 'After', Word.current_word('a-zA-Z0-9',:right) + + assert_equal "\t\tBefore", Word.current_word("\ta-zA-Z",:left) + assert_equal "After\t\t", Word.current_word("\ta-zA-Z",:right) + end + + def test_with_dash + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + Before--After + EOF + ENV['TM_LINE_INDEX'] = '11' + ENV['TM_TAB_SIZE'] = '2' + assert_equal 'Before--After', Word.current_word('-a-zA-Z0-9') + assert_equal 'Before-', Word.current_word('-a-zA-Z0-9',:left) + assert_equal '-After', Word.current_word('-a-zA-Z0-9',:right) + + assert_equal 'Before-', Word.current_word("\ta-zA-Z\-",:left) + end + + def test_hash_result + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + before_match BeforeAfter after_match + EOF + ENV['TM_LINE_INDEX'] = '22' + ENV['TM_TAB_SIZE'] = '2' + + word = Word.current_word("a-zA-Z",:hash) + + assert_equal ENV['TM_CURRENT_LINE'], "#{word[:line]}" + assert_equal 'Before', word[:left] + assert_equal 'After', word[:right] + end +=begin +=end + def test_both_result + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + before_match BeforeAfter after_match + EOF + ENV['TM_LINE_INDEX'] = '22' + ENV['TM_TAB_SIZE'] = '2' + + assert_equal 'BeforeAfter', Word.current_word("a-zA-Z",:both) + end + + def test_should_support_custom_regex + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + before_match BeforeAfter after_match + EOF + ENV['TM_LINE_INDEX'] = '22' + ENV['TM_TAB_SIZE'] = '2' + + assert_equal '', Word.current_word(/[a-zA-Z]/,:both) # No match since no capture group was used! + + assert_equal 'ef', Word.current_word(/([a-z])/,:both) # Capture group, but only selecting a single caracter before and after the caret + assert_equal 'eforefter', Word.current_word(/([a-z]+)/,:both) # Only lowercase characters + assert_equal 'BeforeAfter', Word.current_word(/^([a-z]*)/i,:both) # Ignore case + assert_equal 'BeforeAfter', Word.current_word(/^([a-zA-Z]*)/,:both) # Explicit case + end + + def test_should_support_custom_regex_example1 + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF + background-color: ; + EOF + ENV['TM_LINE_INDEX'] = '20' + ENV['TM_TAB_SIZE'] = '2' + + assert_equal ' background-color: ', Word.current_word(/^(.*)/,:left) + assert_equal 'background-color', Word.current_word(/:([-a-z]+)/,:left) + end + + def test_should_support_custom_regex_example2 + ENV['TM_SELECTED_TEXT']= nil + ENV['TM_CURRENT_LINE'] = <<-EOF +

Lorem ipsum dolor sit amet

+ EOF + ENV['TM_LINE_INDEX'] = '44' + ENV['TM_TAB_SIZE'] = '2' + + assert_equal %Q{\t

Lorem ipsum}, Word.current_word(/^(.*)/,:left) + assert_equal 'Lorem ipsum dolor sit amet', Word.current_word(/^([^<>]+)/i,:both) + + # You have to reverse the regex since it's matching against the reverse of the text before the caret + assert_equal 'p', Word.current_word(/([-:a-z]+) "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Commands.png", + "D" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Drag Commands.png", + "L" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Languages.png", + "M" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Macros.png", + "P" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Preferences.png", + "S" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Snippets.png", + "T" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Templates.png", + "Doc" => "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Template Files.png", + } + + def initialize + end + + # 0-config completion command using environment variables for everything + def complete! + return choices unless choices + TextMate::UI.complete(choices, {:images => images, :extra_chars => extra_chars}) + end + + def tip! + # If there is no current_word, then check the next current_word + # If there really is no current_word, then show a menu of choices + + chars = "a-zA-Z0-9" # Hard-coded into D2 + chars += Regexp.escape(extra_chars) if extra_chars + current_word ||= Word.current_word chars, :both + + result = nil + menu_choices = nil + choices = nil + choice = 0 + + [current_word, current_method_name, current_collection_name].each do |initial_filter| + next unless initial_filter and not initial_filter.empty? + # p initial_filter + + choices = self.choices.select { |c| (c['match'] || c['display']) =~ /^#{Regexp.quote(initial_filter)}/ } + + # p choices + break if choices and not choices.empty? + end + choices ||= self.choices + + menu_choices = choices.map { |c| c['display'] } + choice = TextMate::UI.menu(menu_choices) if menu_choices and menu_choices.length > 1 + if choice + result = choices[choice] + end + + TextMate::UI.tool_tip( result['tool_tip'], {:format => result['tool_tip_format'] || :text }) if result + end + + def choices + @choices ||= data['suggestions'] + end + def choices= choice_array + @choices = array_to_suggestions(choice_array) + end + + def images + @images = data['images'] || IMAGES + + data['images']||{}.each_pair do |name,path| + @images[name] = path + next if File.exists? @images[name] + @images[name] = ENV['TM_BUNDLE_SUPPORT'] + "/#{IMAGES_FOLDER_NAME}/" + path + next if File.exists? @images[name] + @images[name] = ENV['TM_SUPPORT_PATH'] + "/#{IMAGES_FOLDER_NAME}/" + path + next if File.exists? @images[name] + end + + @images + end + + def tool_tip_prefix + @tool_tip_prefix ||= data['tool_tip_prefix'] + end + + def extra_chars + ENV['TM_COMPLETIONS_EXTRACHARS'] || data['extra_chars'] + end + + def chars + "a-zA-Z0-9" + end + + private + def data(raw_data=nil) + fix_legacy + + raw_data ||= read_data + return {} unless raw_data and not raw_data.empty? + + @data = parse_data raw_data + return @data + end + + def read_data + raw_data = read_file + raw_data ||= read_string + raw_data + end + + def read_file + paths = [ENV['TM_COMPLETIONS_FILE']] if ENV['TM_COMPLETIONS_FILE'] + paths ||= Shellwords.shellwords( ENV['TM_COMPLETIONS_FILES'] ) if ENV.has_key?('TM_COMPLETIONS_FILES') + return nil unless paths + + paths.map do |path| + next unless path and not path.empty? + path = ENV['TM_BUNDLE_SUPPORT'] + '/' + path unless File.exists? path + next unless File.exists? path + + { :data => File.read(path), + :format => path.scan(/\.([^\.]+)$/).last.last + } + end + end + + def read_string + [{:data => ENV['TM_COMPLETIONS'], + :format => ENV['TM_COMPLETIONS_SPLIT'] + }] + end + + attr_accessor :filepath + + def parse_data(raw_datas) + return @parsed if @parsed + parsed = {"suggestions"=>[]} + + raw_datas.each do |raw_data| + suggestions = parsed['suggestions'] + + case raw_data[:format] + when 'plist' + par = parse_plist(raw_data) + when 'json' + par = parse_json(raw_data) + when "txt" + raw_data[:format] = "\n" + par = parse_string(raw_data) + when nil + raw_data[:format] = "," + par = parse_string(raw_data) + else + par = parse_string(raw_data) + end + + if par['tool_tip_prefix'] + par['suggestions'] = par['suggestions'].map do |suggestion| + suggestion['tool_tip'] = par['tool_tip_prefix'] + suggestion['tool_tip'] + suggestion + end + end + + parsed.merge! par + parsed['suggestions'] = suggestions + parsed['suggestions'] + end + + @parsed = parsed + end + def parse_string(raw_data) + return {} unless raw_data and raw_data[:data] + return raw_data[:data] unless raw_data[:data].respond_to? :to_str + raw_data[:data] = raw_data[:data].to_str + + data = {} + data['suggestions'] = array_to_suggestions(raw_data[:data].split(raw_data[:format])) + data + end + def parse_plist(raw_data) + OSX::PropertyList.load(raw_data[:data]) + end + def parse_json(raw_data) + JSON.parse(raw_data[:data]) + end + + def array_to_suggestions(suggestions) + suggestions.delete('') + + suggestions.map! do |c| + {'display' => c} + end + + suggestions + end + def current_method_name + # Regex for finding a method or function name that's close to your caret position using Word.current_word + # TODO: Allow completion prefs to define their own Complete.tip! method_name + + characters = "a-zA-Z0-9" # Hard-coded into D2 + characters += Regexp.escape(extra_chars) if extra_chars + + regex = %r/ + (?> [^\(\)]+ | \) (?> [^\(\)]+ | \) (?> [^\(\)]+ | \) (?> [^\(\)]+ | \) (?> [^\(\)]+ | \) (?> [^\(\)]* ) \( | )+ \( | )+ \( | )+ \( | )+ \( | )+ + (?: \(([#{characters}]+) )?/ix + + Word.current_word(regex,:left) + end + def current_collection_name + characters = "a-zA-Z0-9" # Hard-coded into D2 + characters += Regexp.escape(extra_chars) if extra_chars + + regex = %r/ + (?> [^\[\]]+ | \] (?> [^\[\]]+ | \] (?> [^\[\]]+ | \] (?> [^\[\]]+ | \] (?> [^\[\]]+ | \] (?> [^\[\]]* ) \[ | )+ \[ | )+ \[ | )+ \[ | )+ \[ | )+ + (?: \[([#{characters}]+) )?/ix + + Word.current_word(regex,:left) + end + + def fix_legacy + ENV['TM_COMPLETIONS_SPLIT'] ||= ENV['TM_COMPLETIONS_split'] + end + end +end + +if __FILE__ == $0 + +`open "txmt://open?url=file://$TM_FILEPATH"` #For testing purposes, make this document the topmost so that the complete popup works +ENV['WEB_PREVIEW_RUBY']='NO-RUN' +require "test/unit" +# require "complete" + +class TestComplete < Test::Unit::TestCase + def setup + @string_raw = 'ad(),adipisicing,aliqua,aliquip,amet,anim,aute,cillum,commodo,consectetur,consequat,culpa,cupidatat,deserunt,do,dolor,dolore,Duis,ea,eiusmod,elit,enim,esse,est,et,eu,ex,Excepteur,exercitation,fugiat,id,in,incididunt,ipsum,irure,labore,laboris,laborum,Lorem,magna,minim,mollit,nisi,non,nostrud,nulla,occaecat,officia,pariatur,proident,qui,quis,reprehenderit,sed,sint,sit,sunt,tempor,ullamco,Ut,ut,velit,veniam,voluptate,' + + @plist_raw = <<-'PLIST' + { suggestions = ( + { display = moo; image = Drag; insert = "(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})"; tool_tip = "moo(one, two, four[, five])\n This method does something or other maybe.\n Insert longer description of it here."; }, + { display = foo; image = Macro; insert = "(${1:one}, \"${2:one}\", ${3:three}${4:, ${5:five}, ${6:six}})"; tool_tip = "foo(one, two)\n This method does something or other maybe.\n Insert longer description of it here."; }, + { display = bar; image = Command; insert = "(${1:one}, ${2:one}, \"${3:three}\"${4:, \"${5:five}\", ${6:six}})"; tool_tip = "bar(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here."; } + ); + extra_chars = '.'; + images = { + Command = "Commands.png"; + Drag = "Drag Commands.png"; + Language = "Languages.png"; + Macro = "Macros.png"; + Preference = "Preferences.png"; + Snippet = "Snippets.png"; + Template = "Template Files.png"; + Templates = "Templates.png"; + }; + } + PLIST + + @json_raw = <<-'JSON' + { + "extra_chars": "-_$.", + "suggestions": [ + { "display": ".moo", "image": "", "insert": "(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})", "tool_tip": "moo(one, two, four[, five])\n This method does something or other maybe.\n Insert longer description of it here." }, + { "display": "foo", "image": "", "insert": "(${1:one}, \"${2:one}\", ${3:three}${4:, ${5:five}, ${6:six}})", "tool_tip": "foo(one, two)\n This method does something or other maybe.\n Insert longer description of it here." }, + { "display": "bar", "image": "", "insert": "(${1:one}, ${2:one}, \"${3:three}\"${4:, \"${5:five}\", ${6:six}})", "tool_tip": "bar(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here." } + ], + "images": { + "String" : "String.png", + "RegExp" : "RegExp.png", + "Number" : "Number.png", + "Array" : "Array.png", + "Function": "Function.png", + "Object" : "Object.png", + "Node" : "Node.png", + "NodeList": "NodeList.png" + } + } + JSON + end + + def test_basic_complete + ENV['TM_COMPLETIONS'] = @string_raw + + assert_equal ENV['TM_COMPLETIONS'].split(','), TextMate::Complete.new.choices.map{|c| c['display']} + assert_equal TextMate::Complete::IMAGES, TextMate::Complete.new.images + + TextMate::Complete.new.complete! + end + # + def test_should_support_plist + ENV['TM_COMPLETIONS_SPLIT']='plist' + ENV['TM_COMPLETIONS'] = @plist_raw + TextMate::Complete.new.complete! + end + # + def test_should_support_json + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + + ENV['TM_COMPLETIONS_SPLIT']='json' + ENV['TM_COMPLETIONS'] = @json_raw + fred = TextMate::Complete.new + assert_equal(3, fred.choices.length) + end + # + def test_should_be_able_to_modify_the_choices + ENV['TM_COMPLETIONS'] = @string_raw + + fred = TextMate::Complete.new + + assert_not_nil fred.choices + assert_equal ENV['TM_COMPLETIONS'].split(','), fred.choices.map{|c| c['display']} + fred.choices.reject!{|choice| choice['display'] !~ /^a/ } + assert_equal ENV['TM_COMPLETIONS'].split(',').grep(/^a/), fred.choices.map{|c| c['display']} + + fred.choices=%w[fred is not my name] + assert_equal %w[fred is not my name], fred.choices.map{|c| c['display']} + end + # + def test_should_parse_files_based_on_extension_plist + ENV['TM_COMPLETIONS_FILE'] = '/tmp/completions_test.plist' + + File.open(ENV['TM_COMPLETIONS_FILE'],'w'){|file| file.write @plist_raw } + assert File.exists?(ENV['TM_COMPLETIONS_FILE']) + + fred = TextMate::Complete.new + assert_equal(['moo', 'foo', 'bar'], fred.choices.map{|c| c['display']}) + end + # + def test_should_parse_files_based_on_extension_txt + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + + ENV['TM_COMPLETIONS_FILE'] = '/tmp/completions_test.txt' + + File.open(ENV['TM_COMPLETIONS_FILE'],'w'){|file| file.write @string_raw.gsub(',',"\n") } + assert File.exists?(ENV['TM_COMPLETIONS_FILE']) + + fred = TextMate::Complete.new + + assert_equal(@string_raw.split(','), fred.choices.map{|c| c['display']}) + end + # + def test_should_parse_multiple_files + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + ENV.delete 'TM_COMPLETIONS_FILE' + assert_nil(ENV['TM_COMPLETIONS_FILE']) + + ENV['TM_COMPLETIONS_FILES'] = "'/tmp/completions_test.txt' '/tmp/completions_test1.txt' '/tmp/completions_test2.txt'" + + require 'shellwords' + Shellwords.shellwords( ENV['TM_COMPLETIONS_FILES'] ).each_with_index do |filepath,i| + File.open(filepath,'w'){|file| file.write @string_raw.gsub(',',"#{i}\n") } + assert File.exists?(filepath) + end + + fred = TextMate::Complete.new + + assert_equal(@string_raw.split(',').uniq.length * 3, fred.choices.map{|c| c['display']}.length ) + end + # + def test_should_override_split_with_extension + ENV['TM_COMPLETIONS_SPLIT'] = ',' + ENV['TM_COMPLETIONS_FILE'] = '/tmp/completions_test.plist' + + File.open(ENV['TM_COMPLETIONS_FILE'],'w'){|file| file.write @plist_raw } + assert File.exists?(ENV['TM_COMPLETIONS_FILE']) + + fred = TextMate::Complete.new + assert_equal(['moo', 'foo', 'bar'], fred.choices.map{|c| c['display']}) + end + # + def test_should_get_extra_chars_from_var + ENV['TM_COMPLETIONS_SPLIT']=',' + ENV['TM_COMPLETIONS'] = @string_raw + ENV['TM_COMPLETIONS_EXTRACHARS'] = '.' + + fred = TextMate::Complete.new + assert_equal('.', fred.extra_chars) + end + # + def test_should_get_extra_chars_from_plist + ENV['TM_COMPLETIONS_SPLIT']='plist' + ENV['TM_COMPLETIONS'] = @plist_raw + + assert_nil(ENV['TM_COMPLETIONS_EXTRACHARS']) + + fred = TextMate::Complete.new + assert_equal('.', fred.extra_chars) + end + # TODO: should_fix_image_paths +=begin + def test_should_fix_image_paths + ENV['TM_COMPLETIONS_SPLIT'] = 'plist' + ENV['TM_COMPLETIONS'] = @plist_raw + ENV['TM_BUNDLE_SUPPORT'] = '/tmp' + ENV['TM_SUPPORT_PATH'] = '/tmp' + + images = OSX::PropertyList.load(@plist_raw)['images'] + + FileUtils.mkdir_p "#{ENV['TM_SUPPORT_PATH']}/#{TextMate::Complete::IMAGES_FOLDER_NAME}" + images.each_pair do |name,path| + File.open("#{ENV['TM_SUPPORT_PATH']}/#{TextMate::Complete::IMAGES_FOLDER_NAME}/#{path}", 'w'){ |file| file.write('') } + end + + TextMate::Complete.new.images.each_pair do |name,path| + assert File.exists?(path) + end + + end +=end + def test_should_apply_prefix + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + + @json_raw = <<-'JSON' + { + "extra_chars": "-_$.", + "tool_tip_prefix":"prefix", + "suggestions": [ + { "display": ".moo", "image": "", "insert": "(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})", "tool_tip": "moo(one, two, four[, five])\n This method does something or other maybe.\n Insert longer description of it here." }, + { "display": "foo", "image": "", "insert": "(${1:one}, \"${2:one}\", ${3:three}${4:, ${5:five}, ${6:six}})", "tool_tip": "foo(one, two)\n This method does something or other maybe.\n Insert longer description of it here." }, + { "display": "bar", "image": "", "insert": "(${1:one}, ${2:one}, \"${3:three}\"${4:, \"${5:five}\", ${6:six}})", "tool_tip": "bar(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here." } + ], + "images": { + "String" : "String.png", + "RegExp" : "RegExp.png", + "Number" : "Number.png", + "Array" : "Array.png", + "Function": "Function.png", + "Object" : "Object.png", + "Node" : "Node.png", + "NodeList": "NodeList.png" + } + } + JSON + + ENV['TM_COMPLETIONS_SPLIT']='json' + ENV['TM_COMPLETIONS'] = @json_raw + fred = TextMate::Complete.new + assert_equal(3, fred.choices.length) + assert fred.choices.first['tool_tip'].match(/^prefix/) + end + # + def test_should_show_tooltip_without_inserting_anything + # This method passes if it shows a tooltip when selecting a menu-item + # and DOESN'T insert anything or cause the document think anything has changed + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + + ENV['TM_COMPLETIONS_SPLIT']='json' + ENV['TM_COMPLETIONS'] = @json_raw + fred = TextMate::Complete.new + assert_equal(3, fred.choices.length) + + TextMate::Complete.new.tip! + end + # + def test_tip_should_look_for_the_current_word_and_then_try_the_closest_function_name + ENV.delete 'TM_COMPLETIONS' + assert_nil(ENV['TM_COMPLETIONS']) + ENV.delete 'TM_COMPLETIONS_SPLIT' + assert_nil(ENV['TM_COMPLETIONS_SPLIT']) + + ENV['TM_COMPLETIONS_SPLIT']='json' + ENV['TM_COMPLETIONS'] = @json_raw + fred = TextMate::Complete.new + assert_equal(3, fred.choices.length) + + TextMate::Complete.new.tip! + # + # This test passes if, when run, you see the tooltip for closest function + # Be sure to more your caret around and try a few times + # Showing a menu is a fail + # + # foo( bar( ), '.moo' ) + # ^ Caret here should give the tip for 'foo' + # ^ Caret here should give the tip for 'bar' + # ^ Caret here should give the tip for 'bar' + # ^ Caret here should give the tip for '.moo' + # foo( bar(one,two,foo), '.moo' ) + # foo['bar'] + end + # +end + +end#if