mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
321 lines
8.2 KiB
Plaintext
321 lines
8.2 KiB
Plaintext
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>beforeRunningCommand</key>
|
|
<string>nop</string>
|
|
<key>bundleUUID</key>
|
|
<string>4679484F-6227-11D9-BFB1-000D93589AF6</string>
|
|
<key>command</key>
|
|
<string>#!/usr/bin/env ruby
|
|
require "#{ENV['TM_SUPPORT_PATH']}/lib/escape"
|
|
require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes"
|
|
|
|
class Lexer
|
|
include Enumerable
|
|
def initialize
|
|
@label = nil
|
|
@pattern = nil
|
|
@handler = nil
|
|
@input = nil
|
|
|
|
reset
|
|
|
|
yield self if block_given?
|
|
end
|
|
|
|
def input(&reader)
|
|
if @input.is_a? self.class
|
|
@input.input(&reader)
|
|
else
|
|
class << reader
|
|
alias_method :next, :call
|
|
end
|
|
|
|
@input = reader
|
|
end
|
|
end
|
|
|
|
def add_token(label, pattern, &handler)
|
|
unless @label.nil?
|
|
@input = clone
|
|
end
|
|
|
|
@label = label
|
|
@pattern = /(#{pattern})/
|
|
@handler = handler || lambda { |label, match| [label, match] }
|
|
|
|
reset
|
|
end
|
|
|
|
def next(peek = false)
|
|
while @tokens.empty? and not @finished
|
|
new_input = @input.next
|
|
if new_input.nil? or new_input.is_a? String
|
|
@buffer += new_input unless new_input.nil?
|
|
new_tokens = @buffer.split(@pattern)
|
|
while new_tokens.size > 2 or (new_input.nil? and not new_tokens.empty?)
|
|
@tokens << new_tokens.shift
|
|
@tokens << @handler[@label, new_tokens.shift] unless new_tokens.empty?
|
|
end
|
|
@buffer = new_tokens.join
|
|
@finished = true if new_input.nil?
|
|
else
|
|
separator, new_token = @buffer.split(@pattern)
|
|
new_token = @handler[@label, new_token] unless new_token.nil?
|
|
@tokens.push( *[ separator,
|
|
new_token,
|
|
new_input ].select { |t| not t.nil? and t != "" } )
|
|
reset(:buffer)
|
|
end
|
|
end
|
|
peek ? @tokens.first : @tokens.shift
|
|
end
|
|
|
|
def peek
|
|
self.next(true)
|
|
end
|
|
|
|
def each
|
|
while token = self.next
|
|
yield token
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def reset(*attrs)
|
|
@buffer = String.new if attrs.empty? or attrs.include? :buffer
|
|
@tokens = Array.new if attrs.empty? or attrs.include? :tokens
|
|
@finished = false if attrs.empty? or attrs.include? :finished
|
|
end
|
|
end
|
|
|
|
|
|
class ObjcParser
|
|
|
|
attr_reader :list
|
|
def initialize(args)
|
|
@list = args
|
|
end
|
|
|
|
def get_position
|
|
return nil,nil if @list.empty?
|
|
has_message = true
|
|
|
|
a = @list.pop
|
|
endings = [:close,:post_op,:at_string,:at_selector,:identifier]
|
|
openings = [:open,:return,:control]
|
|
if a.tt == :identifier && !@list.empty? && endings.include?(@list[-1].tt)
|
|
insert_point = find_object_start
|
|
else
|
|
@list << a
|
|
has_message = false unless methodList
|
|
insert_point = find_object_start
|
|
end
|
|
return insert_point, has_message
|
|
end
|
|
|
|
def methodList
|
|
old = Array.new(@list)
|
|
|
|
a = selector_loop(@list)
|
|
if !a.nil? && a.tt == :selector
|
|
if file_contains_selector? a.text
|
|
return true
|
|
else
|
|
internal = Array.new(@list)
|
|
b = a.text
|
|
until internal.empty?
|
|
tmp = selector_loop(internal)
|
|
return true if tmp.nil?
|
|
b = tmp.text + b
|
|
if file_contains_selector? b
|
|
@list = internal
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
else
|
|
end
|
|
@list = old
|
|
return false
|
|
end
|
|
|
|
def file_contains_selector?(methodName)
|
|
fileNames = ["#{ENV['TM_BUNDLE_SUPPORT']}/cocoa.txt.gz"]
|
|
userMethods = "#{ENV['TM_PROJECT_DIRECTORY']}/.methods.TM_Completions.txt.gz"
|
|
|
|
fileNames += [userMethods] if File.exists? userMethods
|
|
candidates = []
|
|
fileNames.each do |fileName|
|
|
zGrepped = %x{zgrep ^#{e_sh methodName }[[:space:]] #{e_sh fileName }}
|
|
candidates += zGrepped.split("\n")
|
|
end
|
|
|
|
return !candidates.empty?
|
|
end
|
|
|
|
def selector_loop(l)
|
|
until l.empty?
|
|
obj = l.pop
|
|
case obj.tt
|
|
when :selector
|
|
return obj
|
|
when :close
|
|
return nil if match_bracket(obj.text,l).nil?
|
|
when :open
|
|
return nil
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
def match_bracket(type,l)
|
|
partner = {"]"=>"[",")"=>"(","}"=>"{"}[type]
|
|
up = 1
|
|
until l.empty?
|
|
obj = l.pop
|
|
case obj.text
|
|
when type
|
|
up +=1
|
|
when partner
|
|
up -=1
|
|
end
|
|
return obj.beg if up == 0
|
|
end
|
|
end
|
|
|
|
def find_object_start
|
|
openings = [:operator,:selector,:open,:return,:control]
|
|
until @list.empty? || openings.include?(@list[-1].tt)
|
|
obj = @list.pop
|
|
case obj.tt
|
|
when :close
|
|
tmp = match_bracket(obj.text, @list)
|
|
b = tmp unless tmp.nil?
|
|
when :star
|
|
b, ate = eat_star(b,obj.beg)
|
|
return b unless ate
|
|
when :nil
|
|
b = nil
|
|
else
|
|
b = obj.beg
|
|
end
|
|
end
|
|
return b
|
|
end
|
|
|
|
def eat_star(prev, curr)
|
|
openings = [:operator,:selector,:open,:return,:control,:star]
|
|
if @list.empty? || openings.include?(@list[-1].tt)
|
|
return curr, true
|
|
else
|
|
return prev, false
|
|
end
|
|
end
|
|
end
|
|
|
|
if __FILE__ == $PROGRAM_NAME
|
|
require "stringio"
|
|
line = ENV['TM_CURRENT_LINE']
|
|
caret_placement =ENV['TM_LINE_INDEX'].to_i - 1
|
|
|
|
up = 0
|
|
pat = /"(?:\\.|[^"\\])*"|\[|\]/
|
|
line.scan(pat).each do |item|
|
|
case item
|
|
when "["
|
|
up+=1
|
|
when "]"
|
|
up -=1
|
|
end
|
|
end
|
|
if caret_placement ==-1
|
|
print "]$0" + e_sn(line[caret_placement+1..-1])
|
|
TextMate.exit_insert_snippet
|
|
end
|
|
|
|
if up != 0
|
|
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
|
|
TextMate.exit_insert_snippet
|
|
end
|
|
|
|
to_parse = StringIO.new(line[0..caret_placement])
|
|
lexer = Lexer.new do |l|
|
|
l.add_token(:return, /\breturn\b/)
|
|
l.add_token(:nil, /\bnil\b/)
|
|
l.add_token(:control, /\b(?:if|while|for|do)(?:\s*)\(/)# /\bif|while|for|do(?:\s*)\(/)
|
|
l.add_token(:at_string, /"(?:\\.|[^"\\])*"/)
|
|
l.add_token(:selector, /\b[A-Za-z_0-9]+:/)
|
|
l.add_token(:identifier, /\b[A-Za-z_0-9]+\b/)
|
|
l.add_token(:bind, /(?:->)|\./)
|
|
l.add_token(:post_op, /\+\+|\-\-/)
|
|
l.add_token(:at, /@/)
|
|
l.add_token(:star, /\*/)
|
|
l.add_token(:close, /\)|\]|\}/)
|
|
l.add_token(:open, /\(|\[|\{/)
|
|
l.add_token(:operator, /[&-+\/=%!:\,\?;<>\|\~\^]/)
|
|
|
|
l.add_token(:terminator, /;\n*|\n+/)
|
|
l.add_token(:whitespace, /\s+/)
|
|
l.add_token(:unknown, /./)
|
|
|
|
l.input { to_parse.gets }
|
|
#l.input {STDIN.read}
|
|
end
|
|
|
|
offset = 0
|
|
tokenList = []
|
|
A = Struct.new(:tt, :text, :beg)
|
|
|
|
lexer.each do |token|
|
|
tokenList << A.new(*(token<<offset)) unless [:whitespace,:terminator].include? token[0]
|
|
offset +=token[1].length
|
|
end
|
|
if tokenList.empty?
|
|
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
|
|
TextMate.exit_insert_snippet
|
|
end
|
|
|
|
par = ObjcParser.new(tokenList)
|
|
b, has_message = par.get_position
|
|
|
|
if !line[caret_placement+1].nil? && line[caret_placement+1].chr == "]"
|
|
if b.nil? || par.list.empty? || par.list[-1].text == "["
|
|
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+2..-1])
|
|
TextMate.exit_insert_snippet
|
|
end
|
|
end
|
|
|
|
if b.nil?
|
|
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
|
|
elsif !has_message && (b < caret_placement )
|
|
print e_sn(line[0..b-1]) unless b == 0
|
|
ins = (/\s/ =~ line[caret_placement].chr ? "$0]" : " $0]")
|
|
print "[" +e_sn(line[b..caret_placement]) + ins +e_sn(line[caret_placement+1..-1])
|
|
elsif b < caret_placement
|
|
print e_sn(line[0..b-1]) unless b == 0
|
|
print "[" +e_sn(line[b..caret_placement]) +"]$0"+e_sn(line[caret_placement+1..-1])
|
|
else
|
|
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
|
|
end
|
|
end
|
|
</string>
|
|
<key>fallbackInput</key>
|
|
<string>line</string>
|
|
<key>input</key>
|
|
<string>selection</string>
|
|
<key>keyEquivalent</key>
|
|
<string>]</string>
|
|
<key>name</key>
|
|
<string>Insert Matching Start Bracket</string>
|
|
<key>output</key>
|
|
<string>insertAsSnippet</string>
|
|
<key>scope</key>
|
|
<string>source.js.objj</string>
|
|
<key>uuid</key>
|
|
<string>CD025B3E-36B9-4E16-A81E-8DB6E8466CD1</string>
|
|
</dict>
|
|
</plist>
|