Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1047 lines (888 sloc) 41.7 KB
# encoding: utf-8
# TextMate Code Completion
# Version: 9
# By: Thomas Aylott / subtleGradient, oblivious@
#
require "#{ENV['TM_SUPPORT_PATH']}/lib/ui"
USE_DIALOG2 = ENV['DIALOG'] =~ /2$/ # DIALOG 2
class TextmateCodeCompletion
$debug_codecompletion = {}
EMPTY_ROW = /(^\s*$)/
class << self
def parse_options(options={})
options[:split ] = ENV['TM_COMPLETION_split' ] if ENV['TM_COMPLETION_split' ]
options[:characters ] = ENV['TM_COMPLETION_characters' ] if ENV['TM_COMPLETION_characters' ]
options[:filter ] = ENV['TM_COMPLETION_filter' ] if ENV['TM_COMPLETION_filter' ]
options[:nil_context] = ENV['TM_COMPLETION_nil_context'] if ENV['TM_COMPLETION_nil_context']
options[:padding ] = ENV['TM_COMPLETION_padding' ] if ENV['TM_COMPLETION_padding' ]
options[:select ] = ENV['TM_COMPLETION_select' ] if ENV['TM_COMPLETION_select' ]
options[:sort ] = ENV['TM_COMPLETION_sort' ] if ENV['TM_COMPLETION_sort' ]
options[:unique ] = ENV['TM_COMPLETION_unique' ] if ENV['TM_COMPLETION_unique' ]
options[:scope ] = ENV['TM_COMPLETION_scope' ].to_sym if ENV['TM_COMPLETION_scope' ]
options[:sort ] = true if options[:sort ] == 'true'
options[:sort ] = false if options[:sort ] == 'false'
options[:unique ] = true if options[:unique ] == 'true'
options[:unique ] = false if options[:unique ] == 'false'
return options
end
def go!(options={})
options = TextmateCodeCompletion.parse_options(options)
if USE_DIALOG2
if options[:split] == 'plist'
choices = TextmateCompletionsPlist.new(ENV['TM_COMPLETIONS']).to_ary
else
choices = TextmateCompletionsText.new(ENV['TM_COMPLETIONS'],{:split=>','}.merge(options)).to_ary
end
return print(TextmateCodeCompletion.new( choices, STDIN.read, options ).to_snippet)
end
if options[:split] == 'plist'
choices = TextmateCompletionsPlist.new(ENV['TM_COMPLETIONS']).to_ary
else
choices = TextmateCompletionsText.new(ENV['TM_COMPLETIONS'],{:split=>','}.merge(options)).to_ary
end
print TextmateCodeCompletion.new( choices, STDIN.read, options ).to_snippet
end
# DEPRECATED
def plist(preference='Completions')
choices = TextmateCompletionsPlist.new( "#{ENV['TM_BUNDLE_PATH']}/Preferences/#{preference}#{'.tmPreferences' if preference !~ /\./}" )
print TextmateCodeCompletion.new(choices,STDIN.read).to_snippet
end
def txt(file='Completions.txt')
choices = TextmateCompletionsText.new( "#{ENV['TM_BUNDLE_PATH']}/Support/#{file}" )
print TextmateCodeCompletion.new(choices,STDIN.read).to_snippet
end
alias :simple :plist
end
def initialize(choices=nil,line=nil,options={})
options = TextmateCodeCompletion.parse_options(options)
@options = {}
@options[:characters] = /\w+$/
@options.merge!(options)
@options.merge!(TextmateCompletionsParser::PARSERS[options[:scope]] || {}) if options[:scope]
@debug = true
@has_selection = ENV['TM_SELECTED_TEXT'] == line
@line = line
set_line!
cancel() and return if choices.is_a? String
cancel() and return unless choices and choices.to_ary and !choices.to_ary.empty?
@choices = choices.to_ary
@choice = false
filter_choices!
choose() unless @choice
# rescue
# cancel()
end
def choice
@choice
end
def index
@choice_i
end
def to_snippet
completion()
end
private
def cancel
@choice = ''
@cancel = true
end
def set_line!
@raw_line = ENV['TM_CURRENT_LINE']
caret_placement()
@line_before = @raw_line[0..caret_placement]
@line_before = '' if caret_placement == -1
get_choice_partial!
@selection = @line if @has_selection
@line_after = @raw_line[caret_placement+1..@raw_line.length+1]
@line_before.gsub!(/#{Regexp.escape @choice_partial}$/,'')
@line_after.gsub!(/^#{Regexp.escape @selection}/,'') if @selection
cancel() if @options[:nil_context]==false and (!@line_before or @line_before == '')
if @debug
$debug_codecompletion["caret_placement"] = caret_placement+2
$debug_codecompletion["line_before" ] = @line_before
$debug_codecompletion["choice_partial" ] = @choice_partial
$debug_codecompletion["selection" ] = @selection
$debug_codecompletion["line_after" ] = @line_after
end
end
def caret_placement
return @caret_placement if @caret_placement
caret_placement = 0
caret_placement = ENV['TM_COLUMN_NUMBER'].to_i - 2
caret_placement = ENV['TM_INPUT_START_COLUMN'].to_i - 2 if @has_selection
# caret_placement = 0 if caret_placement < 0
# Fix those dang tabs being longer than 1 character
if @raw_line =~ /\t/
tabs_to_spaces = ''; ENV['TM_TAB_SIZE'].to_i.times {tabs_to_spaces<<' '}
number_of_tabs_before_cursor = 0
unless caret_placement <= 0
number_of_tabs_before_cursor = @raw_line.gsub(' ','X').gsub("\t",tabs_to_spaces)[0..caret_placement].gsub(/[^ ]/,'').length / ENV['TM_TAB_SIZE'].to_i
end
add_to_caret_placement = 0
add_to_caret_placement -= number_of_tabs_before_cursor * ENV['TM_TAB_SIZE'].to_i
add_to_caret_placement += number_of_tabs_before_cursor
caret_placement += add_to_caret_placement
end
@caret_placement = caret_placement
end
def get_choice_partial!
return nil unless @line_before
@choice_partial = @line_before.scan(@options[:characters]).to_s || ''
if @options[:context]
match = @line_before.match(@options[:context])
@strip_partial = match[1].to_s if match
cancel() unless @strip_partial
$debug_codecompletion["match"] = match
end
$debug_codecompletion["strip"] = @options[:context]
$debug_codecompletion["strip_partial"] = @strip_partial
end
def filter_choices!
cancel() and return if @choices.length == @choices.grep(EMPTY_ROW).length
# Convert the empties to seperators
# Unless they're the first or last choice
while @choices.first =~ EMPTY_ROW
@choices.delete_at(0)
end
while @choices.last =~ EMPTY_ROW
@choices.delete_at(@choices.length-1)
end
@choices.each_with_index do |e, i|
@choices[i] = '--' if e =~ EMPTY_ROW
end
@choices.each {|e| e.gsub!(@strip_partial,'\1') } if @options[:context] and @strip_partial
@choices = @choices - @choices.grep(@options[:context]).uniq if @strip_partial
@choices = @choices.grep(/^#{Regexp.escape @choice_partial}/).uniq if @choice_partial #and @choice_partial != ''
@choices.sort! if @options[:sort]
end
def choose
cancel() and return if @cancel
cancel() and return unless @choices and @choices!=[]
if @choices.length == 1
val = 0
else
val = TextMate::UI.menu(@choices)
end
cancel() and return unless val
@choice_i = val
@choice = @choices[val]
end
def completion
$debug_codecompletion["choice"] = @choice
$debug_codecompletion["cancel"] = @cancel
$debug_codecompletion["choices"] = @choices
completion = ''
completion << snip(@line_before) unless @has_selection
if @cancel
completion << snip(@choice_partial)
completion << "${0:#{snip(@selection)}}"
else
if @choice
completion << @options[:padding] unless @line_before.match(/#{Regexp.escape @options[:padding]}$/) or @choice.match(/^#{Regexp.escape @options[:padding]}/) if @options[:padding]
completion << snippetize(@choice) unless @cancel
else
completion << snip(@selection) if @selection
end
end
completion << snip(@line_after) unless @has_selection if @line_after
completion
end
def snippetize(text)
text.gsub!(/^#{Regexp.escape @choice_partial}/,'') if @has_selection # Trimoff the choice_partial if we have a selection
snippet = ''
# snippet << '${101:'
snippet << snippetize_quotes(snippetize_methods(text))
# snippet << '}$100'
snippet << '$0'
snippet
end
def snippetize_methods(text)
text = text.to_s
@place = 0
text.gsub!(/(\$)/) { |g| snip($1) }
text.gsub!(/([\(,])([^\),]*)/) do |g|
thing = $2
"#{$1}${#{@place += 1}:#{snippetize_quotes(thing,true)}}"
end
text
end
def snippetize_quotes(text,escape=false)
text = text.to_s
text = snip(text,escape) if escape
text.gsub!(/(["'])(?!\$\{)(.*?)(\1)/) do |g|
thing = $2
thing1 = $3
"#{$1}${#{@place += 1}:#{snippetize_quotes(thing,!escape)}}#{thing1}"
end
text
end
def snip(text,escape_bracket=false) #make snippet proof
chars = /(\$|\`)/
chars = /(\$|\`|\})/ if escape_bracket
text.to_s.gsub(chars,'\\\\\\1')
end
end
class TextmateCompletionsPlist
attr_accessor :raw
attr_accessor :scope
attr_accessor :format
attr_accessor :choices
attr_accessor :parsed
def initialize(path=nil,options={})
require "#{ENV['TM_SUPPORT_PATH']}/lib/osx/plist"
if path.match(/\{/)
self.raw = path.to_s
@fullsize = false
else
return false unless File.exist?(path)
self.raw = File.read(path)
@fullsize = true
end
@parsed = OSX::PropertyList.load(self.raw)
# p parsed unless parsed.is_a? Array
p @parsed if @parsed.is_a? Array
@parsed = @parsed.first if @parsed.is_a? Array
self.scope = @parsed['scope'].split(/, ?/) if @fullsize and @parsed['scope']
# This is for parsing tmPreference file completions directly from the bundle. DEPRECATED
self.choices = (@fullsize ? @parsed['settings'] : @parsed)['completions']
# This is for parsing the new format of plist that is used in Dialog2
self.choices = @parsed['suggestions'] if @parsed['suggestions']
self.format = self.choices[0].is_a?(Array) ? :array : :hash
end
def to_ary
return self.choices if self.format == :array
return self.choices.map{|c|c['title'] || c['match'] || c['display']}
end
def to_hash
# return self.choices if self.choices.is_a? Hash
self.choices = self.choices.map do |choice|
next unless choice and choice.respond_to? :to_str or choice.respond_to? :keys
hashed_choice ||= choice if choice.respond_to? :keys
if choice.respond_to? :to_str and choice.to_str =~ /^--/
hashed_choice ||= { 'separator' => choice.to_str.gsub(/^-+\s*|\s*-+$/,'') }
end
# Add all characters in every choice to the extra_chars
# @extra_chars ||= []
# @extra_chars += choice.to_str.scan(/[^a-z]/i)
# @extra_chars.uniq!
hashed_choice ||= { 'display' => choice.to_str }
hashed_choice
end
return {'completions' => self.choices, 'extra_chars' => @extra_chars, 'images' => @images}
end
end
class TextmateCompletionsText
attr :raw, true
attr :scope, true
attr :choices, true
def initialize(path,options={})
return false unless path
options[:split] ||= "\n"
if path.match(options[:split])
self.raw = path.to_s
else
return false unless File.exist?(path)
self.raw = File.new(path).read
end
self.scope = nil
self.choices = self.raw.split(options[:split])
self.choices = self.choices - self.choices.grep(options[:filter]) if options[:filter]
end
def to_ary
self.choices
end
end
class TextmateCompletionsParser
PARSERS = {}
def initialize(filepath=nil, options={})
unless options[:debug] and filepath.is_a? String
path = filepath || ENV['TM_FILEPATH']
return false unless path and File.exist?(path)
return false if File.directory?(path)
@raw = IO.read(path)
else
@raw = filepath
end
@options = {}
@options[:split] = "\n"
@options.merge!(options)
@options.merge!(PARSERS[options[:scope]]) if options[:scope]
@raw = @raw.split(@options[:split])
@filter = arrayify @options[:filter]
@selects = arrayify @options[:select]
collect_selects!
render!()
@rendered.sort! if @options[:sort]
end
def to_ary
@rendered
end
private
def render!
@filter.each do |filter|
@raw -= @raw.grep(filter)
end
@rendered = @raw
@rendered = @raw.grep(@select)
@rendered.each do |r|
@selects.each do |select|
r.gsub!(select,'\1')
end
end
@rendered -= @rendered.grep(/^\s*$/)
end
def collect_selects!
@select = Regexp.new(@selects.collect do |select|
select.to_s << '|'
end.to_s.gsub(/\|$/,''))
end
end
def arrayify(anything)
anything.is_a?(Array) ? anything : [anything]
end
TextmateCompletionsParser::PARSERS[:css] = {
:select =>[%r/^([#\.][a-z][-_\w\d]*)\b.*/i, #Ids and Classes
%r/.*(?:id="(.*?)"|id='(.*?)').*/ #IDs in HTML
],
:filter =>[%r/^#([0-9a-f]{6}|[0-9a-f]{3})/,
%r/^..*#.*$/
],
:sort => true,
:split => /[,;\n\s{}]|(\/\*|\*\/)/,
:characters => /[-_:#\.\w]+$|\.$/
}
TextmateCompletionsParser::PARSERS[:css_values] = {
:select =>[%r/(url\(.*?\))/,#URLs
%r/(#([0-9a-f]{6}|[0-9a-f]{3}))/i, #HEX colors
],
:sort => true,
:characters => /[#0-9a-z]+$/,
:split => /[ :;]/
}
TextmateCompletionsParser::PARSERS[:html_attributes] = {
:sort => true,
:characters => /(?:<\w+\b ?)?(\b\w*)$/,
:context => /(<[^\s>]+ ?)([^>]*(<\B.*?\B>)?)+$/,
:nil_context => false,
:padding => ' ',
}
TextmateCompletionsParser::PARSERS[:ruby] = {
:select =>[%r/^[ \t]*(?:class)\s*(.*?)\s*(<.*?)?\s*(#.*)?$/,
%r/^[ \t]*(?:def)\s*(.*?(\([^\)]*\))?)\s*(<.*?)?\s*(#.*)?$/,
%r/^[ \t]*(?:attr_.*?)\s*(.*?(\([^\)]*\))?)\s*(<.*?)?\s*(#.*)?$/
],
:filter => [/test_/,'< Test::Unit::TestCase']
}
# ================= #
# = TESTS = #
# ================= #
if $0 == __FILE__
require 'test/unit'
require "stringio"
# STDIN = StringIO.new
puts "\nJust keep hittin' 1\n\n"
def print(text)
return text
end
# =begin
class TextmateCodeCompletionTest < Test::Unit::TestCase
def test_blank
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "test$0", TextmateCodeCompletion.new(['test']).to_snippet
end
def test_basic
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "basic$0", TextmateCodeCompletion.new(['basic'], %{basic}).to_snippet
end
def test_a
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "a", "TM_COLUMN_NUMBER" => "2", "TM_INPUT_START_COLUMN" => "1"})
tcc = TextmateCodeCompletion.new(['aaa'], %{a})
assert_equal "aaa$0", tcc.to_snippet , $debug_codecompletion.inspect
assert_equal 0, tcc.index , $debug_codecompletion.inspect
assert_equal 'aaa', tcc.choice , $debug_codecompletion.inspect
end
def test_choices
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\t", "TM_COLUMN_NUMBER" => "3", "TM_BUNDLE_PATH" => "#{ENV['TM_BUNDLE_PATH']}../CSS.tmbundle", "TM_INPUT_START_COLUMN" => "1"})
TextmateCodeCompletion.new([' ',' ','real1',' ','real2',' '], "\t").to_snippet
assert_equal '--', $debug_codecompletion['choices'][1], $debug_codecompletion.inspect
assert_equal 3, $debug_codecompletion['choices'].length, $debug_codecompletion.inspect
assert_equal "\t${0:}", TextmateCodeCompletion.new('', "\t").to_snippet, $debug_codecompletion.inspect
assert_equal "\t${0:}", TextmateCodeCompletion.new(nil, "\t").to_snippet, $debug_codecompletion.inspect
assert_equal "\t${0:}", TextmateCodeCompletion.new([nil], "\t").to_snippet, $debug_codecompletion.inspect
assert_equal "\t${0:}", TextmateCodeCompletion.new([''], "\t").to_snippet, $debug_codecompletion.inspect
end
def test_in_snippet
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => %{${1:snippet}}, "TM_COLUMN_NUMBER" => "12", "TM_INPUT_START_COLUMN" => "1"})
assert_equal '\${1:snippet${0:}}', TextmateCodeCompletion.new(['nomatch'], %{${1:snippet}}).to_snippet
end
def test_in_snippet_match
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => %{${1:snippet}}, "TM_COLUMN_NUMBER" => "12", "TM_INPUT_START_COLUMN" => "1"})
assert_equal '\${1:snippet$0}', TextmateCodeCompletion.new(['snippet'], %{${1:snippet}}).to_snippet
end
def test_choice_partial_selection
set_tm_vars({"TM_SELECTED_TEXT" => "selection", "TM_CURRENT_LINE" => "choice_partialselection", "TM_COLUMN_NUMBER" => "24", "TM_INPUT_START_COLUMN" => "15"})
assert_equal "choice_partial${0:selection}", TextmateCodeCompletion.new(['test'], %{selection}).to_snippet, $debug_codecompletion.inspect
end
def test_choice_partial_selection_match
set_tm_vars({"TM_SELECTED_TEXT" => "selection", "TM_CURRENT_LINE" => "choice_partialselection", "TM_COLUMN_NUMBER" => "24", "TM_INPUT_START_COLUMN" => "15"})
assert_equal "_match$0", TextmateCodeCompletion.new(['choice_partial_match'], %{selection}).to_snippet, $debug_codecompletion.inspect
end
def test_selection_no_line
set_tm_vars({"TM_SELECTED_TEXT" => "basic_selection", "TM_CURRENT_LINE" => "basic_selection", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "test_selection$0", TextmateCodeCompletion.new(['test_selection'], %{basic_selection}).to_snippet, $debug_codecompletion.inspect
end
def test_snippetize
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "String", "TM_COLUMN_NUMBER" => "7", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "String.method(${1:})$0", TextmateCodeCompletion.new(['String.method()'], %{String}).to_snippet, $debug_codecompletion.inspect
end
def test_snippetize_methods
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "String", "TM_COLUMN_NUMBER" => "7", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{String.method(${1:"${2:one}"},${3:two})(${4:})$0}, TextmateCodeCompletion.new(['String.method("one",two)()'], %{String}).to_snippet, $debug_codecompletion.inspect
end
def test_snippetize_methods_with_stuff
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "change_column", "TM_COLUMN_NUMBER" => "14", "TM_INPUT_START_COLUMN" => "1"})
assert_equal 'change_column(${1:table_name},${2: column_name},${3: type},${4: options = {\}})$0', TextmateCodeCompletion.new([%{change_column(table_name, column_name, type, options = {})}],'').to_snippet, $debug_codecompletion.inspect
end
def test_snippetize_bracket_escaping
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "{before} {inside} {after}", "TM_COLUMN_NUMBER" => "14","TM_INPUT_START_COLUMN" => "1"})
assert_equal %{{before} {ins${0:}ide} {after}}, TextmateCodeCompletion.new(['test'], %{{before} {inside} {after}}).to_snippet, $debug_codecompletion.inspect
end
def test_snippetize_quotes
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "String", "TM_COLUMN_NUMBER" => "7", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{String="${1:some '${2:thing}'}"$0}, TextmateCodeCompletion.new([%{String="some 'thing'"}], %{String}).to_snippet, $debug_codecompletion.inspect
end
def test_spaces
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => " padding-top: 1px;", "TM_COLUMN_NUMBER" => "10", "TM_INPUT_START_COLUMN" => "1"})
assert_equal " padding_is_awesome$0-top: 1px;", TextmateCodeCompletion.new(['padding_is_awesome'], %{ padding-top: 1px;}).to_snippet, $debug_codecompletion.inspect
end
def test_tabs
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\t\t\t\tpadding-top: 1px;", "TM_COLUMN_NUMBER" => "16", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "\t\t\t\tpadding_is_awesome$0-top: 1px;", TextmateCodeCompletion.new(['padding_is_awesome'], "\t\t\t\tpadding-top: 1px;").to_snippet, $debug_codecompletion.inspect
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\tpadding-top: 1px;", "TM_COLUMN_NUMBER" => "10", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "\tpadding_is_awesome$0-top: 1px;", TextmateCodeCompletion.new(['padding_is_awesome'], %{ padding-top: 1px;}).to_snippet, $debug_codecompletion.inspect
# Make sure it's not also recalculating the tabs after the cursor position
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\t\t\t\tpadding\t\t\t\t-top: 1px;", "TM_COLUMN_NUMBER" => "16", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "\t\t\t\tpadding_is_awesome$0\t\t\t\t-top: 1px;", TextmateCodeCompletion.new(['padding_is_awesome'], "\t\t\t\tpadding\t\t\t\t-top: 1px;").to_snippet, $debug_codecompletion.inspect
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\tpadding\t\t\t\t-top: 1px;", "TM_COLUMN_NUMBER" => "10", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "\tpadding_is_awesome$0\t\t\t\t-top: 1px;", TextmateCodeCompletion.new(['padding_is_awesome'], "\tpadding\t\t\t\t-top: 1px;").to_snippet, $debug_codecompletion.inspect
end
def test_extra_word_characters
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => ".", "TM_COLUMN_NUMBER" => "2", "TM_INPUT_START_COLUMN" => "1"})
tcc = TextmateCodeCompletion.new(['.aaa'], %{.}, {:characters => /[-_:#\.\w]$/})
assert_equal ".aaa$0", tcc.to_snippet , $debug_codecompletion.inspect
assert_equal 0, tcc.index , $debug_codecompletion.inspect
assert_equal '.aaa', tcc.choice , $debug_codecompletion.inspect
end
def test_sort
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
assert_equal "basic$0", TextmateCodeCompletion.new(
%w[basic2 basic3 basic basic1],
%{basic},
{:sort => true}
).to_snippet
end
def test_html
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<div><p><a><img ></a></p></div>", "TM_COLUMN_NUMBER" => "17", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<div><p><a><img one="${1:}"$0></a></p></div>}, TextmateCodeCompletion.new(
['<img one=""','<img two=""','<div three=""','<div four=""'],
%{<div><p><a><img ></a></p></div>},
{:scope => :html_attributes}
).to_snippet, $debug_codecompletion.inspect
end
def test_context_sensitive_filter
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => %{<div><p><a><img class="Value" t></a></p></div>}, "TM_COLUMN_NUMBER" => "32", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<div><p><a><img class="Value" talc="${1:}"$0></a></p></div>}, TextmateCodeCompletion.new(
['class=""','turtles=""','talc=""','id=""','zero=""','nada=""','<img one=""','<img two=""','<div three=""','<div four=""'],
%{<div><p><a><img class="Value" t></a></p></div>},
{:scope => :html_attributes}
).to_snippet, $debug_codecompletion.inspect
end
def test_html_with_other_attributes
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<div><p><a><img class=\"Value\" ></a></p></div>", "TM_COLUMN_NUMBER" => "31", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<div><p><a><img class="Value" class="${1:}"$0></a></p></div>}, TextmateCodeCompletion.new(
['<img id=""','<div id=""','<div class=""','<img class=""',],
%{<div><p><a><img class="Value" ></a></p></div>},
{:scope => :html_attributes}
).to_snippet, $debug_codecompletion.inspect
end
def test_html_with_embedded_source
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => %{<div><p><a><img class="<%= something %>" ></a></p></div>}, "TM_COLUMN_NUMBER" => "42", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<div><p><a><img class="<%= something %>" class="${1:}"$0></a></p></div>}, TextmateCodeCompletion.new(
['<img id=""','<div id=""','<div class=""','<img class=""',],
%{<div><p><a><img class="<%= something %>" ></a></p></div>},
{:scope => :html_attributes}
).to_snippet, $debug_codecompletion.inspect
end
def test_padding
# Insert the padding character if it's not there already
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<img.>", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<img. test$0>}, TextmateCodeCompletion.new(['test'], %{<img.>}, :padding => ' ').to_snippet, $debug_codecompletion.inspect
end
def test_no_padding
# Don't insert the padding text if it's already there
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<img >", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<img test$0>}, TextmateCodeCompletion.new(['test'], %{<img >}, :scope => :html_attributes).to_snippet, $debug_codecompletion.inspect
end
def test_nil_line_before
# Do insert if there's no line_before text
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => ">", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{test$0>}, TextmateCodeCompletion.new(['test'], %{>}).to_snippet, $debug_codecompletion.inspect
# Don't insert anything if there's no line_before text and :nil_context===false
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => ">", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{${0:}>}, TextmateCodeCompletion.new(['test'], %{>}, :scope => :html_attributes).to_snippet, $debug_codecompletion.inspect
# Don't insert anything if the line_before text doesn't match the :context and :nil_context===false
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => " <>", "TM_COLUMN_NUMBER" => "3", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{ ${0:}<>}, TextmateCodeCompletion.new(['test'], %{ <>}, :scope => :html_attributes).to_snippet, $debug_codecompletion.inspect
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<>", "TM_COLUMN_NUMBER" => "3", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<>${0:}}, TextmateCodeCompletion.new(['test'], %{<>}, :scope => :html_attributes).to_snippet, $debug_codecompletion.inspect
end
def test_caret_placement
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "\t\t</div>", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{test$0 </div>}, TextmateCodeCompletion.new(['test'], %{ </div>}).to_snippet, $debug_codecompletion.inspect
end
def test_html_with_no_attributes
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "<div>", "TM_COLUMN_NUMBER" => "5", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %{<div class="${1:}"$0>}, TextmateCodeCompletion.new(['<div class=""'], %{<div>}, :scope => :html_attributes).to_snippet, $debug_codecompletion.inspect
end
def test_go_basic
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
ENV['TM_COMPLETIONS'] = 'basic,basic1'
text = TextmateCodeCompletion.go!
assert_equal "basic$0", text
end
def test_go_vars
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
ENV['TM_COMPLETIONS'] = 'basicbasic1'
ENV['TM_COMPLETION_split'] = ''
text = TextmateCodeCompletion.go!
assert_equal "basic$0", text
end
def test_shouldnt_have_to_escape_dollars
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "", "TM_COLUMN_NUMBER" => "1", "TM_INPUT_START_COLUMN" => "1"})
assert_equal %q{\$\$(${1:'${2:selectors:mixed}'})\$\$$0}, TextmateCodeCompletion.new(["$$('selectors:mixed')$$"]).to_snippet
assert_equal %q{\$apple\$$0}, TextmateCodeCompletion.new(["$apple$"]).to_snippet
end
def test_plist_split
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
ENV['TM_COMPLETIONS'] = %{{ suggestions =(
{ title = "basic"; },
{ title = "basic1"; },
{ title = "basic2"; }
);}}
ENV['TM_COMPLETION_split'] = 'plist'
text = TextmateCodeCompletion.go!
assert_equal "basic$0", text
end
def test_plist_snippet
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "basic", "TM_COLUMN_NUMBER" => "6", "TM_INPUT_START_COLUMN" => "1"})
ENV['TM_COMPLETIONS'] = %{{ suggestions =( { title = "basic 'All this text should be removed'"; snippet = "basic"; } );}}
ENV['TM_COMPLETION_split'] = 'plist'
text = TextmateCodeCompletion.go!
# assert_equal "basic$0", text
# Haven't implemented the code to make this pass yet :-!
end
end
# =begin
# =end
class TextmateCompletionsPlistTest < Test::Unit::TestCase
def test_plist_file
`echo "{settings={ completions = ( 'fibbity', 'flabbity', 'floo' ); };}" >/tmp/test_plist_file.plist`
completions = TextmateCompletionsPlist.new("/tmp/test_plist_file.plist")
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length > 0
end
def test_plist_string_format1
completions = TextmateCompletionsPlist.new("{ completions = ( 'fibbity', 'flabbity', 'floo' ); }")
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_string_format1_dialog2
completions = TextmateCompletionsPlist.new %q`
{
completions = (
{
display = moo;
image = Drag;
insert = "(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})";
"tool_tip" = "(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" = "(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" = "(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here.";
}
);
images = {
Command = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Commands.png";
Drag = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Drag Commands.png";
Language = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Languages.png";
Macro = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Macros.png";
Preference = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Preferences.png";
Snippet = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Snippets.png";
Template = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Template Files.png";
Templates = "/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Templates.png";
};
}
`
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert_kind_of Hash, completions.to_hash
assert_equal [
{'image' => 'Drag', 'display' => 'moo', 'insert' => '(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})', 'tool_tip' => "(one, two, four[, five])\n This method does something or other maybe.\n Insert longer description of it here."},
{'image' => 'Macro', 'display' => 'foo', 'insert' => '(${1:one}, "${2:one}", ${3:three}${4:, ${5:five}, ${6:six}})', 'tool_tip' => "(one, two)\n This method does something or other maybe.\n Insert longer description of it here."},
{'image' => 'Command', 'display' => 'bar', 'insert' => '(${1:one}, ${2:one}, "${3:three}"${4:, "${5:five}", ${6:six}})', 'tool_tip' => "(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here."},
], completions.to_hash['completions']
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_string_format1_dialog2_xml
completions = TextmateCompletionsPlist.new %q{
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>completions</key>
<array>
<dict>
<key>display</key>
<string>moo</string>
<key>image</key>
<string>Drag</string>
<key>insert</key>
<string>(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two, four[, five])
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
<dict>
<key>display</key>
<string>foo</string>
<key>image</key>
<string>Macro</string>
<key>insert</key>
<string>(${1:one}, "${2:one}", ${3:three}${4:, ${5:five}, ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two)
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
<dict>
<key>display</key>
<string>bar</string>
<key>image</key>
<string>Command</string>
<key>insert</key>
<string>(${1:one}, ${2:one}, "${3:three}"${4:, "${5:five}", ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two[, three])
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
</array>
<key>images</key>
<dict>
<key>Command</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Commands.png</string>
<key>Drag</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Drag Commands.png</string>
<key>Language</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Languages.png</string>
<key>Macro</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Macros.png</string>
<key>Preference</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Preferences.png</string>
<key>Snippet</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Snippets.png</string>
<key>Template</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Template Files.png</string>
<key>Templates</key>
<string>/Applications/TextMate.app/Contents/Resources/Bundle Item Icons/Templates.png</string>
</dict>
</dict>
</plist>
}
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_string_format1_dialog2_only_completions
plist = <<-PLIST
{ completions = (
{ display = 'moo';
image = 'Drag';
insert = '(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})';
tool_tip = '(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 = '(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 = '(one, two[, three])\n This method does something or other maybe.\n Insert longer description of it here.';
},
);
}
PLIST
completions = TextmateCompletionsPlist.new plist
assert_equal OSX::PropertyList.load(plist), completions.parsed
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_string_format1_dialog2_only_completions_xml
plist = <<-'XML'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>completions</key>
<array>
<dict>
<key>display</key>
<string>moo</string>
<key>image</key>
<string>Drag</string>
<key>insert</key>
<string>(${1:one}, ${2:one}, ${3:three}${4:, ${5:five}, ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two, four[, five])
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
<dict>
<key>display</key>
<string>foo</string>
<key>image</key>
<string>Macro</string>
<key>insert</key>
<string>(${1:one}, &quot;${2:one}&quot;, ${3:three}${4:, ${5:five}, ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two)
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
<dict>
<key>display</key>
<string>bar</string>
<key>image</key>
<string>Command</string>
<key>insert</key>
<string>(${1:one}, ${2:one}, &quot;${3:three}&quot;${4:, &quot;${5:five}&quot;, ${6:six}})</string>
<key>tool_tip</key>
<string>(one, two[, three])
This method does something or other maybe.
Insert longer description of it here.</string>
</dict>
</array>
</dict>
</plist>
XML
completions = TextmateCompletionsPlist.new plist
assert_equal OSX::PropertyList.load(plist), completions.parsed
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_string_format2
completions = TextmateCompletionsPlist.new %{{ suggestions =( { title = "basic"; }, { title = "basic1"; }, { title = "basic2"; } );}}
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
def test_plist_both_formats
completions = TextmateCompletionsPlist.new %{{
completions = ( 'fibbity', 'flabbity', 'floo' );
suggestions = ( { title = "basic"; }, { title = "basic1"; }, { title = "basic2"; } );
}}
assert ['basic', 'basic1', 'basic2'] == completions.to_ary
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3, completions.choices
end
end
class TextmateCompletionsTextTest < Test::Unit::TestCase
def test_txt
completions = TextmateCompletionsText.new("README.txt")
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length > 0
end
def test_txt_completions
completion = TextmateCodeCompletion.new(TextmateCompletionsText.new("README.txt"),'').to_snippet
assert_not_nil completion
end
def test_txt_completions_dict
completions = TextmateCompletionsText.new(`cat /usr/share/dict/web2|grep ^fr`).to_ary
completion = TextmateCodeCompletion.new(completions,'fra').to_snippet
assert_not_nil completion
end
def test_strings
them = %{one\ntwo\nthree}
completions = TextmateCompletionsText.new(them)
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3
them = %{one,two,three}
completions = TextmateCompletionsText.new(them, :split => ',')
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 3
them = %{one,two,three}
completions = TextmateCompletionsText.new(them, :split => ',', :filter => /three/)
assert_not_nil completions
assert_kind_of Array, completions.to_ary
assert completions.to_ary.length == 2
end
end
class TextmateCompletionsParserTest < Test::Unit::TestCase
def test_parser_dir
fred = TextmateCompletionsParser.new(File.dirname(__FILE__), :select => /^[ \t]*(?:class|def)\s*(.*?)\s*(<.*?)?\s*(#.*)?$/).to_ary
assert_nil fred
end
def test_parser_symbol
fred = TextmateCompletionsParser.new(nil, :scope => :ruby).to_ary
assert_kind_of Array, fred.to_ary
assert fred.to_ary.length > 0, fred.inspect
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "a", "TM_COLUMN_NUMBER" => "2", "TM_INPUT_START_COLUMN" => "1"})
assert_not_nil TextmateCodeCompletion.new(fred).to_snippet
end
def test_parser_array
fred = TextmateCompletionsParser.new(nil,
:split => "\n",
:select => [%r/^[ \t]*(?:class)\s*(.*?)\s*(<.*?)?\s*(#.*)?$/,
%r/^[ \t]*(?:def)\s*(.*?(\([^\)]*\))?)\s*(<.*?)?\s*(#.*)?$/,
%r/^[ \t]*(?:attr_.*?)\s*(.*?(\([^\)]*\))?)\s*(<.*?)?\s*(#.*)?$/],
:filter => /_string/).to_ary
assert_kind_of Array, fred.to_ary, $debug_codecompletion.inspect
assert fred.to_ary.length > 0, $debug_codecompletion.inspect
set_tm_vars({"TM_SELECTED_TEXT" => nil, "TM_CURRENT_LINE" => "a", "TM_COLUMN_NUMBER" => "2", "TM_INPUT_START_COLUMN" => "1"})
assert_not_nil TextmateCodeCompletion.new(fred).to_snippet
end
def test_parser_array_with_empty_rows
fred = TextmateCompletionsParser.new('codecompletion.rb', :scope => :ruby).to_ary
assert fred.to_ary.grep(/^$/).length == 0, fred.to_ary.grep(/^$/).inspect
end
end
def set_tm_vars(env)
ENV['TM_BUNDLE_PATH'] = env['TM_BUNDLE_PATH'] if env['TM_BUNDLE_PATH']
# ENV['TM_SUPPORT_PATH'] = env['TM_SUPPORT_PATH']
ENV['TM_COLUMN_NUMBER'] = env['TM_COLUMN_NUMBER']
ENV['TM_CURRENT_LINE'] = env['TM_CURRENT_LINE']
ENV['TM_INPUT_START_COLUMN'] = env['TM_INPUT_START_COLUMN']
ENV['TM_SELECTED_TEXT'] = env['TM_SELECTED_TEXT']
end
end # TESTS
=begin
=end
Something went wrong with that request. Please try again.