├── .gitignore ├── Commands ├── Cocoa Context.tmCommand ├── Cocoa Function Completion.tmCommand ├── Cocoa Method Signature Completion.tmCommand ├── Completion: Inside @selector.tmCommand ├── Delete Outer Method.tmCommand ├── Documentation for Selector.tmCommand ├── Format Method Signature.plist ├── Generate Index.tmCommand ├── Help.tmCommand ├── Insert Call to Super.plist ├── Insert Matching Start Bracket.tmCommand ├── Insert NSLog() for current method.tmCommand ├── Lookup Cocoa Class.plist ├── Paste Implementation : Interface.tmCommand ├── Paste selector.tmCommand ├── Reflow Method Call.tmCommand ├── Toggle Import : Include Keyword.tmCommand └── Wrap in [[alloc] init] (alloc).plist ├── Preferences ├── Cocoa completions.plist ├── Folding.tmPreferences ├── Highlight Pairs: Protocol Specifiers.tmPreferences ├── Symbol List.plist └── Typing Pairs: Protocol Specifier.tmPreferences ├── README.mdown ├── Snippets ├── #import "" (imp).plist ├── #import <> (Imp).plist ├── 020 Class (objc).plist ├── 030 NSArray (array).plist ├── 040 NSDictionary (dict).plist ├── 050 Method (m).plist ├── 060 SubMethod (sm).plist ├── @selector.tmSnippet ├── Category (cat).plist ├── Category Implementation.tmSnippet ├── Category Interface Only (cati).plist ├── Class Implementation.tmSnippet ├── Class Interface Only (classi).plist ├── Class Method (M).plist ├── Class Method Interface (M).plist ├── CoreData Accessors Implementation.plist ├── Delegate Responds to Selector.plist ├── Detach New NSThread.tmSnippet ├── For Loop.tmSnippet ├── IBOutlet (ibo).plist ├── Initialize Implementation (I).plist ├── Key:value binding (bind).plist ├── LoD array (arracc).plist ├── LoD array interface (arracc).plist ├── Lock Focus.plist ├── Method Interface (m).plist ├── NSAutoreleasePool (pool).plist ├── NSBezierPath (bez).plist ├── NSLog (log) 2.plist ├── NSLog(.., _cmd) (log).plist ├── NSRunAlertPanel (alert).plist ├── NSString stringWithFormat (format).plist ├── Object Accessors Interface (objacc).plist ├── Property.tmSnippet ├── Protocol.tmSnippet ├── Read from defaults (getprefs).plist ├── Register for Notification.tmSnippet ├── Responds to Selector.plist ├── Save and Restore Graphics Context (gsave).plist ├── Scalar Accessors (acc).plist ├── Scalar Accessors Interface (acc).plist ├── String Accessors Interface (stracc).plist ├── Synthesize.tmSnippet ├── Write to defaults (setprefs).plist └── for(… in …).tmSnippet ├── Support ├── CocoaAnnotatedStrings.txt.gz ├── CocoaAnonymousEnums.txt.gz ├── CocoaClasses.txt.gz ├── CocoaClassesWithAncestry.txt.gz ├── CocoaClassesWithFramework.txt.gz ├── CocoaConstants.txt.gz ├── CocoaFunctions.txt.gz ├── CocoaMethods.txt.gz ├── CocoaNotifications.txt.gz ├── CocoaProtocols.txt.gz ├── CocoaTypes.txt.gz ├── CppReferenceWiki.tsf ├── Platform │ ├── Makefile │ ├── README.md │ ├── generator.mm │ ├── includes.c │ └── includes.mm ├── SpecialRules.txt ├── anonymousEnums.rb ├── generateMethodList.rb ├── lib │ └── docset_query.rb ├── objcParser.rb ├── objc_completion2.rb ├── objc_selector_completion2.rb └── typedefdump.rb ├── Syntaxes ├── Objective-C++.tmLanguage ├── Objective-C.tmLanguage ├── Platform.md ├── Platform.tmLanguage └── Strings File.tmLanguage ├── Templates └── Singleton │ ├── class_in.mm │ ├── header_in.h │ └── info.plist └── info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | Support/Platform/generator 2 | -------------------------------------------------------------------------------- /Commands/Cocoa Context.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/exit_codes" 12 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 13 | require "#{ENV['TM_BUNDLE_SUPPORT']}/objc_completion2" 14 | 15 | def stripComments(line) 16 | line.gsub(/((['"])(?:\\.|.)*?\2)|\/\*.*?\*\/|\/\/[^\n\r]*/m) do |s| 17 | if $1 18 | s 19 | else 20 | s.split("\n").map{|e| ' ' * e.length() }.join("\n") 21 | end 22 | end 23 | end 24 | 25 | class String 26 | def index_of_nth_occurrence_of(n, ch) 27 | self.unpack("U*").each_with_index do |e, i| 28 | return i if e == ch && (n -= 1) == 0 29 | end 30 | return -1 31 | end 32 | end 33 | 34 | def caret_position(line) 35 | tmp = ENV['TM_LINE_NUMBER'].to_i - ENV['TM_INPUT_START_LINE'].to_i 36 | if tmp > 0 37 | caret_placement = line.index_of_nth_occurrence_of(tmp,?\n) + ENV['TM_LINE_INDEX'].to_i 38 | else 39 | caret_placement =ENV['TM_LINE_INDEX'].to_i-ENV['TM_INPUT_START_LINE_INDEX'].to_i - 1 40 | end 41 | end 42 | 43 | if ENV['TERMINAL_MATE_NEW'] 44 | class ObjCMethodCompletion 45 | def show_dialog(prettyCandidates,start,&snip_gen) 46 | require "#{ENV['TM_SUPPORT_PATH']}/lib/osx/plist" 47 | pl = {'menuItems' => prettyCandidates.map { |pretty, junk, full | { 'title' => pretty, 'cand' => full} }} 48 | pl.to_plist 49 | res = pl['menuItems'][0] 50 | snip_gen.call( res['cand'], start ) 51 | end 52 | end 53 | 54 | class TextMateEarlyExitException < RuntimeError 55 | end 56 | 57 | module TextMate 58 | module_function 59 | def exit_show_tool_tip(out = nil) 60 | print out if out 61 | raise TextMateEarlyExitException, "show tool kit" 62 | end 63 | 64 | def exit_discard(out = nil) 65 | print out if out 66 | raise TextMateEarlyExitException, "exit discard" 67 | end 68 | end 69 | 70 | 71 | 72 | tc = [ 73 | {:tmVars => {'TM_LINE_NUMBER' => '19', 'TM_INPUT_START_LINE' => '19', 'TM_LINE_INDEX' => '8', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[self ad]'}, 74 | {:tmVars => {'TM_LINE_NUMBER' => '20', 'TM_INPUT_START_LINE' => '20', 'TM_LINE_INDEX' => '20', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[[NSStrig alloc] ini]'}, 75 | {:tmVars => {'TM_LINE_NUMBER' => '19', 'TM_INPUT_START_LINE' => '19', 'TM_LINE_INDEX' => '8', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[self adbl]'}, 76 | {:tmVars => {'TM_LINE_NUMBER' => '21', 'TM_INPUT_START_LINE' => '21', 'TM_LINE_INDEX' => '26', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[NSObject isKindOfClass:NS]'}, 77 | {:tmVars => {'TM_LINE_NUMBER' => '22', 'TM_INPUT_START_LINE' => '22', 'TM_LINE_INDEX' => '18', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[sto setObject:for]'}, 78 | {:tmVars => {'TM_LINE_NUMBER' => '23', 'TM_INPUT_START_LINE' => '23', 'TM_LINE_INDEX' => '22', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[sto setObject:for for]'}, 79 | {:tmVars => {'TM_LINE_NUMBER' => '24', 'TM_INPUT_START_LINE' => '24', 'TM_LINE_INDEX' => '21', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[sto setObject:for + ]'}, 80 | {:tmVars => {'TM_LINE_NUMBER' => '25', 'TM_INPUT_START_LINE' => '25', 'TM_LINE_INDEX' => '5', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj ]'}, 81 | {:tmVars => {'TM_LINE_NUMBER' => '26', 'TM_INPUT_START_LINE' => '26', 'TM_LINE_INDEX' => '7', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[NSObje]'}, 82 | {:tmVars => {'TM_LINE_NUMBER' => '27', 'TM_INPUT_START_LINE' => '27', 'TM_LINE_INDEX' => '5', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj ]'}, 83 | {:tmVars => {'TM_LINE_NUMBER' => '28', 'TM_INPUT_START_LINE' => '28', 'TM_LINE_INDEX' => '6', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj t]'}, 84 | {:tmVars => {'TM_LINE_NUMBER' => '11','TM_INPUT_START_LINE' => '11','TM_LINE_INDEX' => '11','TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj t:b:av]'}, 85 | {:tmVars => {'TM_LINE_NUMBER' => '30', 'TM_INPUT_START_LINE' => '30', 'TM_LINE_INDEX' => '19', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj set:[NSString ]]'}, 86 | {:tmVars => {'TM_LINE_NUMBER' => '31', 'TM_INPUT_START_LINE' => '31', 'TM_LINE_INDEX' => '30', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj set:[NSString role:@"eu" ]]'}, 87 | {:tmVars => {'TM_LINE_NUMBER' => '32', 'TM_INPUT_START_LINE' => '32', 'TM_LINE_INDEX' => '35', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj set:[NSString role:@"eu" forYo]]'}, 88 | {:tmVars => {'TM_LINE_NUMBER' => '33', 'TM_INPUT_START_LINE' => '33', 'TM_LINE_INDEX' => '40', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj set:[NSString role:@"eu" forYou:sel]]'}, 89 | {:tmVars => {'TM_LINE_NUMBER' => '34', 'TM_INPUT_START_LINE' => '34', 'TM_LINE_INDEX' => '26', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => '[obj postNotificationName: object:NSString *]'}, 90 | {:tmVars => {'TM_LINE_NUMBER'=> '7','TM_INPUT_START_LINE'=> '6','TM_LINE_INDEX'=> '55', 'TM_INPUT_START_LINE_INDEX' => '0'}, :line => "[[NSNotificationCenter defaultCenter] addObserver:self\n selector:@selector(colorPicker:) ]"}] 91 | 92 | 93 | ENV['TM_BUNDLE_SUPPORT'] = "/Library/Application Support/TextMate/Bundles/Objective-C.tmbundle/Support" 94 | tc.each do |element| 95 | element[:tmVars].each do |key,value| 96 | ENV[key] = value 97 | end 98 | caret_placement = caret_position(element[:line]) 99 | begin 100 | res = ObjCMethodCompletion.new(element[:line] , caret_placement).print 101 | rescue NoMethodError => boom 102 | 103 | puts "error in:" + element.inspect 104 | 105 | puts boom 106 | 107 | rescue TextMateEarlyExitException => boom 108 | puts "Early Exit" 109 | end 110 | 111 | end 112 | 113 | else 114 | line = STDIN.read 115 | caret_placement = caret_position(line) 116 | if ENV['TM_SCOPE'].include? "meta.bracketed.objc" 117 | res, os = ObjCMethodCompletion.new(stripComments(line) , caret_placement).print 118 | else 119 | res = ObjCFallbackCompletion.new(stripComments(line) , caret_placement).print 120 | os = 0 121 | end 122 | if res 123 | print e_sn(line[0..caret_placement]) + res + e_sn(line[caret_placement + 1 + os..-1]) 124 | else 125 | TextMate.exit_discard 126 | end 127 | end 128 | 129 | disableOutputAutoIndent 130 | 131 | fallbackInput 132 | scope 133 | input 134 | selection 135 | keyEquivalent 136 | ~ 137 | name 138 | Completion: Inside Brackets 139 | output 140 | insertAsSnippet 141 | scope 142 | meta.function-with-body.objc | meta.bracketed.objc 143 | uuid 144 | 478FBA1D-C11C-4D53-BE95-8B8ABB5F15DC 145 | 146 | 147 | -------------------------------------------------------------------------------- /Commands/Cocoa Function Completion.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/exit_codes" 12 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 13 | require "#{ENV['TM_BUNDLE_SUPPORT']}/objc_completion2" 14 | 15 | def stripComments(line) 16 | line.gsub(/((['"])(?:\\.|.)*?\2)|\/\*.*?\*\/|\/\/[^\n\r]*/m) do |s| 17 | if $1 18 | s 19 | else 20 | ' ' * s.length() 21 | end 22 | end 23 | end 24 | 25 | class String 26 | def index_of_nth_occurrence_of(n, ch) 27 | self.unpack("U*").each_with_index do |e, i| 28 | return i if e == ch && (n -= 1) == 0 29 | end 30 | return -1 31 | end 32 | end 33 | 34 | def caret_position(line) 35 | tmp = ENV['TM_LINE_NUMBER'].to_i - ENV['TM_INPUT_START_LINE'].to_i 36 | if tmp > 0 37 | caret_placement = line.index_of_nth_occurrence_of(tmp,?\n) + ENV['TM_LINE_INDEX'].to_i 38 | else 39 | caret_placement =ENV['TM_LINE_INDEX'].to_i-ENV['TM_INPUT_START_LINE_INDEX'].to_i - 1 40 | end 41 | end 42 | 43 | line = ENV['TM_CURRENT_LINE'] 44 | caret_placement = caret_position(line) 45 | res = ObjCFallbackCompletion.new(stripComments(line) , caret_placement).print 46 | os = 0 47 | print res 48 | input 49 | none 50 | keyEquivalent 51 | ~ 52 | name 53 | Completion: Fallback 54 | output 55 | insertAsSnippet 56 | scope 57 | source.objc, source.objc++ 58 | uuid 59 | 88754B0F-D8DB-4796-9D02-058B756C606D 60 | 61 | 62 | -------------------------------------------------------------------------------- /Commands/Cocoa Method Signature Completion.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes" 12 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 13 | 14 | line = ENV['TM_CURRENT_LINE'] 15 | 16 | def construct_arg_name(arg) 17 | a = arg.match(/(NS|AB|CI|CD)?(Mutable)?(([AEIOQUYi])?[A-Za-z_0-9]+)/) 18 | unless a.nil? 19 | (a[4].nil? ? "a": "an") + a[3].sub!(/\b\w/) { $&.upcase } 20 | else 21 | "" 22 | end 23 | end 24 | 25 | def prettify(cand, call) 26 | stuff = cand.split("\t") 27 | if stuff[0].count(":") > 0 28 | name_array = stuff[0].split(":") 29 | out = "" 30 | begin 31 | stuff[-(name_array.size)..-1].each_with_index do |arg,i| 32 | if arg == "SEL" 33 | out << name_array[i] + ":(SEL)"+ "aSelector " 34 | else 35 | out << name_array[i] + ":("+ arg.gsub(/ \*/,(ENV['TM_C_POINTER'] || " *").rstrip)+")"+ "#{construct_arg_name(arg)} " 36 | end 37 | end 38 | rescue NoMethodError 39 | out << stuff[0] 40 | end 41 | else 42 | out = stuff[0] 43 | end 44 | out = "(#{stuff[5].gsub(/ \*/,(ENV['TM_C_POINTER'] || " *").rstrip)})#{out}" unless call || (stuff.size < 4) 45 | 46 | return [out.chomp.strip, stuff[0], cand] 47 | end 48 | 49 | def snippet_generator(cand, start, call) 50 | start = 0 51 | stuff = cand[start..-1].split("\t") 52 | if stuff[0].count(":") > 0 53 | 54 | name_array = stuff[0].split(":") 55 | name_array = [""] if name_array.empty? 56 | out = "" 57 | begin 58 | stuff[-(name_array.size)..-1].each_with_index do |arg,i| 59 | if arg == "SEL" 60 | out << name_array[i] + ":(#{arg})${#{(i+1).to_s}:aSelector} " 61 | else 62 | out << name_array[i] + ":(#{arg.gsub(/ \*/,(ENV['TM_C_POINTER'] || " *").rstrip)})${#{(i+1).to_s}:#{construct_arg_name(arg)}} " 63 | end 64 | end 65 | rescue NoMethodError 66 | out << stuff[0] 67 | end 68 | else 69 | out = stuff[0] 70 | end 71 | out = "(#{stuff[5].gsub(/ \*/,(ENV['TM_C_POINTER'] || " *").rstrip)})#{out}" unless (stuff.size < 4) 72 | if ENV['TM_SCOPE'].include? "meta.scope.implementation.objc" 73 | if stuff[5].match(/^void$/) || stuff[5].match(/IBAction/) 74 | rv = "" 75 | elsif stuff[5].match(/^BOOL$/) 76 | rv = "\treturn ${1:Y}${1/^(?:(Y)|(N)|.*)/(?1:ES:(?2:O))/};\n" 77 | else 78 | rv = "\treturn nil;\n" 79 | end 80 | 81 | out = out.chomp.strip + "\n\{$0\n#{rv}\}" 82 | else 83 | out = out.chomp.strip + "$0;" 84 | end 85 | return out 86 | end 87 | 88 | def pop_up(candidates, searchTerm, call = true) 89 | start = searchTerm.size 90 | prettyCandidates = candidates.map { |candidate| prettify(candidate,call) }.sort 91 | 92 | if prettyCandidates.size > 1 93 | require "enumerator" 94 | pruneList = [] 95 | 96 | prettyCandidates.each_cons(2) do |a| 97 | pruneList << (a[0][0] != a[1][0]) # check if prettified versions are the same 98 | end 99 | pruneList << true 100 | ind = -1 101 | prettyCandidates = prettyCandidates.select do |a| #remove duplicates 102 | pruneList[ind+=1] 103 | end 104 | end 105 | prettyCandidates = prettyCandidates.sort {|x,y| x[1].downcase <=> y[1].downcase } 106 | if prettyCandidates.size > 1 107 | #index = start 108 | #test = false 109 | #while !test 110 | # candidates.each_cons(2) do |a,b| 111 | # break if test = (a[index].chr != b[index].chr || a[index].chr == "\t") 112 | # end 113 | # break if test 114 | # searchTerm << candidates[0][index].chr 115 | # index +=1 116 | #end 117 | 118 | show_dialog(prettyCandidates,start) do |c,s| 119 | snippet_generator(c,s, call) 120 | end 121 | else 122 | snippet_generator( candidates[0], start, call ) 123 | end 124 | end 125 | 126 | def show_dialog(prettyCandidates,start,&snip_gen) 127 | require "#{ENV['TM_SUPPORT_PATH']}/lib/osx/plist" 128 | pl = {'menuItems' => prettyCandidates.map { |pretty,junk, full | { 'title' => pretty, 'cand' => full} }} 129 | io = open('|"$DIALOG" -u', "r+") 130 | io << pl.to_plist 131 | io.close_write 132 | res = OSX::PropertyList::load(io.read) 133 | if res.has_key? 'selectedMenuItem' 134 | snip_gen.call( res['selectedMenuItem']['cand'], start ) 135 | else 136 | "$0" 137 | end 138 | end 139 | 140 | def candidates_or_exit(methodSearch, list, fileNames, notif = false) 141 | x = candidate_list(methodSearch, list, fileNames, notif) 142 | TextMate.exit_show_tool_tip "No completion available" if x.empty? 143 | return x 144 | end 145 | 146 | def candidate_list(methodSearch, list, fileNames, notif = false) 147 | candidates = [] 148 | fileNames.each do |fileName| 149 | zGrepped = %x{ zgrep ^#{e_sh methodSearch } #{e_sh ENV['TM_BUNDLE_SUPPORT']}/#{fileName} } 150 | candidates += zGrepped.split("\n") 151 | end 152 | # strip notifications 153 | if notif 154 | candidates = candidates.select {|cand| cand.match(/\tno\t/) } 155 | else 156 | candidates = candidates.reject {|cand| cand.match(/\tno\t/) } 157 | end 158 | return [] if candidates.empty? 159 | if list.nil? 160 | return candidates 161 | else 162 | n = [] 163 | candidates.each do |cand| 164 | n << cand if list.include?(cand.split("\t")[0]) 165 | end 166 | n = (n.empty? ? candidates : n) 167 | 168 | return n 169 | end 170 | end 171 | 172 | methodDeclaration = /^((?:\+|-)\s*)([a-zA-Z][a-zA-Z0-9:]*)$/ 173 | 174 | if k = line.match(methodDeclaration) 175 | candidates = candidates_or_exit( k[2], nil, "CocoaMethods.txt.gz") 176 | res =pop_up(candidates, k[2]) 177 | TextMate.exit_discard if res == "$0" 178 | print k[1] + res 179 | else 180 | TextMate.exit_discard 181 | end 182 | 183 | fallbackInput 184 | line 185 | input 186 | selection 187 | keyEquivalent 188 | ~ 189 | name 190 | Completion: Partial Method Signature 191 | output 192 | insertAsSnippet 193 | scope 194 | meta.function.objc - (meta.argument-type.objc | meta.return-type.objc | meta.bracketed) 195 | uuid 196 | 30E93FBA-5A81-4D94-8A03-9CD46FCA3CFA 197 | 198 | 199 | -------------------------------------------------------------------------------- /Commands/Completion: Inside @selector.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/exit_codes" 12 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 13 | require "#{ENV['TM_BUNDLE_SUPPORT']}/objc_selector_completion2" 14 | 15 | def stripComments(line) 16 | line.gsub(/((['"])(?:\\.|.)*?\2)|\/\*.*?\*\/|\/\/[^\n\r]*/m) do |s| 17 | if $1 18 | s 19 | else 20 | ' ' * s.length() 21 | end 22 | end 23 | end 24 | 25 | 26 | def caret_position(line) 27 | tmp = ENV['TM_LINE_NUMBER'].to_i - ENV['TM_INPUT_START_LINE'].to_i 28 | if tmp > 0 29 | caret_placement = line.index_of_nth_occurrence_of(tmp,?\n) + ENV['TM_LINE_INDEX'].to_i 30 | else 31 | caret_placement =ENV['TM_LINE_INDEX'].to_i-ENV['TM_INPUT_START_LINE_INDEX'].to_i - 1 32 | end 33 | end 34 | 35 | line = STDIN.read 36 | 37 | caret_placement = caret_position(line) 38 | 39 | res = ObjcSelectorCompletion.new(stripComments(line) , caret_placement).print 40 | print res 41 | disableOutputAutoIndent 42 | 43 | fallbackInput 44 | scope 45 | hideFromUser 46 | 47 | input 48 | selection 49 | keyEquivalent 50 | ~ 51 | name 52 | Completion: Inside @selector 53 | output 54 | insertAsSnippet 55 | scope 56 | meta.selector.objc 57 | uuid 58 | F929835A-C9F7-4934-87BD-05FD11C4435B 59 | 60 | 61 | -------------------------------------------------------------------------------- /Commands/Delete Outer Method.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | print STDIN.read.sub(/\A\[(.*\])[^\]]*\]\z/, '\\1') 10 | 11 | fallbackInput 12 | scope 13 | input 14 | selection 15 | keyEquivalent 16 | ^@ 17 | name 18 | Delete Outer Method Call 19 | output 20 | replaceSelectedText 21 | scope 22 | meta.bracketed.objc 23 | uuid 24 | E802FA1A-1E2E-4F8A-957F-C1533CE57400 25 | 26 | 27 | -------------------------------------------------------------------------------- /Commands/Documentation for Selector.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 -wKU 11 | require "#{ENV['TM_BUNDLE_SUPPORT']}/lib/docset_query.rb" 12 | 13 | documentation_for_selector 14 | 15 | fallbackInput 16 | scope 17 | input 18 | selection 19 | keyEquivalent 20 | ^h 21 | name 22 | Documentation for Selector 23 | output 24 | showAsTooltip 25 | scope 26 | (meta.bracketed.objc | meta.function.objc) - dyn.selection 27 | uuid 28 | 8AF46225-833C-473E-8EEC-F21C581636F6 29 | 30 | 31 | -------------------------------------------------------------------------------- /Commands/Format Method Signature.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | text = STDIN.read 10 | 11 | text.gsub!(/(\([^\)]+)\s+(\*\))/, '\1\2') 12 | 13 | offset_to_first_colon = text.index(':') 14 | 15 | argument_triplets = text.scan /(.+?):\s*\((.+?)\)\s*([^\s]*)\s*/ 16 | 17 | print(argument_triplets.collect do |triplet| 18 | sprintf "%#{offset_to_first_colon}s:(%s)%s", triplet[0], triplet[1], triplet[2] 19 | end.join("\n")) 20 | 21 | print $1 if text.match /(\n+)\z/ 22 | fallbackInput 23 | scope 24 | input 25 | selection 26 | keyEquivalent 27 | ^q 28 | name 29 | Reformat Method Signature 30 | output 31 | replaceSelectedText 32 | scope 33 | meta.function.objc 34 | uuid 35 | 122E10C1-DFA2-4A9E-9B17-8EBFA6E10CC7 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/Generate Index.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | if [[ -d "$TM_PROJECT_DIRECTORY" ]]; then 11 | find -E "$TM_PROJECT_DIRECTORY" -regex '.*/(_darcs|CVS|\..*)' -prune -or -name '*.h' -print0 | ruby18 "$TM_BUNDLE_SUPPORT/generateMethodList.rb" -c "$TM_PROJECT_DIRECTORY/.classes.TM_Completions.txt" -m "$TM_PROJECT_DIRECTORY/.methods.TM_Completions.txt" -w "$TM_BUNDLE_SUPPORT/CocoaClassesWithFramework.txt.gz"; 12 | gzip -f "$TM_PROJECT_DIRECTORY/.methods.TM_Completions.txt"; 13 | gzip -f "$TM_PROJECT_DIRECTORY/.classes.TM_Completions.txt"; 14 | echo "indexing complete"; 15 | else 16 | echo "no Project Path found"; 17 | fi 18 | fallbackInput 19 | word 20 | input 21 | none 22 | name 23 | Index Headers for Completion 24 | output 25 | showAsTooltip 26 | scope 27 | source.objc, source.objc++ 28 | uuid 29 | 42B1691B-DC28-4743-9B18-C8D51B70722C 30 | 31 | 32 | -------------------------------------------------------------------------------- /Commands/Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | . "$TM_SUPPORT_PATH/lib/webpreview.sh" 11 | html_header "Objective-C Bundle Help" "Objective-C" 12 | "$TM_SUPPORT_PATH/lib/markdown_to_help.rb" <<'MARKDOWN' 13 | 14 | # Introduction 15 | 16 | This document describes the commands of the Objective-C bundle and is a recommended read, since not all features are easy to discover. 17 | 18 | In addition to this help file there are also 3 screencasts dedicated to showing Objective-C features (the links below are to more info about the screencast): 19 | 20 | 1. The [most recent][SC1] is by Joachim Mårtensson and shows completion, bracket matching, reformatting methods, and documentation lookup. 21 | 2. [Objective-C Part 2][SC2] by Allan Odgaard. 22 | 3. [Graceful Objective-C Snippets][SC3] by Allan Odgaard. 23 | 24 | You can see [all screencasts here][AllCasts]. 25 | 26 | [SC1]: http://macromates.com/screencast/TextMateObjCScreenCast.mov 27 | [SC2]: http://macromates.com/blog/archives/2006/04/29/objective-c-part-2-screencast/ 28 | [SC3]: http://macromates.com/blog/archives/2006/03/17/graceful-objective-c-snippets/ 29 | [AllCasts]: http://macromates.com/screencasts 30 | 31 | # Code Completion 32 | 33 | Code Completion is activated using the ⌥⎋ key equivalent. Code completion is available in several places which will be the topic of the next few sections. 34 | 35 | ## Within Brackets 36 | 37 | A method call in Objective-C consists of three different types (though not all method calls take arguments): 38 | 39 | [«receiver» «selector»:«argument»] 40 | 41 | The completion support can help you with all three parts, which will be explained in the following three sections. 42 | 43 | ### Receiver 44 | 45 | A partially typed receiver can be completed, here candidates are all Cocoa classes (class objects). For example if we have: 46 | 47 | [NSObje‸ ] 48 | 49 | Then the list of possible completions will contain `NSObject` and `NSObjectController`. 50 | 51 | ### Selector 52 | 53 | When the receiver is a class object, like in the following example: 54 | 55 | [NSString ‸] 56 | 57 | Then the candidates are all methods implemented by that class, in the above example, that would be all `NSString` class methods. 58 | 59 | If the selector is partially typed, and the receiver is not a known class object, as is the case below: 60 | 61 | [object setV‸] 62 | 63 | Then a list is shown with all Cocoa methods starting with `setV`. 64 | 65 | Currently the list of completion candidates are only filtered to those implemented by `object`, when object is a method local variable of a type that has been indexed. 66 | 67 | One exception is when the receiver is itself a method call, for example in the following case: 68 | 69 | [[object string] ‸] 70 | 71 | Here only methods implemented by `NSString` are suggested, since it is know that the result of the `string` selector is an `NSString` object. 72 | 73 | For selectors with multiple arguments, it is possible to activate completion when entering the name of a later argument, for example: 74 | 75 | [object setObject:name forK‸] 76 | 77 | Will list all methods starting with `setObject:forK`. 78 | 79 | ### Argument 80 | 81 | When at the argument position, like here: 82 | 83 | [NSString stringWithCString:"foo" encoding:‸] 84 | 85 | The completion command will check the argument type and find all constants which match that type. In the above example that would be all string encoding constants. 86 | 87 | ## Outside of Brackets 88 | 89 | The completion command will give different suggestions based on the caret’s scope. To see the current scope you can press ⌃⇧P. The 6 different scopes are marked below: 90 | 91 | @interface MyClass : NSO‸₁ <NSObj‸₂> 92 | { 93 | NSSt‸₃ 94 | } 95 | @end 96 | 97 | @implementation MyClass 98 | - (id)init 99 | { 100 | if(self = [super init]) 101 | { 102 | NSArr‸₄ 103 | } 104 | return self; 105 | } 106 | - windowW‸₅ 107 | - (NSStr‸₆)stringFromString(NSSt‸₆<NSCod‸₂>) 108 | @end 109 | 110 | The candidates suggested for the 6 different scopes are: 111 | 112 | 1. Known Cocoa classes. 113 | 2. Known Cocoa protocols. 114 | 3. Same as 1, but a variable name will also be inserted. For example the above will suggest `NSString` and `NSStream`. If we pick the former, it will insert `NSString *aString`. 115 | 4. Same as 3, but completion of known (C, C++, and Cocoa) functions is also suggested. 116 | 5. Here completion candidates are known Cocoa methods, but inserted as when implementing the method. For example in the above, one of the suggestions is `windowWillClose`, which when selected, will have the line changed to: `- (void)windowWillClose:(NSNotification *)aNotification`. 117 | 6. Same as 1, but an asterisk (`*`) is inserted. 118 | 119 | ## Completing User Methods 120 | 121 | By default completion candidates comes from the various Apple frameworks (mostly under the Cocoa umbrella). 122 | 123 | If you wish to have your own methods and classes shown as completion candidates, you can invoke the *Index Headers for Completion* command. 124 | 125 | This scans all headers in the current project folder and saves the result as `.methods.TM_Completions.txt.gz` and `.classes.TM_Completions.txt.gz` in your project folder. 126 | 127 | You can later re-run the command to update the index. 128 | 129 | # Bracket Matching 130 | 131 | ## Wrapping Selectors 132 | 133 | When you want to send a message (selector) to an object, you need to wrap both the object and message in square brackets (`[object message]`). Even if you did not put an opening bracket at the start of the expression, there is no need to go back and place it, since TextMate is smart enough to figure out where to place the start bracket, when typing an unmatched close bracket. 134 | 135 | Here are two simple examples: 136 | 137 | obj message‸ → [obj message] 138 | 139 | obj message:arg‸ → [obj message:arg] 140 | 141 | An ambiguity exists when sending multi-argument messages to the object. For example if we have: 142 | 143 | obj message:arg otherMessage:arg2‸ 144 | 145 | Then there are two candidates for the outcome: 146 | 147 | 1. [obj message:arg otherMessage:arg2] 148 | 2. obj message:[arg otherMessage:arg2] 149 | 150 | If `message:otherMessage:` is a known Cocoa method or one of your indexed methods, then the first one is picked, otherwise the second one. 151 | 152 | ## Wrapping Objects 153 | 154 | If you type a closing bracket after a single word, it is assumed that this word is an object to which you want to send a message, e.g.: 155 | 156 | obj‸ → [obj ‸] 157 | 158 | The space is only inserted if there is not already a space after the object. 159 | 160 | ## General 161 | 162 | The bracket completion is aware of quite a few C and Objective-C constructs and will not wrap when it does not make (much) sense. 163 | 164 | nil‸ → nil] // no messaging nil 165 | return self‸ → return [self ‸] 166 | NSArray arrayWithObjects:names, urls, nil‸ 167 | → [NSArray arrayWithObjects:names, urls, nil] 168 | 169 | Here is how the bracket matcher (basically) works: 170 | 171 | 1. If there is a word to the left of the caret, try to find an object to the left of it. 172 | 2. If the above failed, look for a message that takes an argument. If found, try to find even more such messages compare them with known Cocoa methods as we go, if no known Cocoa methods are found we use only the first matched message. try to find an object to the left of the message. 173 | 3. If neither 1 or 2, we have a single object, wrap it and insert the caret between the brackets. 174 | 175 | # Reformatting 176 | 177 | ## Method Calls 178 | 179 | Pressing ⌃Q when the caret is inside a multi-part method call will align the method-parts around the colon (`:`). For example the following: 180 | 181 | [NSEvent enterExitEventWithType:anEventType location:aPoint 182 | modifierFlags:flags timestamp:aTimeInterval 183 | windowNumber:number context:aGraphicsContext 184 | eventNumber:x trackingNumber:tracker userData:data] 185 | 186 | Will be reformatted as: 187 | 188 | [NSEvent enterExitEventWithType:anEventType 189 | location:aPoint 190 | modifierFlags:flags 191 | timestamp:aTimeInterval 192 | windowNumber:number 193 | context:aGraphicsContext 194 | eventNumber:x 195 | trackingNumber:tracker 196 | userData:data] 197 | 198 | By default the inner brackets will be reformatted if the brackets are nested, move the caret to a non nested area to get the outer methods reformatted. 199 | 200 | ## Method Implementations 201 | 202 | Like with method calls, we can reformat method implementations using ⌃Q. If for example we implemented the method above, and our source looks like this: 203 | 204 | + (NSEvent *)enterExitEventWithType:(NSEventType)type 205 | location:(NSPoint)location modifierFlags:(unsigned int)flags 206 | timestamp:(NSTimeInterval)time windowNumber:(int)windowNumber 207 | context:(NSGraphicsContext *)context eventNumber:(int)eventNumber 208 | trackingNumber:(int)trackingNumber userData:(void *)userData 209 | { 210 | 211 | } 212 | 213 | Then we can reformat it easily using ⌃Q on the first line, and we get: 214 | 215 | + (NSEvent *)enterExitEventWithType:(NSEventType)type 216 | location:(NSPoint)location 217 | modifierFlags:(unsigned int)flags 218 | timestamp:(NSTimeInterval)time 219 | windowNumber:(int)windowNumber 220 | context:(NSGraphicsContext *)context 221 | eventNumber:(int)eventNumber 222 | trackingNumber:(int)trackingNumber 223 | userData:(void*)userData 224 | { 225 | 226 | } 227 | 228 | # Documentation Look-up 229 | 230 | Pressing ⌃H when the caret is on a class name, method call, function name, constant, or similar, will (for most known Cocoa stuff) find the appropriate spot in the documentation. 231 | 232 | There are actually two documentation look-up commands (for two different scopes), so generally use the ⌃H key equivalent rather than the menu item. 233 | 234 | # Snippets 235 | 236 | The Objective-C bundle has specialized several of the snippets for different scopes. 237 | 238 | An example is shown below: 239 | 240 | @interface MyClass : NSObject 241 | { 242 | } 243 | m‸ 244 | @end 245 | 246 | @implementation MyClass 247 | m‸ 248 | 249 | - (void)myMethod 250 | { 251 | log‸ 252 | } 253 | @end 254 | 255 | void MyFunction () 256 | { 257 | log‸ 258 | } 259 | 260 | Here we have entered both the tab trigger `m` and `log` in two different scopes. If we press tab (⇥) to expand all four tab triggers, then the resulting code becomes: 261 | 262 | @interface MyClass : NSObject 263 | { 264 | } 265 | - (id‸)method:(id)anArgument; 266 | @end 267 | 268 | @implementation MyClass 269 | - (id‸)method:(id)anArgument 270 | { 271 | return nil; 272 | } 273 | 274 | - (void)myMethod 275 | { 276 | NSLog(@"%s‸", _cmd); 277 | } 278 | @end 279 | 280 | void MyFunction () 281 | { 282 | NSLog(@"‸"); 283 | } 284 | 285 | What’s interesting here is that the `m` tab trigger expands to a full method implementation inside `@implementation…@end`, but only a prototype when inside `@interface…@end`. Likewise the `log` tab trigger will only output the `_cmd` variable when called from inside a method (where it is available). 286 | 287 | All the accessor snippets are likewise specialized for `@implementation` and `@interface`, though only one set appears in the menu (so use the tab trigger to get the proper one). 288 | 289 | In addition to specializing the snippets for different scopes, a lot of other magic has also been put into them. If for example you add `%d` to the format string of the `NSLog` snippet, then an argument placeholder is automatically inserted. The method snippet will remove the `return nil;` line if you change the return type to `void`, and it will let the argument variable’s name match its type, for example if you change the type from `id` to `NSString*` then the variable becomes `aString`. 290 | 291 | # Credits 292 | 293 | The cool stuff in this bundle is done by Joachim Mårtensson. 294 | 295 | Additional work by Chris Thomas and Allan Odgaard. The initial bracket matcher (which served us well for a long time) was done by Rob Rix. 296 | 297 | MARKDOWN 298 | html_footer 299 | input 300 | none 301 | name 302 | Help 303 | output 304 | showAsHTML 305 | scope 306 | source.objc, source.objc++ 307 | uuid 308 | AFB40870-6F83-4211-9362-0538287B52A9 309 | 310 | 311 | -------------------------------------------------------------------------------- /Commands/Insert Call to Super.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | # Inserts a [super method] call suitable for the current method. 11 | # 12 | # The command is inserted as a snippet with each parameter as a tabstop 13 | # An opening bracket is inserted if necessary, and a semicolon is 14 | # added after the closing bracket if there is nothing else on the line. 15 | # 16 | # The command uses heuristics to find which method implementation is 17 | # being edited. It should be reasonably tolerant to various coding styles, 18 | # including different bracket and indentation styles. 19 | 20 | proto_re = / 21 | ^\s* # Start of the line and optional space 22 | [+-]\s* # a plus or minus for method specifier 23 | \([^)]+\) # the return type in brackets 24 | (?!.*;) # Assert implementation and not interface 25 | ((?:\n|[^{])*) 26 | (?m:.*?) 27 | \{ 28 | /x 29 | 30 | previous_lines = STDIN.readlines[1..ENV['TM_LINE_NUMBER'].to_i - 1] 31 | invocation_line = previous_lines[-1] 32 | proto = previous_lines.join.scan(proto_re)[-1] 33 | 34 | exit if proto.nil? or proto.empty? 35 | 36 | last_proto_sel_with_types = proto[0].strip.sub(/^\s+/, '').sub(%r{\s*//.*$}, '').gsub(/\n\s*/, ' ') 37 | 38 | tabstop = 0 39 | 40 | last_proto_sel_with_types.gsub!(/\([^)]+\)\s*(([A-Za-z0-9_][A-Za-z0-9_]*))/) do |match| 41 | %Q{${#{tabstop += 1}:#$1}} 42 | end 43 | 44 | print '[' if invocation_line[ENV["TM_LINE_INDEX"].to_i - 1] != ?[ 45 | print 'super ' 46 | print last_proto_sel_with_types 47 | print "]" 48 | print ";" if invocation_line =~ /^\s+$/ 49 | 50 | fallbackInput 51 | scope 52 | input 53 | document 54 | name 55 | Insert Call to Super 56 | output 57 | insertAsSnippet 58 | scope 59 | source.objc meta.scope.implementation, source.objc++ meta.scope.implementation 60 | tabTrigger 61 | super 62 | uuid 63 | DA9B35AF-938D-4166-8576-E8E3C73F0739 64 | 65 | 66 | -------------------------------------------------------------------------------- /Commands/Insert Matching Start Bracket.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 12 | require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes" 13 | 14 | class Lexer 15 | include Enumerable 16 | def initialize 17 | @label = nil 18 | @pattern = nil 19 | @handler = nil 20 | @input = nil 21 | 22 | reset 23 | 24 | yield self if block_given? 25 | end 26 | 27 | def input(&reader) 28 | if @input.is_a? self.class 29 | @input.input(&reader) 30 | else 31 | class << reader 32 | alias_method :next, :call 33 | end 34 | 35 | @input = reader 36 | end 37 | end 38 | 39 | def add_token(label, pattern, &handler) 40 | unless @label.nil? 41 | @input = clone 42 | end 43 | 44 | @label = label 45 | @pattern = /(#{pattern})/ 46 | @handler = handler || lambda { |label, match| [label, match] } 47 | 48 | reset 49 | end 50 | 51 | def next(peek = false) 52 | while @tokens.empty? and not @finished 53 | new_input = @input.next 54 | if new_input.nil? or new_input.is_a? String 55 | @buffer += new_input unless new_input.nil? 56 | new_tokens = @buffer.split(@pattern) 57 | while new_tokens.size > 2 or (new_input.nil? and not new_tokens.empty?) 58 | @tokens << new_tokens.shift 59 | @tokens << @handler[@label, new_tokens.shift] unless new_tokens.empty? 60 | end 61 | @buffer = new_tokens.join 62 | @finished = true if new_input.nil? 63 | else 64 | separator, new_token = @buffer.split(@pattern) 65 | new_token = @handler[@label, new_token] unless new_token.nil? 66 | @tokens.push( *[ separator, 67 | new_token, 68 | new_input ].select { |t| not t.nil? and t != "" } ) 69 | reset(:buffer) 70 | end 71 | end 72 | peek ? @tokens.first : @tokens.shift 73 | end 74 | 75 | def peek 76 | self.next(true) 77 | end 78 | 79 | def each 80 | while token = self.next 81 | yield token 82 | end 83 | end 84 | 85 | private 86 | 87 | def reset(*attrs) 88 | @buffer = String.new if attrs.empty? or attrs.include? :buffer 89 | @tokens = Array.new if attrs.empty? or attrs.include? :tokens 90 | @finished = false if attrs.empty? or attrs.include? :finished 91 | end 92 | end 93 | 94 | 95 | class ObjcParser 96 | 97 | attr_reader :list 98 | def initialize(args) 99 | @list = args 100 | end 101 | 102 | def get_position 103 | return nil,nil if @list.empty? 104 | has_message = true 105 | 106 | a = @list.pop 107 | endings = [:close,:post_op,:at_string,:at_selector,:identifier] 108 | openings = [:open,:return,:control] 109 | if a.tt == :identifier && !@list.empty? && endings.include?(@list[-1].tt) 110 | insert_point = find_object_start 111 | else 112 | @list << a 113 | has_message = false unless methodList 114 | insert_point = find_object_start 115 | end 116 | return insert_point, has_message 117 | end 118 | 119 | def methodList 120 | old = Array.new(@list) 121 | 122 | a = selector_loop(@list) 123 | if !a.nil? && a.tt == :selector 124 | if file_contains_selector? a.text 125 | return true 126 | else 127 | internal = Array.new(@list) 128 | b = a.text 129 | until internal.empty? 130 | tmp = selector_loop(internal) 131 | return true if tmp.nil? 132 | b = tmp.text + b 133 | if file_contains_selector? b 134 | @list = internal 135 | return true 136 | end 137 | end 138 | end 139 | else 140 | end 141 | @list = old 142 | return false 143 | end 144 | 145 | def file_contains_selector?(methodName) 146 | fileNames = ["#{ENV['TM_BUNDLE_SUPPORT']}/CocoaMethods.txt.gz"] 147 | userMethods = "#{ENV['TM_PROJECT_DIRECTORY']}/.methods.TM_Completions.txt.gz" 148 | 149 | fileNames += [userMethods] if File.exists? userMethods 150 | candidates = [] 151 | fileNames.each do |fileName| 152 | zGrepped = %x{zgrep ^#{e_sh methodName }[[:space:]] #{e_sh fileName }} 153 | candidates += zGrepped.split("\n") 154 | end 155 | 156 | return !candidates.empty? 157 | end 158 | 159 | def selector_loop(l) 160 | until l.empty? 161 | obj = l.pop 162 | case obj.tt 163 | when :selector 164 | return obj 165 | when :close 166 | return nil if match_bracket(obj.text,l).nil? 167 | when :open 168 | return nil 169 | end 170 | end 171 | return nil 172 | end 173 | 174 | def match_bracket(type,l) 175 | partner = {"]"=>"[",")"=>"(","}"=>"{"}[type] 176 | up = 1 177 | until l.empty? 178 | obj = l.pop 179 | case obj.text 180 | when type 181 | up +=1 182 | when partner 183 | up -=1 184 | end 185 | return obj.beg if up == 0 186 | end 187 | end 188 | 189 | def find_object_start 190 | openings = [:operator,:selector,:open,:return,:control] 191 | until @list.empty? || openings.include?(@list[-1].tt) 192 | obj = @list.pop 193 | case obj.tt 194 | when :close 195 | tmp = match_bracket(obj.text, @list) 196 | b = tmp unless tmp.nil? 197 | when :star 198 | b, ate = eat_star(b,obj.beg) 199 | return b unless ate 200 | when :nil 201 | b = nil 202 | else 203 | b = obj.beg 204 | end 205 | end 206 | return b 207 | end 208 | 209 | def eat_star(prev, curr) 210 | openings = [:operator,:selector,:open,:return,:control,:star] 211 | if @list.empty? || openings.include?(@list[-1].tt) 212 | return curr, true 213 | else 214 | return prev, false 215 | end 216 | end 217 | end 218 | 219 | if __FILE__ == $PROGRAM_NAME 220 | require "stringio" 221 | line = ENV['TM_CURRENT_LINE'] 222 | caret_placement =ENV['TM_LINE_INDEX'].to_i - 1 223 | 224 | up = 0 225 | pat = /"(?:\\.|[^"\\])*"|\[|\]/ 226 | line.scan(pat).each do |item| 227 | case item 228 | when "[" 229 | up+=1 230 | when "]" 231 | up -=1 232 | end 233 | end 234 | if caret_placement ==-1 235 | print "]$0" + e_sn(line[caret_placement+1..-1]) 236 | TextMate.exit_insert_snippet 237 | end 238 | 239 | if up != 0 240 | print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1]) 241 | TextMate.exit_insert_snippet 242 | end 243 | 244 | to_parse = StringIO.new(line[0..caret_placement]) 245 | lexer = Lexer.new do |l| 246 | l.add_token(:return, /\breturn\b/) 247 | l.add_token(:nil, /\bnil\b/) 248 | l.add_token(:control, /\b(?:if|while|for|do)(?:\s*)\(/)# /\bif|while|for|do(?:\s*)\(/) 249 | l.add_token(:at_string, /"(?:\\.|[^"\\])*"/) 250 | l.add_token(:selector, /\b[A-Za-z_0-9]+:/) 251 | l.add_token(:identifier, /\b[A-Za-z_0-9]+\b/) 252 | l.add_token(:bind, /(?:->)|\./) 253 | l.add_token(:post_op, /\+\+|\-\-/) 254 | l.add_token(:at, /@/) 255 | l.add_token(:star, /\*/) 256 | l.add_token(:close, /\)|\]|\}/) 257 | l.add_token(:open, /\(|\[|\{/) 258 | l.add_token(:operator, /[&-+\/=%!:\,\?;<>\|\~\^]/) 259 | 260 | l.add_token(:terminator, /;\n*|\n+/) 261 | l.add_token(:whitespace, /\s+/) 262 | l.add_token(:unknown, /./) 263 | 264 | l.input { to_parse.gets } 265 | #l.input {STDIN.read} 266 | end 267 | 268 | offset = 0 269 | tokenList = [] 270 | A = Struct.new(:tt, :text, :beg) 271 | 272 | lexer.each do |token| 273 | tokenList << A.new(*(token<<offset)) unless [:whitespace,:terminator].include? token[0] 274 | offset +=token[1].length 275 | end 276 | if tokenList.empty? 277 | print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1]) 278 | TextMate.exit_insert_snippet 279 | end 280 | 281 | par = ObjcParser.new(tokenList) 282 | b, has_message = par.get_position 283 | 284 | if !line[caret_placement+1].nil? && line[caret_placement+1].chr == "]" 285 | if b.nil? || par.list.empty? || par.list[-1].text == "[" 286 | print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+2..-1]) 287 | TextMate.exit_insert_snippet 288 | end 289 | end 290 | 291 | if b.nil? 292 | print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1]) 293 | elsif !has_message && (b < caret_placement ) 294 | print e_sn(line[0..b-1]) unless b == 0 295 | ins = (/\s/ =~ line[caret_placement].chr ? "$0]" : " $0]") 296 | print "[" +e_sn(line[b..caret_placement]) + ins +e_sn(line[caret_placement+1..-1]) 297 | elsif b < caret_placement 298 | print e_sn(line[0..b-1]) unless b == 0 299 | print "[" +e_sn(line[b..caret_placement]) +"]$0"+e_sn(line[caret_placement+1..-1]) 300 | else 301 | print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1]) 302 | end 303 | end 304 | 305 | fallbackInput 306 | line 307 | input 308 | selection 309 | keyEquivalent 310 | ] 311 | name 312 | Insert Matching Start Bracket 313 | output 314 | insertAsSnippet 315 | scope 316 | (source.objc | source.objc++) - (string | comment | dyn.selection | dyn.caret.mixed) 317 | uuid 318 | DB16585F-4D78-412B-B468-38AD54C254B5 319 | 320 | 321 | -------------------------------------------------------------------------------- /Commands/Insert NSLog() for current method.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | proto_re = / 11 | ^\s* # Start of the line and optional space 12 | [+-]\s* # a plus or minus for method specifier 13 | \([^)]+\) # the return type in brackets 14 | ((?:\n|[^@{])*) 15 | (?m:[\s;]*) 16 | \{ 17 | /x 18 | 19 | previous_lines = STDIN.readlines[1..ENV['TM_LINE_NUMBER'].to_i - 1] 20 | invocation_line = previous_lines[-1] 21 | 22 | proto = previous_lines.join.scan(proto_re)[-1] 23 | 24 | exit if proto.nil? or proto.empty? 25 | 26 | last_proto_sel_with_types = proto[0].strip.sub(/^\s+/, '').sub(%r{\s*//.*$}, '').gsub(/\n\s*/, ' ') 27 | 28 | params = [] 29 | params = last_proto_sel_with_types.scan(/(.+?)\s*:\s*\((.+?)\)\s*(\w+)/) 30 | 31 | def format_specifier_for_type(type) 32 | case type.gsub(/\s*const\s*/, '') 33 | when /\b(int|bool|BOOL)\b/ then '%d' 34 | when /\b(NSInteger|long)\b/ then '%ld' 35 | when /\b(NSUInteger)\b/ then '%lu' 36 | when /\b(size_t)\b/ then '%zu' 37 | when /\b(ssize_t)\b/ then '%zd' 38 | when /\b(float|double|CGFloat)\b/ then '%f' 39 | when /\b(char\*|string\b)/ then '%s' 40 | when /\b(char)\b/ then '%c' 41 | when /\b(unichar)\b/ then '%C' 42 | else '%@' 43 | end 44 | end 45 | 46 | def transformer_for(type, name) 47 | case type 48 | when 'NSRect': "NSStringFromRect(#{name})" 49 | when 'NSRange': "NSStringFromRange(#{name})" 50 | when 'NSPoint': "NSStringFromPoint(#{name})" 51 | when 'NSSize': "NSStringFromSize(#{name})" 52 | when 'SEL': "NSStringFromSelector(#{name})" 53 | when /string/: "#{name}.c_str()" 54 | else name 55 | end 56 | end 57 | 58 | print 'NSLog(@"[%@ ' 59 | if params.empty? 60 | print last_proto_sel_with_types 61 | else 62 | print params.map { |param, type, name| param + ':' + format_specifier_for_type(type) }.join 63 | end 64 | print ']", [self class]' 65 | print ', ' + params.map { |param, type, name| transformer_for(type, name) }.join(', ') unless params.empty? 66 | print ");" 67 | 68 | input 69 | document 70 | name 71 | Insert NSLog() for Current Method 72 | output 73 | insertAsSnippet 74 | scope 75 | source.objc meta.scope.implementation, source.objc++ meta.scope.implementation 76 | tabTrigger 77 | logm 78 | uuid 79 | C5624A26-E661-46EE-AA6A-14E6B678CFF9 80 | 81 | 82 | -------------------------------------------------------------------------------- /Commands/Lookup Cocoa Class.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | require "#{ENV['TM_BUNDLE_SUPPORT']}/lib/docset_query.rb" 10 | 11 | documentation_for_word 12 | 13 | fallbackInput 14 | word 15 | input 16 | none 17 | inputFormat 18 | text 19 | keyEquivalent 20 | ^h 21 | name 22 | Documentation for Word / Selection 23 | outputCaret 24 | afterOutput 25 | outputFormat 26 | text 27 | outputLocation 28 | toolTip 29 | scope 30 | source.c, source.c++, source.objc, source.objc++, (source.objc support | source.objc++ support) - support.function.any-method 31 | semanticClass 32 | lookup.define.objc 33 | uuid 34 | 2E0F350A-7B23-11D9-B084-000D93589AF6 35 | version 36 | 2 37 | 38 | 39 | -------------------------------------------------------------------------------- /Commands/Paste Implementation : Interface.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | # 10 | # Possible improvements: 11 | # • Preserve empty lines between methods taken from the clipboard 12 | # • Make the “parser” conform to the actual Objective-C spec 13 | # 14 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 15 | 16 | methods = [] 17 | 18 | %x{ pbpaste }.scan(/^ 19 | \s* 20 | ([-+]) # Class or object method 21 | (\s* \( ([^\)]+) \))? # Optional return type 22 | (\s* [a-z0-9_]+) # Method name 23 | 24 | # Zero or more parameters: 25 | 26 | ( (\s* [a-z0-9_]*) # Optional name of parameter 27 | : # Mandatory colon 28 | (\s* \( [^\)]+ \))? # Optional type of parameter 29 | (\s* [a-z0-9_]+) # Parameter name (might be optional) 30 | (\s* , \s* ...)? # Optional var-args notation 31 | )* 32 | 33 | (?=\s* ;?) # Optional semicolon 34 | 35 | /ix) do 36 | rettype = $3.to_s.strip 37 | methods << [$&.strip.gsub(' *)', (ENV['TM_C_POINTER'] || ' *').rstrip + ')'), rettype] 38 | end 39 | 40 | TextMate::exit_show_tool_tip('No methods found on the clipboard') if methods.empty? 41 | 42 | if ENV['TM_SCOPE'] !~ /meta.implementation.objc/ 43 | methods.each { |(proto, rettype)| puts "#{proto};" } 44 | else 45 | tabstop = 0 46 | puts(methods.map do |(proto, rettype)| 47 | ret = case rettype 48 | when "void", "IBAction" 49 | "" 50 | when "BOOL" 51 | "\treturn ${#{tabstop+=1}:Y}${1/^(?:(Y)|(N)|.*)/(?1:ES:(?2:O))/};\n" 52 | else 53 | "\treturn ${#{tabstop+=1}:nil};\n" 54 | end 55 | "#{proto}\n{\n#{ret}}\n" 56 | end.join("\n")) 57 | end 58 | 59 | fallbackInput 60 | line 61 | input 62 | none 63 | keyEquivalent 64 | ^V 65 | name 66 | Paste Implementation / Interface 67 | output 68 | insertAsSnippet 69 | scope 70 | meta.interface-or-protocol.objc, meta.implementation.objc 71 | uuid 72 | CB5EC7EC-35B7-4FD8-9045-31CCC379D474 73 | 74 | 75 | -------------------------------------------------------------------------------- /Commands/Paste selector.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | pbpaste|head -n1|perl -pe's/:\(.+?\)\w+\s*/:/g'|perl -pe's/^[-+]\s*\(.+?\)\s*|\s+|;//g' 9 | input 10 | none 11 | keyEquivalent 12 | ^V 13 | name 14 | Paste Selector 15 | output 16 | afterSelectedText 17 | scope 18 | meta.selector.objc 19 | uuid 20 | D9CA98D1-7564-4CCB-8156-9A06210A1A7F 21 | 22 | 23 | -------------------------------------------------------------------------------- /Commands/Reflow Method Call.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | 4679484F-6227-11D9-BFB1-000D93589AF6 9 | command 10 | #!/usr/bin/env ruby18 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 12 | 13 | line = STDIN.read 14 | offset = ENV['TM_INPUT_START_COLUMN'].to_i - 1 15 | caret_placement = 0 16 | tmp = ENV['TM_LINE_NUMBER'].to_i - ENV['TM_INPUT_START_LINE'].to_i 17 | if tmp > 0 18 | class String 19 | def index_of_nth_occurrence_of(n, ch) 20 | self.unpack("U*").each_with_index do |e, i| 21 | return i if e == ch && (n -= 1) == 0 22 | end 23 | return -1 24 | end 25 | end 26 | caret_placement += line.index_of_nth_occurrence_of(tmp,?\n) + ENV['TM_LINE_INDEX'].to_i 27 | else 28 | caret_placement =ENV['TM_LINE_INDEX'].to_i-ENV['TM_INPUT_START_LINE_INDEX'].to_i - 1 29 | end 30 | 31 | def match_iter(rgxp,str) 32 | offset = 0 33 | while m = str.match(rgxp) 34 | yield [m[0], m.begin(0) + offset, m[0].length] 35 | str = m.post_match 36 | offset += m.end(0) 37 | end 38 | end 39 | 40 | pat = /("(\\.|[^"\\])*"|\[|\]|@selector\([^\)]*\)|[a-zA-Z][a-zA-Z0-9]*:)/ 41 | up = 0 42 | list = [] 43 | 44 | up = 0 45 | pat = /("(\\.|[^"\\])*"|\[|\]|@selector\([^\)]*\)|[a-zA-Z][a-zA-Z0-9]*:)/ 46 | start = [0] 47 | match_iter(pat , line[0..caret_placement]) do |tok, beg, len| 48 | t = tok[0].chr 49 | if t == "[" 50 | start << beg 51 | elsif t == "]" 52 | start.pop 53 | end 54 | end 55 | 56 | 57 | up = 0 58 | last = line.length 59 | match_iter(pat , line[caret_placement+1..line.length]) do |tok, beg, len| 60 | t = tok[0].chr 61 | if t == "[" 62 | up +=1 63 | elsif t == "]" 64 | if up == 0 65 | last = beg + caret_placement + 1 66 | break 67 | end 68 | up -=1 69 | end 70 | end 71 | 72 | list = [] 73 | prefix = "" 74 | prefix = line[0..start[-1]-1] unless start[-1] == 0 75 | suffix = line[last+1..-1] 76 | l = line[start[-1]..last] 77 | up = -1 78 | 79 | match_iter(pat , l) do |tok, beg, len| 80 | t = tok[0].chr 81 | if t == "[" 82 | up +=1 83 | elsif t == "]" 84 | up -=1 85 | elsif t !='"' and t !='@' and up == 0 86 | list << [beg,len] 87 | end 88 | end 89 | 90 | list << [l.length,0] 91 | offset += start[-1] 92 | if list.length > 2 93 | print e_sn(prefix+ l[0...list[1][0]].strip) 94 | #check to if the first "selector:" is not in the first line 95 | if k = line[0...start[-1]+list[0][0]].rindex("\n") 96 | firstIndex = list[0][0]+list[0][1]- k -1 97 | offset = start[-1] 98 | else 99 | firstIndex = list[0][0] + list[0][1] 100 | end 101 | (1..(list.length() -2)).each do |ind| 102 | list[ind][1]+list[ind][0] 103 | b = (b = firstIndex-list[ind][1]+offset) > 0 ? b : 0 104 | print e_sn("\n" + " "*b + l[(list[ind][0])...(list[ind+1][0])].strip) 105 | end 106 | print e_sn(suffix) unless suffix.nil? 107 | else 108 | print e_sn(line) 109 | end 110 | 111 | fallbackInput 112 | scope 113 | input 114 | selection 115 | keyEquivalent 116 | ^q 117 | name 118 | Reformat Method Call 119 | output 120 | replaceSelectedText 121 | scope 122 | meta.bracketed.objc 123 | uuid 124 | 8957C99F-88F5-42CC-B355-AAC6BF3FDF8D 125 | 126 | 127 | -------------------------------------------------------------------------------- /Commands/Toggle Import : Include Keyword.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | def toggle(keyword) 11 | case keyword 12 | when 'import' then 'include' 13 | when 'include' then 'import' 14 | else keyword 15 | end 16 | end 17 | 18 | STDOUT << toggle(STDIN.read) 19 | 20 | hideFromUser 21 | 22 | input 23 | scope 24 | inputFormat 25 | text 26 | keyEquivalent 27 | ^" 28 | name 29 | Toggle Import/Include Keyword 30 | outputCaret 31 | interpolateByChar 32 | outputFormat 33 | text 34 | outputLocation 35 | replaceInput 36 | scope 37 | keyword.control.import.include, L:keyword.control.import.include 38 | uuid 39 | A8F23393-4D73-480A-A268-6DCD514DE2E4 40 | version 41 | 2 42 | 43 | 44 | -------------------------------------------------------------------------------- /Commands/Wrap in [[alloc] init] (alloc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | def e (str); str.gsub(/[$`\\]/, '\\\\\0'); end 11 | 12 | line = STDIN.read 13 | col = ENV['TM_LINE_INDEX'].to_i 14 | 15 | left, right = line[0...col], line[col..-1] 16 | 17 | if left =~ /(.*?)(\[)?(\w+)\s+$/ then 18 | lead, bracket, cl = $1, $2, $3 19 | right = line[col+1..-1] unless bracket.nil? 20 | if ENV.has_key?('TM_OBJC_MRR') 21 | print "#{e lead}${1/.+/[/}[[#{e cl} alloc] init$2]${1: autorelease]}" 22 | else 23 | print "#{e lead}[[#{e cl} alloc] init$1]" 24 | end 25 | print right.empty? ? ";" : "#{e right}" 26 | else 27 | # this is only if we were not able to interpret the line 28 | print "#{e left}$0#{e right}" 29 | end 30 | 31 | fallbackInput 32 | line 33 | input 34 | selection 35 | name 36 | Insert [[… alloc] init] 37 | output 38 | insertAsSnippet 39 | scope 40 | source.objc, source.objc++ 41 | tabTrigger 42 | alloc 43 | uuid 44 | EA820F17-FD1D-4E7A-9961-E75F7D360968 45 | 46 | 47 | -------------------------------------------------------------------------------- /Preferences/Cocoa completions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Completions: Cocoa 7 | scope 8 | source.objc, source.objc++ 9 | settings 10 | 11 | completions 12 | 13 | retain 14 | release 15 | autorelease 16 | description 17 | stringWithFormat: 18 | componentsSeparatedByString: 19 | componentsJoinedByString: 20 | isEqualToString: 21 | UTF8String 22 | lastPathComponent 23 | pathExtension 24 | stringByAbbreviatingWithTildeInPath 25 | stringByAppendingPathComponent: 26 | stringByAppendingPathExtension: 27 | stringByDeletingLastPathComponent 28 | stringByDeletingPathExtension 29 | stringByExpandingTildeInPath 30 | stringByResolvingSymlinksInPath 31 | stringByStandardizingPath 32 | valueForKey: 33 | valueForKeyPath: 34 | setValue: 35 | forKey: 36 | forKeyPath: 37 | NSArray 38 | NSDictionary 39 | NSMutableArray 40 | NSMutableDictionary 41 | NSMutableString 42 | NSString 43 | 44 | 45 | uuid 46 | 512175CE-933E-4312-BBF2-D744700CB4CA 47 | 48 | 49 | -------------------------------------------------------------------------------- /Preferences/Folding.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Folding 7 | scope 8 | source.objc++, source.objc 9 | settings 10 | 11 | foldingStartMarker 12 | (?x) 13 | /\*\*(?!\*) 14 | |^(?![^{]*?//|[^{]*?/\*(?!.*?\*/.*?\{)).*?\{\s*($|//|/\*(?!.*?\*/.*\S)) 15 | |^@(interface|protocol|implementation)\b (?!.*;) 16 | 17 | foldingStopMarker 18 | (?<!\*)\*\*/|^\s*\}|^@end\b 19 | 20 | uuid 21 | 1366A19B-083A-4DB1-BD93-3FD9104B5028 22 | 23 | 24 | -------------------------------------------------------------------------------- /Preferences/Highlight Pairs: Protocol Specifiers.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Highlight Pairs: Protocol Specifiers 7 | scope 8 | meta.protocol-list.objc | meta.inherited-protocol.end.objc | meta.return-type.objc | meta.argument-type.objc 9 | settings 10 | 11 | highlightPairs 12 | 13 | 14 | < 15 | > 16 | 17 | 18 | ( 19 | ) 20 | 21 | 22 | 23 | uuid 24 | 0D675D9D-B93C-400D-B8D6-C9888F7FAAE4 25 | 26 | 27 | -------------------------------------------------------------------------------- /Preferences/Symbol List.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List: Method 7 | scope 8 | meta.function.objc 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 15 | s/^([-+])\s*\(.*?\)\s*/ $1 /; # strip result type 16 | s/:\s*\(.*?\)\s*\w+\s*/:/g; # strip argument variables 17 | s/\s*;?$//g; # strip terminating ws + semi-colon 18 | 19 | 20 | uuid 21 | ADFCD53A-3CC4-4C31-88C4-BB607684951A 22 | 23 | 24 | -------------------------------------------------------------------------------- /Preferences/Typing Pairs: Protocol Specifier.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Typing Pairs: Protocol Specifier 7 | scope 8 | (meta.interface-or-protocol.objc | meta.return-type.objc | meta.argument-type.objc) - meta.protocol-list.objc 9 | settings 10 | 11 | smartTypingPairs 12 | 13 | 14 | < 15 | > 16 | 17 | 18 | ( 19 | ) 20 | 21 | 22 | 23 | uuid 24 | C41409C1-97FD-4326-A8E9-7BF89ED6BEAF 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.mdown: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | You can install this bundle in TextMate by opening the preferences and going to the bundles tab. After installation it will be automatically updated for you. 4 | 5 | # General 6 | 7 | * [Bundle Styleguide](http://kb.textmate.org/bundle_styleguide) — _before you make changes_ 8 | * [Commit Styleguide](http://kb.textmate.org/commit_styleguide) — _before you send a pull request_ 9 | * [Writing Bug Reports](http://kb.textmate.org/writing_bug_reports) — _before you report an issue_ 10 | 11 | # License 12 | 13 | If not otherwise specified (see below), files in this repository fall under the following license: 14 | 15 | Permission to copy, use, modify, sell and distribute this 16 | software is granted. This software is provided "as is" without 17 | express or implied warranty, and with no claim as to its 18 | suitability for any purpose. 19 | 20 | An exception is made for files in readable text which contain their own license information, or files where an accompanying file exists (in the same directory) with a “-license” suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example “tidy” is accompanied by “tidy-license.txt”. -------------------------------------------------------------------------------- /Snippets/#import "" (imp).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | #import "${1:${TM_FILENAME/\...*$/.h/}}" 7 | name 8 | #import "…" 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | imp 13 | uuid 14 | 1E3A92DA-7299-11D9-813A-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/#import <> (Imp).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | #import <${1:Cocoa/Cocoa.h}> 7 | name 8 | #import <…> 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | Imp 13 | uuid 14 | 20241464-7299-11D9-813A-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/020 Class (objc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @interface ${1:${TM_FILENAME/\...*$|(^$)/(?1:object)/}} : ${2:NSObject} 7 | { 8 | } 9 | @end 10 | 11 | @implementation $1 12 | - (instancetype)init 13 | { 14 | if(self = [super init]) 15 | {$0 16 | } 17 | return self; 18 | } 19 | @end 20 | name 21 | Class 22 | scope 23 | source.objc, source.objc++ - meta.scope.implementation.objc 24 | tabTrigger 25 | cl 26 | uuid 27 | BC8B9C24-5F16-11D9-B9C3-000D93589AF6 28 | 29 | 30 | -------------------------------------------------------------------------------- /Snippets/030 NSArray (array).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSMutableArray${TM_C_POINTER: *}${1:array} = [NSMutableArray array]; 7 | name 8 | NSArray 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | array 13 | uuid 14 | BC8B9CAD-5F16-11D9-B9C3-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/040 NSDictionary (dict).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSMutableDictionary${TM_C_POINTER: *}${1:dict} = [NSMutableDictionary dictionary]; 7 | name 8 | NSDictionary 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | dict 13 | uuid 14 | BC8B9D3A-5F16-11D9-B9C3-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/050 Method (m).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:id})${2:${TM_SELECTED_TEXT:method}}${3::(${4:id})${5:${4/(NS([AEIOQUY])?(\w+).*)|(.)?.*/(?1:a(?2:n$2)$3:(?4:anArgument))/}}} 7 | {$0${1/^(void|IBAction)$|(.*)/${2:+ 8 | return nil;}/} 9 | } 10 | keyEquivalent 11 | ^M 12 | name 13 | Method 14 | scope 15 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 16 | tabTrigger 17 | m 18 | uuid 19 | BC8B9DD7-5F16-11D9-B9C3-000D93589AF6 20 | 21 | 22 | -------------------------------------------------------------------------------- /Snippets/060 SubMethod (sm).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:id})${2:method}${3::(${4:id})${5:${4/(NS([AEIOQUY])?(\w+).*)|(.)?.*/(?1:a(?2:n$2)$3:(?4:anArgument))/}}} 7 | { 8 | ${1/^(void|IBAction)$|(.*)/(?2:$2 res = )/}[super ${2:method}${5/.+/:$0/}];$0${1/^(void|IBAction)$|(.*)/(?2: 9 | return res;)/} 10 | } 11 | name 12 | Sub-method (Call Super) 13 | scope 14 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 15 | tabTrigger 16 | sm 17 | uuid 18 | BC8B9E72-5F16-11D9-B9C3-000D93589AF6 19 | 20 | 21 | -------------------------------------------------------------------------------- /Snippets/@selector.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @selector(${1:method:}) 7 | name 8 | @selector(…) 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | sel 13 | uuid 14 | 7829F2EC-B8BA-11D9-AE51-000393A143CC 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Category (cat).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @interface ${1:${TM_FILENAME/.*?(\w+).*|.*/(?1:$1:NSObject)/}} (${2:${TM_FILENAME/.*?\w+\W+(\w+).*\..+|.*/(?1:$1:Category)/}}) 7 | @end 8 | 9 | @implementation $1 ($2) 10 | $0 11 | @end 12 | name 13 | Category 14 | scope 15 | source.objc, source.objc++ 16 | tabTrigger 17 | cat 18 | uuid 19 | 27AC6270-9900-11D9-9BB8-000A95A89C98 20 | 21 | 22 | -------------------------------------------------------------------------------- /Snippets/Category Implementation.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @implementation ${1:${TM_FILENAME/.*?(\w+).*|.*/(?1:$1:NSObject)/}} (${2:${TM_FILENAME/.*?\w+\W+(\w+).*\..+|.*/(?1:$1:Category)/}}) 7 | $0 8 | @end 9 | name 10 | Category Implementation 11 | scope 12 | source.objc, source.objc++ 13 | tabTrigger 14 | catm 15 | uuid 16 | 3E270C37-E7E2-4D1D-B28F-CEDD8DE0041C 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/Category Interface Only (cati).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @interface ${1:${TM_FILENAME/.*?(\w+).*|.*/(?1:$1:NSObject)/}} (${2:${TM_FILENAME/.*?\w+\W+(\w+).*\..+|.*/(?1:$1:Category)/}}) 7 | $0 8 | @end 9 | name 10 | Category Interface 11 | scope 12 | source.objc, source.objc++ 13 | tabTrigger 14 | cath 15 | uuid 16 | 596B13EC-9900-11D9-9BB8-000A95A89C98 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/Class Implementation.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @implementation ${1:${TM_FILENAME/\...*$|(^$)/(?1:object)/}} 7 | - (instancetype)init 8 | { 9 | if(self = [super init]) 10 | {$0 11 | } 12 | return self; 13 | } 14 | @end 15 | name 16 | Class Implementation 17 | scope 18 | source.objc, source.objc++ 19 | tabTrigger 20 | clm 21 | uuid 22 | BE0B2832-D88E-40BF-93EE-281DDA93840B 23 | 24 | 25 | -------------------------------------------------------------------------------- /Snippets/Class Interface Only (classi).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @interface ${1:${TM_FILENAME/\...*$|(^$)/(?1:object)/}} : ${2:NSObject} 7 | {$3 8 | } 9 | $0 10 | @end 11 | name 12 | Class Interface 13 | scope 14 | source.objc, source.objc++ 15 | tabTrigger 16 | clh 17 | uuid 18 | 06F15373-9900-11D9-9BB8-000A95A89C98 19 | 20 | 21 | -------------------------------------------------------------------------------- /Snippets/Class Method (M).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | + (${1:id})${2:method}${3::(${4:id})${5:${4/(NS([AEIOQUY])?(\w+).*)|(.)?.*/(?1:a(?2:n$2)$3:(?4:anArgument))/}}} 7 | {$0${1/^(void|IBAction)$|(.*)/(?2: 8 | return nil;)/} 9 | } 10 | name 11 | Class Method 12 | scope 13 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 14 | tabTrigger 15 | M 16 | uuid 17 | 1251B9E2-6BF0-11D9-8384-000D93589AF6 18 | 19 | 20 | -------------------------------------------------------------------------------- /Snippets/Class Method Interface (M).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | + (${1:id})${0:method}; 7 | name 8 | Interface: Class Method 9 | scope 10 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 11 | tabTrigger 12 | M 13 | uuid 14 | 9D01148D-1073-40D2-936E-FFF67580D2B3 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/CoreData Accessors Implementation.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:id})${2:attribute} 7 | { 8 | [self willAccessValueForKey:@"${2: attribute}"]; 9 | ${1:id} value = [self primitiveValueForKey:@"${2: attribute}"]; 10 | [self didAccessValueForKey:@"${2: attribute}"]; 11 | return value; 12 | } 13 | 14 | - (void)set${2/./\u$0/}:($1)aValue 15 | { 16 | [self willChangeValueForKey:@"${2: attribute}"]; 17 | [self setPrimitiveValue:aValue forKey:@"${2: attribute}"]; 18 | [self didChangeValueForKey:@"${2: attribute}"]; 19 | } 20 | name 21 | CoreData 22 | scope 23 | source.objc, source.objc++ 24 | tabTrigger 25 | cdacc 26 | uuid 27 | 563B2FDB-A163-46FE-9380-4178EFC1AD14 28 | 29 | 30 | -------------------------------------------------------------------------------- /Snippets/Delegate Responds to Selector.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | if([${1:[self delegate]} respondsToSelector:@selector(${2:selfDidSomething:})]) 7 | [$1 ${3:${2/((^\s*([A-Za-z0-9_]*:)\s*)|(:\s*$)|(:\s*))/(?2:$2self :\:<>)(?4::)(?5: :)/g}}]; 8 | 9 | name 10 | Delegate Responds to Selector 11 | scope 12 | source.objc, source.objc++ 13 | tabTrigger 14 | delegate 15 | uuid 16 | 622842E6-11F7-4D7B-A322-F1B8A1FE8CE5 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/Detach New NSThread.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [NSThread detachNewThreadSelector:@selector(${1:method}:) toTarget:${2:aTarget} withObject:${3:anArgument}] 7 | name 8 | Detach New NSThread 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | thread 13 | uuid 14 | 25AD69B4-905B-4EBC-A3B3-0BAB6D8BDD75 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/For Loop.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | for(NSUInteger ${2:i} = 0; $2 < ${1:count}; ${3:++$2}) 7 | { 8 | ${0:/* code */} 9 | } 10 | name 11 | For Loop 12 | scope 13 | source.objc, source.objc++ 14 | tabTrigger 15 | for 16 | uuid 17 | 7AB60FCF-822A-4D74-A7C4-1B6A724DD669 18 | 19 | 20 | -------------------------------------------------------------------------------- /Snippets/IBOutlet (ibo).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | IBOutlet ${1:NSSomeClass}${TM_C_POINTER: *}${2:${1/^[A-Z](?:[A-Z]+|[a-z]+)([A-Z]\w*)/\l$1/}}; 7 | name 8 | IBOutlet 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | ibo 13 | uuid 14 | 30C260A7-AFB1-11D9-9D48-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Initialize Implementation (I).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | + (void)initialize 7 | { 8 | [[NSUserDefaults standardUserDefaults] registerDefaults:@{ 9 | $0@"key" : @"value", 10 | }]; 11 | } 12 | name 13 | Method: Initialize 14 | scope 15 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 16 | tabTrigger 17 | I 18 | uuid 19 | 366DBAB0-554B-4A38-966E-793DFE13A1EC 20 | 21 | 22 | -------------------------------------------------------------------------------- /Snippets/Key:value binding (bind).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | bind:@"${2:binding}" toObject:${3:observableController} withKeyPath:@"${4:keyPath}" options:${5:nil} 7 | name 8 | Bind Property to Key Path of Object 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | bind 13 | uuid 14 | 59FC2842-A645-11D9-B2CB-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/LoD array (arracc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (void)addObjectTo${1:Things}:(${2:id})anObject 7 | { 8 | [${3:${1/./\l$0/}} addObject:anObject]; 9 | } 10 | 11 | - (void)insertObject:($2)anObject in$1AtIndex:(NSUInteger)idx 12 | { 13 | [$3 insertObject:anObject atIndex:idx]; 14 | } 15 | 16 | - ($2)objectIn$1AtIndex:(NSUInteger)idx 17 | { 18 | return [$3 objectAtIndex:idx]; 19 | } 20 | 21 | - (NSUInteger)indexOfObjectIn$1:($2)anObject 22 | { 23 | return [$3 indexOfObject:anObject]; 24 | } 25 | 26 | - (void)removeObjectFrom$1AtIndex:(NSUInteger)idx 27 | { 28 | [$3 removeObjectAtIndex:idx]; 29 | } 30 | 31 | - (NSUInteger)countOf$1 32 | { 33 | return [$3 count]; 34 | } 35 | 36 | - (NSArray${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})${1/./\l$0/} 37 | { 38 | return $3; 39 | } 40 | 41 | - (void)set$1:(NSArray${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})new$1 42 | { 43 | [$3 setArray:new$1]; 44 | } 45 | name 46 | KVC Array 47 | scope 48 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 49 | tabTrigger 50 | arracc 51 | uuid 52 | DECC6BAC-94AF-429A-8609-D101C940D18D 53 | 54 | 55 | -------------------------------------------------------------------------------- /Snippets/LoD array interface (arracc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (void)addObjectTo${1:Things}:(${2:id})anObject; 7 | - (void)insertObject:($2)anObject in$1AtIndex:(unsigned int)i; 8 | - ($2)objectIn$1AtIndex:(unsigned int)i; 9 | - (unsigned int)indexOfObjectIn$1:($2)anObject; 10 | - (void)removeObjectFrom$1AtIndex:(unsigned int)i; 11 | - (unsigned int)countOf$1; 12 | - (NSArray${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})${1/./\l$0/}; 13 | - (void)set$1:(NSArray${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})new$1; 14 | name 15 | Interface: Accessors for KVC Array 16 | scope 17 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 18 | tabTrigger 19 | arracc 20 | uuid 21 | C125E6DB-7FB5-4B19-8648-0A5617B1B5BC 22 | 23 | 24 | -------------------------------------------------------------------------------- /Snippets/Lock Focus.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [self lockFocus]; 7 | $0 8 | [self unlockFocus]; 9 | name 10 | Lock Focus 11 | scope 12 | source.objc, source.objc++ 13 | tabTrigger 14 | focus 15 | uuid 16 | 3F57DB1B-9373-46A6-9B6E-19F2D25658DE 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/Method Interface (m).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:id})${2:${TM_SELECTED_TEXT:method}}${3::(${4:id})${5:${4/(NS([AEIOQUY])?(\w+).*)|(.)?.*/(?1:a(?2:n$2)$3:(?4:anArgument))/}}}; 7 | keyEquivalent 8 | ^M 9 | name 10 | Interface: Method 11 | scope 12 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 13 | tabTrigger 14 | m 15 | uuid 16 | 325B0A2B-5939-4805-80A1-6DED5B373283 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/NSAutoreleasePool (pool).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @autoreleasepool { 7 | $0 8 | } 9 | name 10 | Autorelease Pool 11 | scope 12 | source.objc, source.objc++ 13 | tabTrigger 14 | pool 15 | uuid 16 | D402B10A-149B-414D-9961-110880389A8E 17 | 18 | 19 | -------------------------------------------------------------------------------- /Snippets/NSBezierPath (bez).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSBezierPath${TM_C_POINTER: *}${1:path} = [NSBezierPath bezierPath]; 7 | name 8 | NSBezierPath 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | bez 13 | uuid 14 | 917BA9ED-9A62-11D9-9A65-000A95A89C98 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/NSLog (log) 2.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSLog(@"$1"${1/[^%]*(%)?.*/(?1:, :\);)/}$2${1/[^%]*(%)?.*/(?1:\);)/} 7 | name 8 | NSLog(…) 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | log 13 | uuid 14 | 1251B7E8-6BF0-11D9-8384-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/NSLog(.., _cmd) (log).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSLog(@"%s$1", sel_getName(_cmd)${1/[^%]*(%)?.*/(?1:, :\);)/}$2${1/[^%]*(%)?.*/(?1:\);)/} 7 | name 8 | NSLog(.., _cmd) 9 | scope 10 | source.objc meta.scope.implementation, source.objc++ meta.scope.implementation 11 | tabTrigger 12 | log 13 | uuid 14 | A3555C49-D367-4CF5-8032-13B291820CD3 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/NSRunAlertPanel (alert).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | NSAlert* alert = [[NSAlert alloc] init]; 7 | alert.messageText = @"${1:Something important!}"; 8 | alert.informativeText = @"${2:Something important just happend, and now I need to ask you, do you want to continue?}"; 9 | for(NSString* title in @[ @"${3:Continue}", @"${4:Cancel}" ]) 10 | [alert addButtonWithTitle:title]; 11 | 12 | NSInteger choice = [alert runModal]; 13 | if(choice == NSAlertFirstButtonReturn) // “${3:Continue}” 14 | { 15 | $0; 16 | } 17 | else if(choice == NSAlertSecondButtonReturn) // “${4:Cancel}” 18 | { 19 | ; 20 | } 21 | name 22 | NSAlert runModal 23 | scope 24 | source.objc, source.objc++ 25 | tabTrigger 26 | alert 27 | uuid 28 | 9EF84198-BDAF-11D9-9140-000D93589AF6 29 | 30 | 31 | -------------------------------------------------------------------------------- /Snippets/NSString stringWithFormat (format).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [NSString stringWithFormat:@"$1", $2] 7 | name 8 | NSString With Format 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | format 13 | uuid 14 | B07879C7-F1E0-4606-93F1-1A948965CD0E 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Object Accessors Interface (objacc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:id})${2:thing}; 7 | - (void)set${2/./\u$0/}:($1)aValue; 8 | name 9 | Interface: Accessors for Object 10 | scope 11 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 12 | tabTrigger 13 | objacc 14 | uuid 15 | 013BFEBB-A744-46F1-94A5-F851635E00FA 16 | 17 | 18 | -------------------------------------------------------------------------------- /Snippets/Property.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @property (${2:nonatomic${1/.+/, /}}${1|readonly,weak,copy,class|}) ${3:NSSomeClass}${3/^((?!NS(U?Integer|Point|Size|Rect)|C[GF]|BOOL|SEL)[A-Z]\w*)|.*/${1:?${TM_C_POINTER: *}: }/}${4:${3/^(?:(BOOL)|(SEL)|[A-Z](?:[A-Z]+|[a-z]+)([A-Z]\w*))/${1:?flag:${2:?action:\l$3}}/}}; 7 | name 8 | Property 9 | scope 10 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 11 | tabTrigger 12 | prop 13 | uuid 14 | EE603767-8BA3-4F54-8DE5-0C9E64BE5DF7 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Protocol.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @protocol ${1:${2:${TM_FILENAME:?${TM_FILENAME/\..+$//}:My}}Delegate}${3: <NSObject>} 7 | $0 8 | @optional 9 | @end 10 | name 11 | Protocol 12 | scope 13 | source.objc, source.objc++ 14 | tabTrigger 15 | pro 16 | uuid 17 | B638A0D2-1B84-4932-99D4-3134230C3EC8 18 | 19 | 20 | -------------------------------------------------------------------------------- /Snippets/Read from defaults (getprefs).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [[NSUserDefaults standardUserDefaults] ${1|objectForKey,arrayForKey,boolForKey,dataForKey,dictionaryForKey,doubleForKey,floatForKey,integerForKey,stringForKey,stringArrayForKey,URLForKey|}:${2:key}]; 7 | name 8 | Read Defaults Value 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | getprefs 13 | uuid 14 | 3EF96A1F-B597-11D9-A114-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Register for Notification.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [[NSNotificationCenter defaultCenter] addObserver:${1:self} selector:@selector(${3:${2/^([A-Z]{2})?(.+?)(Notification)?$/\l$2/}}:) name:${2:NSWindowDidBecomeMainNotification} object:${4:nil}]; 7 | name 8 | Register for Notification 9 | scope 10 | source.objc meta.scope.implementation, source.objc++ meta.scope.implementation 11 | tabTrigger 12 | obs 13 | uuid 14 | E8107901-70F1-45D9-8633-81BD5E57CC89 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Responds to Selector.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | ${TM_COMMENT_START} ${4:Send $2 to $1, if $1 supports it}${TM_COMMENT_END} 7 | if([${1:self} respondsToSelector:@selector(${2:someSelector:})]) 8 | { 9 | [$1 ${3:${2/((:\s*$)|(:\s*))/:<>(?3: )/g}}]; 10 | } 11 | name 12 | Responds to Selector 13 | scope 14 | source.objc, source.objc++ 15 | tabTrigger 16 | responds 17 | uuid 18 | 171FBCAE-0D6F-4D42-B24F-871E3BB6DFF0 19 | 20 | 21 | -------------------------------------------------------------------------------- /Snippets/Save and Restore Graphics Context (gsave).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [NSGraphicsContext saveGraphicsState]; 7 | $0 8 | [NSGraphicsContext restoreGraphicsState]; 9 | 10 | name 11 | Save and Restore Graphics Context 12 | scope 13 | source.objc, source.objc++ 14 | tabTrigger 15 | gsave 16 | uuid 17 | F2D5B215-2C10-40BC-B973-0A859A3E3CBD 18 | 19 | 20 | -------------------------------------------------------------------------------- /Snippets/Scalar Accessors (acc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1|BOOL,NSInteger,NSUInteger,NSArray*,NSDictionary*,NSString*|})${2:property} 7 | { 8 | return ${3:_$2}; 9 | } 10 | 11 | - (void)set${2/./\u$0/}:(${1})new${2/./\u$0/} 12 | { 13 | $3 = new${2/./\u$0/}; 14 | } 15 | name 16 | Type 17 | scope 18 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 19 | tabTrigger 20 | acc 21 | uuid 22 | DADC6C91-415F-463A-9C24-7A059BB5EE56 23 | 24 | 25 | -------------------------------------------------------------------------------- /Snippets/Scalar Accessors Interface (acc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (${1:unsigned int})${2:thing}; 7 | - (void)set${2/./\u$0/}:($1)new${2/./\u$0/}; 8 | name 9 | Interface: Accessors for Primitive Type 10 | scope 11 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 12 | tabTrigger 13 | acc 14 | uuid 15 | BA432891-294B-47A4-BECF-F3C95B3766C1 16 | 17 | 18 | -------------------------------------------------------------------------------- /Snippets/String Accessors Interface (stracc).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | - (NSString${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})${1:thing}; 7 | - (void)set${1/./\u$0/}:(NSString${TM_C_POINTER/(^(.+?)\s*$)?/(?1:$2: *)/})${2:a${1/.*/\u$0/}}; 8 | name 9 | Interface: Accessors for String 10 | scope 11 | source.objc meta.scope.interface, source.objc++ meta.scope.interface 12 | tabTrigger 13 | stracc 14 | uuid 15 | 35EB2F86-DEA0-443B-8DC2-4815F0478F67 16 | 17 | 18 | -------------------------------------------------------------------------------- /Snippets/Synthesize.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @synthesize ${1:property}; 7 | name 8 | Synthesize Property 9 | scope 10 | (source.objc | source.objc++) & meta.scope.implementation.objc - meta.function-with-body 11 | tabTrigger 12 | syn 13 | uuid 14 | C0B942C9-07CE-46B6-8FAE-CB8496F9F544 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Write to defaults (setprefs).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | [[NSUserDefaults standardUserDefaults] ${1|setObject,setBool,setDouble,setFloat,setInteger,setURL|}:${2:object} forKey:${3:key}]; 7 | name 8 | Write Defaults Value 9 | scope 10 | source.objc, source.objc++ 11 | tabTrigger 12 | setprefs 13 | uuid 14 | 53672612-B597-11D9-A114-000D93589AF6 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/for(… in …).tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | for(${1:id} ${2:item} in ${3:array}) 7 | { 8 | $0 9 | } 10 | name 11 | for(… in …) 12 | scope 13 | source.objc, source.objc++ 14 | tabTrigger 15 | forin 16 | uuid 17 | B47D188C-C0F7-4C53-A6ED-9EFE09371F37 18 | 19 | 20 | -------------------------------------------------------------------------------- /Support/CocoaAnnotatedStrings.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaAnnotatedStrings.txt.gz -------------------------------------------------------------------------------- /Support/CocoaAnonymousEnums.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaAnonymousEnums.txt.gz -------------------------------------------------------------------------------- /Support/CocoaClasses.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaClasses.txt.gz -------------------------------------------------------------------------------- /Support/CocoaClassesWithAncestry.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaClassesWithAncestry.txt.gz -------------------------------------------------------------------------------- /Support/CocoaClassesWithFramework.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaClassesWithFramework.txt.gz -------------------------------------------------------------------------------- /Support/CocoaConstants.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaConstants.txt.gz -------------------------------------------------------------------------------- /Support/CocoaFunctions.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaFunctions.txt.gz -------------------------------------------------------------------------------- /Support/CocoaMethods.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaMethods.txt.gz -------------------------------------------------------------------------------- /Support/CocoaNotifications.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaNotifications.txt.gz -------------------------------------------------------------------------------- /Support/CocoaProtocols.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaProtocols.txt.gz -------------------------------------------------------------------------------- /Support/CocoaTypes.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/objective-c.tmbundle/d59562b0948d4dae01eaee1a2b2bcde3b478404e/Support/CocoaTypes.txt.gz -------------------------------------------------------------------------------- /Support/CppReferenceWiki.tsf: -------------------------------------------------------------------------------- 1 | accumulate std::accumulate http://www.cppreference.com/wiki/stl/algorithm/accumulate 2 | adjacent_difference std::adjacent_difference http://www.cppreference.com/wiki/stl/algorithm/adjacent_difference 3 | adjacent_find std::adjacent_find http://www.cppreference.com/wiki/stl/algorithm/adjacent_find 4 | binary_search std::binary_search http://www.cppreference.com/wiki/stl/algorithm/binary_search 5 | copy std::copy http://www.cppreference.com/wiki/stl/algorithm/copy 6 | copy_backward std::copy_backward http://www.cppreference.com/wiki/stl/algorithm/copy_backward 7 | copy_n std::copy_n http://www.cppreference.com/wiki/stl/algorithm/copy_n 8 | count std::count http://www.cppreference.com/wiki/stl/algorithm/count 9 | count_if std::count_if http://www.cppreference.com/wiki/stl/algorithm/count_if 10 | equal std::equal http://www.cppreference.com/wiki/stl/algorithm/equal 11 | equal_range std::equal_range http://www.cppreference.com/wiki/stl/algorithm/equal_range 12 | fill std::fill http://www.cppreference.com/wiki/stl/algorithm/fill 13 | fill_n std::fill_n http://www.cppreference.com/wiki/stl/algorithm/fill_n 14 | find std::find http://www.cppreference.com/wiki/stl/algorithm/find 15 | find_end std::find_end http://www.cppreference.com/wiki/stl/algorithm/find_end 16 | find_first_of std::find_first_of http://www.cppreference.com/wiki/stl/algorithm/find_first_of 17 | find_if std::find_if http://www.cppreference.com/wiki/stl/algorithm/find_if 18 | for_each std::for_each http://www.cppreference.com/wiki/stl/algorithm/for_each 19 | generate std::generate http://www.cppreference.com/wiki/stl/algorithm/generate 20 | generate_n std::generate_n http://www.cppreference.com/wiki/stl/algorithm/generate_n 21 | includes std::includes http://www.cppreference.com/wiki/stl/algorithm/includes 22 | inner_product std::inner_product http://www.cppreference.com/wiki/stl/algorithm/inner_product 23 | inplace_merge std::inplace_merge http://www.cppreference.com/wiki/stl/algorithm/inplace_merge 24 | is_heap std::is_heap http://www.cppreference.com/wiki/stl/algorithm/is_heap 25 | iter_swap std::iter_swap http://www.cppreference.com/wiki/stl/algorithm/iter_swap 26 | lexicographical_compare std::lexicographical_compare http://www.cppreference.com/wiki/stl/algorithm/lexicographical_compare 27 | lexicographical_compare_3way std::lexicographical_compare_3way http://www.cppreference.com/wiki/stl/algorithm/lexicographical_compare_3way 28 | lower_bound std::lower_bound http://www.cppreference.com/wiki/stl/algorithm/lower_bound 29 | make_heap std::make_heap http://www.cppreference.com/wiki/stl/algorithm/make_heap 30 | max std::max http://www.cppreference.com/wiki/stl/algorithm/max 31 | max_element std::max_element http://www.cppreference.com/wiki/stl/algorithm/max_element 32 | merge std::merge http://www.cppreference.com/wiki/stl/algorithm/merge 33 | min std::min http://www.cppreference.com/wiki/stl/algorithm/min 34 | min_element std::min_element http://www.cppreference.com/wiki/stl/algorithm/min_element 35 | mismatch std::mismatch http://www.cppreference.com/wiki/stl/algorithm/mismatch 36 | next_permutation std::next_permutation http://www.cppreference.com/wiki/stl/algorithm/next_permutation 37 | nth_element std::nth_element http://www.cppreference.com/wiki/stl/algorithm/nth_element 38 | partial_sort std::partial_sort http://www.cppreference.com/wiki/stl/algorithm/partial_sort 39 | partial_sort_copy std::partial_sort_copy http://www.cppreference.com/wiki/stl/algorithm/partial_sort_copy 40 | partial_sum std::partial_sum http://www.cppreference.com/wiki/stl/algorithm/partial_sum 41 | partition std::partition http://www.cppreference.com/wiki/stl/algorithm/partition 42 | pop_heap std::pop_heap http://www.cppreference.com/wiki/stl/algorithm/pop_heap 43 | prev_permutation std::prev_permutation http://www.cppreference.com/wiki/stl/algorithm/prev_permutation 44 | push_heap std::push_heap http://www.cppreference.com/wiki/stl/algorithm/push_heap 45 | random_sample std::random_sample http://www.cppreference.com/wiki/stl/algorithm/random_sample 46 | random_sample_n std::random_sample_n http://www.cppreference.com/wiki/stl/algorithm/random_sample_n 47 | random_shuffle std::random_shuffle http://www.cppreference.com/wiki/stl/algorithm/random_shuffle 48 | remove std::remove http://www.cppreference.com/wiki/stl/algorithm/remove 49 | remove_copy std::remove_copy http://www.cppreference.com/wiki/stl/algorithm/remove_copy 50 | remove_copy_if std::remove_copy_if http://www.cppreference.com/wiki/stl/algorithm/remove_copy_if 51 | remove_if std::remove_if http://www.cppreference.com/wiki/stl/algorithm/remove_if 52 | replace std::replace http://www.cppreference.com/wiki/stl/algorithm/replace 53 | replace_copy std::replace_copy http://www.cppreference.com/wiki/stl/algorithm/replace_copy 54 | replace_copy_if std::replace_copy_if http://www.cppreference.com/wiki/stl/algorithm/replace_copy_if 55 | replace_if std::replace_if http://www.cppreference.com/wiki/stl/algorithm/replace_if 56 | reverse std::reverse http://www.cppreference.com/wiki/stl/algorithm/reverse 57 | reverse_copy std::reverse_copy http://www.cppreference.com/wiki/stl/algorithm/reverse_copy 58 | rotate std::rotate http://www.cppreference.com/wiki/stl/algorithm/rotate 59 | rotate_copy std::rotate_copy http://www.cppreference.com/wiki/stl/algorithm/rotate_copy 60 | search std::search http://www.cppreference.com/wiki/stl/algorithm/search 61 | search_n std::search_n http://www.cppreference.com/wiki/stl/algorithm/search_n 62 | set_difference std::set_difference http://www.cppreference.com/wiki/stl/algorithm/set_difference 63 | set_intersection std::set_intersection http://www.cppreference.com/wiki/stl/algorithm/set_intersection 64 | set_symmetric_difference std::set_symmetric_difference http://www.cppreference.com/wiki/stl/algorithm/set_symmetric_difference 65 | set_union std::set_union http://www.cppreference.com/wiki/stl/algorithm/set_union 66 | sort std::sort http://www.cppreference.com/wiki/stl/algorithm/sort 67 | sort_heap std::sort_heap http://www.cppreference.com/wiki/stl/algorithm/sort_heap 68 | stable_partition std::stable_partition http://www.cppreference.com/wiki/stl/algorithm/stable_partition 69 | stable_sort std::stable_sort http://www.cppreference.com/wiki/stl/algorithm/stable_sort 70 | swap std::swap http://www.cppreference.com/wiki/stl/algorithm/swap 71 | swap_ranges std::swap_ranges http://www.cppreference.com/wiki/stl/algorithm/swap_ranges 72 | transform std::transform http://www.cppreference.com/wiki/stl/algorithm/transform 73 | unique std::unique http://www.cppreference.com/wiki/stl/algorithm/unique 74 | unique_copy std::unique_copy http://www.cppreference.com/wiki/stl/algorithm/unique_copy 75 | upper_bound std::upper_bound http://www.cppreference.com/wiki/stl/algorithm/upper_bound 76 | any std::bitset::any http://www.cppreference.com/wiki/stl/bitset/any 77 | bitset_constructors std::bitset::bitset_constructors http://www.cppreference.com/wiki/stl/bitset/bitset_constructors 78 | bitset_operators std::bitset::bitset_operators http://www.cppreference.com/wiki/stl/bitset/bitset_operators 79 | count std::bitset::count http://www.cppreference.com/wiki/stl/bitset/count 80 | flip std::bitset::flip http://www.cppreference.com/wiki/stl/bitset/flip 81 | none std::bitset::none http://www.cppreference.com/wiki/stl/bitset/none 82 | reset std::bitset::reset http://www.cppreference.com/wiki/stl/bitset/reset 83 | set std::bitset::set http://www.cppreference.com/wiki/stl/bitset/set 84 | size std::bitset::size http://www.cppreference.com/wiki/stl/bitset/size 85 | bitset std::bitset http://www.cppreference.com/wiki/stl/bitset/start 86 | test std::bitset::test http://www.cppreference.com/wiki/stl/bitset/test 87 | to_string std::bitset::to_string http://www.cppreference.com/wiki/stl/bitset/to_string 88 | to_ulong std::bitset::to_ulong http://www.cppreference.com/wiki/stl/bitset/to_ulong 89 | assign std::deque::assign http://www.cppreference.com/wiki/stl/deque/assign 90 | at std::deque::at http://www.cppreference.com/wiki/stl/deque/at 91 | back std::deque::back http://www.cppreference.com/wiki/stl/deque/back 92 | begin std::deque::begin http://www.cppreference.com/wiki/stl/deque/begin 93 | clear std::deque::clear http://www.cppreference.com/wiki/stl/deque/clear 94 | deque_constructors std::deque::deque_constructors http://www.cppreference.com/wiki/stl/deque/deque_constructors 95 | deque_operators std::deque::deque_operators http://www.cppreference.com/wiki/stl/deque/deque_operators 96 | empty std::deque::empty http://www.cppreference.com/wiki/stl/deque/empty 97 | end std::deque::end http://www.cppreference.com/wiki/stl/deque/end 98 | erase std::deque::erase http://www.cppreference.com/wiki/stl/deque/erase 99 | front std::deque::front http://www.cppreference.com/wiki/stl/deque/front 100 | insert std::deque::insert http://www.cppreference.com/wiki/stl/deque/insert 101 | max_size std::deque::max_size http://www.cppreference.com/wiki/stl/deque/max_size 102 | pop_back std::deque::pop_back http://www.cppreference.com/wiki/stl/deque/pop_back 103 | pop_front std::deque::pop_front http://www.cppreference.com/wiki/stl/deque/pop_front 104 | push_back std::deque::push_back http://www.cppreference.com/wiki/stl/deque/push_back 105 | push_front std::deque::push_front http://www.cppreference.com/wiki/stl/deque/push_front 106 | rbegin std::deque::rbegin http://www.cppreference.com/wiki/stl/deque/rbegin 107 | rend std::deque::rend http://www.cppreference.com/wiki/stl/deque/rend 108 | resize std::deque::resize http://www.cppreference.com/wiki/stl/deque/resize 109 | size std::deque::size http://www.cppreference.com/wiki/stl/deque/size 110 | deque std::deque http://www.cppreference.com/wiki/stl/deque/start 111 | swap std::deque::swap http://www.cppreference.com/wiki/stl/deque/swap 112 | binary_function std::functional::binary_function http://www.cppreference.com/wiki/stl/functional/binary_function 113 | binary_negate std::functional::binary_negate http://www.cppreference.com/wiki/stl/functional/binary_negate 114 | bind1st std::functional::bind1st http://www.cppreference.com/wiki/stl/functional/bind1st 115 | bind2nd std::functional::bind2nd http://www.cppreference.com/wiki/stl/functional/bind2nd 116 | binder1st std::functional::binder1st http://www.cppreference.com/wiki/stl/functional/binder1st 117 | binder2nd std::functional::binder2nd http://www.cppreference.com/wiki/stl/functional/binder2nd 118 | const_mem_fun1_ref_t std::functional::const_mem_fun1_ref_t http://www.cppreference.com/wiki/stl/functional/const_mem_fun1_ref_t 119 | const_mem_fun1_t std::functional::const_mem_fun1_t http://www.cppreference.com/wiki/stl/functional/const_mem_fun1_t 120 | const_mem_fun_ref_t std::functional::const_mem_fun_ref_t http://www.cppreference.com/wiki/stl/functional/const_mem_fun_ref_t 121 | const_mem_fun_t std::functional::const_mem_fun_t http://www.cppreference.com/wiki/stl/functional/const_mem_fun_t 122 | divides std::functional::divides http://www.cppreference.com/wiki/stl/functional/divides 123 | functional std::functional http://www.cppreference.com/wiki/stl/functional/start 124 | assign std::list::assign http://www.cppreference.com/wiki/stl/list/assign 125 | back std::list::back http://www.cppreference.com/wiki/stl/list/back 126 | begin std::list::begin http://www.cppreference.com/wiki/stl/list/begin 127 | clear std::list::clear http://www.cppreference.com/wiki/stl/list/clear 128 | empty std::list::empty http://www.cppreference.com/wiki/stl/list/empty 129 | end std::list::end http://www.cppreference.com/wiki/stl/list/end 130 | erase std::list::erase http://www.cppreference.com/wiki/stl/list/erase 131 | front std::list::front http://www.cppreference.com/wiki/stl/list/front 132 | insert std::list::insert http://www.cppreference.com/wiki/stl/list/insert 133 | list_constructors std::list::list_constructors http://www.cppreference.com/wiki/stl/list/list_constructors 134 | list_operators std::list::list_operators http://www.cppreference.com/wiki/stl/list/list_operators 135 | max_size std::list::max_size http://www.cppreference.com/wiki/stl/list/max_size 136 | merge std::list::merge http://www.cppreference.com/wiki/stl/list/merge 137 | pop_back std::list::pop_back http://www.cppreference.com/wiki/stl/list/pop_back 138 | pop_front std::list::pop_front http://www.cppreference.com/wiki/stl/list/pop_front 139 | push_back std::list::push_back http://www.cppreference.com/wiki/stl/list/push_back 140 | push_front std::list::push_front http://www.cppreference.com/wiki/stl/list/push_front 141 | rbegin std::list::rbegin http://www.cppreference.com/wiki/stl/list/rbegin 142 | remove std::list::remove http://www.cppreference.com/wiki/stl/list/remove 143 | remove_if std::list::remove_if http://www.cppreference.com/wiki/stl/list/remove_if 144 | rend std::list::rend http://www.cppreference.com/wiki/stl/list/rend 145 | resize std::list::resize http://www.cppreference.com/wiki/stl/list/resize 146 | reverse std::list::reverse http://www.cppreference.com/wiki/stl/list/reverse 147 | size std::list::size http://www.cppreference.com/wiki/stl/list/size 148 | sort std::list::sort http://www.cppreference.com/wiki/stl/list/sort 149 | splice std::list::splice http://www.cppreference.com/wiki/stl/list/splice 150 | list std::list http://www.cppreference.com/wiki/stl/list/start 151 | swap std::list::swap http://www.cppreference.com/wiki/stl/list/swap 152 | unique std::list::unique http://www.cppreference.com/wiki/stl/list/unique 153 | begin std::map::begin http://www.cppreference.com/wiki/stl/map/begin 154 | clear std::map::clear http://www.cppreference.com/wiki/stl/map/clear 155 | count std::map::count http://www.cppreference.com/wiki/stl/map/count 156 | empty std::map::empty http://www.cppreference.com/wiki/stl/map/empty 157 | end std::map::end http://www.cppreference.com/wiki/stl/map/end 158 | equal_range std::map::equal_range http://www.cppreference.com/wiki/stl/map/equal_range 159 | erase std::map::erase http://www.cppreference.com/wiki/stl/map/erase 160 | find std::map::find http://www.cppreference.com/wiki/stl/map/find 161 | insert std::map::insert http://www.cppreference.com/wiki/stl/map/insert 162 | key_comp std::map::key_comp http://www.cppreference.com/wiki/stl/map/key_comp 163 | lower_bound std::map::lower_bound http://www.cppreference.com/wiki/stl/map/lower_bound 164 | map_constructors std::map::map_constructors http://www.cppreference.com/wiki/stl/map/map_constructors 165 | map_operators std::map::map_operators http://www.cppreference.com/wiki/stl/map/map_operators 166 | map_typedefs std::map::map_typedefs http://www.cppreference.com/wiki/stl/map/map_typedefs 167 | max_size std::map::max_size http://www.cppreference.com/wiki/stl/map/max_size 168 | rbegin std::map::rbegin http://www.cppreference.com/wiki/stl/map/rbegin 169 | rend std::map::rend http://www.cppreference.com/wiki/stl/map/rend 170 | size std::map::size http://www.cppreference.com/wiki/stl/map/size 171 | map std::map http://www.cppreference.com/wiki/stl/map/start 172 | swap std::map::swap http://www.cppreference.com/wiki/stl/map/swap 173 | upper_bound std::map::upper_bound http://www.cppreference.com/wiki/stl/map/upper_bound 174 | value_comp std::map::value_comp http://www.cppreference.com/wiki/stl/map/value_comp 175 | auto_ptr std::memory::auto_ptr http://www.cppreference.com/wiki/stl/memory/auto_ptr 176 | memory std::memory http://www.cppreference.com/wiki/stl/memory/start 177 | begin std::multimap::begin http://www.cppreference.com/wiki/stl/multimap/begin 178 | clear std::multimap::clear http://www.cppreference.com/wiki/stl/multimap/clear 179 | count std::multimap::count http://www.cppreference.com/wiki/stl/multimap/count 180 | empty std::multimap::empty http://www.cppreference.com/wiki/stl/multimap/empty 181 | end std::multimap::end http://www.cppreference.com/wiki/stl/multimap/end 182 | equal_range std::multimap::equal_range http://www.cppreference.com/wiki/stl/multimap/equal_range 183 | erase std::multimap::erase http://www.cppreference.com/wiki/stl/multimap/erase 184 | find std::multimap::find http://www.cppreference.com/wiki/stl/multimap/find 185 | insert std::multimap::insert http://www.cppreference.com/wiki/stl/multimap/insert 186 | key_comp std::multimap::key_comp http://www.cppreference.com/wiki/stl/multimap/key_comp 187 | lower_bound std::multimap::lower_bound http://www.cppreference.com/wiki/stl/multimap/lower_bound 188 | max_size std::multimap::max_size http://www.cppreference.com/wiki/stl/multimap/max_size 189 | multimap_constructors std::multimap::multimap_constructors http://www.cppreference.com/wiki/stl/multimap/multimap_constructors 190 | multimap_operators std::multimap::multimap_operators http://www.cppreference.com/wiki/stl/multimap/multimap_operators 191 | rbegin std::multimap::rbegin http://www.cppreference.com/wiki/stl/multimap/rbegin 192 | rend std::multimap::rend http://www.cppreference.com/wiki/stl/multimap/rend 193 | size std::multimap::size http://www.cppreference.com/wiki/stl/multimap/size 194 | multimap std::multimap http://www.cppreference.com/wiki/stl/multimap/start 195 | swap std::multimap::swap http://www.cppreference.com/wiki/stl/multimap/swap 196 | upper_bound std::multimap::upper_bound http://www.cppreference.com/wiki/stl/multimap/upper_bound 197 | value_comp std::multimap::value_comp http://www.cppreference.com/wiki/stl/multimap/value_comp 198 | begin std::multiset::begin http://www.cppreference.com/wiki/stl/multiset/begin 199 | clear std::multiset::clear http://www.cppreference.com/wiki/stl/multiset/clear 200 | count std::multiset::count http://www.cppreference.com/wiki/stl/multiset/count 201 | empty std::multiset::empty http://www.cppreference.com/wiki/stl/multiset/empty 202 | end std::multiset::end http://www.cppreference.com/wiki/stl/multiset/end 203 | equal_range std::multiset::equal_range http://www.cppreference.com/wiki/stl/multiset/equal_range 204 | erase std::multiset::erase http://www.cppreference.com/wiki/stl/multiset/erase 205 | find std::multiset::find http://www.cppreference.com/wiki/stl/multiset/find 206 | insert std::multiset::insert http://www.cppreference.com/wiki/stl/multiset/insert 207 | key_comp std::multiset::key_comp http://www.cppreference.com/wiki/stl/multiset/key_comp 208 | lower_bound std::multiset::lower_bound http://www.cppreference.com/wiki/stl/multiset/lower_bound 209 | max_size std::multiset::max_size http://www.cppreference.com/wiki/stl/multiset/max_size 210 | multiset_constructors std::multiset::multiset_constructors http://www.cppreference.com/wiki/stl/multiset/multiset_constructors 211 | multiset_operators std::multiset::multiset_operators http://www.cppreference.com/wiki/stl/multiset/multiset_operators 212 | rbegin std::multiset::rbegin http://www.cppreference.com/wiki/stl/multiset/rbegin 213 | rend std::multiset::rend http://www.cppreference.com/wiki/stl/multiset/rend 214 | size std::multiset::size http://www.cppreference.com/wiki/stl/multiset/size 215 | multiset std::multiset http://www.cppreference.com/wiki/stl/multiset/start 216 | swap std::multiset::swap http://www.cppreference.com/wiki/stl/multiset/swap 217 | upper_bound std::multiset::upper_bound http://www.cppreference.com/wiki/stl/multiset/upper_bound 218 | value_comp std::multiset::value_comp http://www.cppreference.com/wiki/stl/multiset/value_comp 219 | empty std::priority_queue::empty http://www.cppreference.com/wiki/stl/priority_queue/empty 220 | pop std::priority_queue::pop http://www.cppreference.com/wiki/stl/priority_queue/pop 221 | pqueue_constructors std::priority_queue::pqueue_constructors http://www.cppreference.com/wiki/stl/priority_queue/pqueue_constructors 222 | push std::priority_queue::push http://www.cppreference.com/wiki/stl/priority_queue/push 223 | size std::priority_queue::size http://www.cppreference.com/wiki/stl/priority_queue/size 224 | priority_queue std::priority_queue http://www.cppreference.com/wiki/stl/priority_queue/start 225 | top std::priority_queue::top http://www.cppreference.com/wiki/stl/priority_queue/top 226 | back std::queue::back http://www.cppreference.com/wiki/stl/queue/back 227 | empty std::queue::empty http://www.cppreference.com/wiki/stl/queue/empty 228 | front std::queue::front http://www.cppreference.com/wiki/stl/queue/front 229 | pop std::queue::pop http://www.cppreference.com/wiki/stl/queue/pop 230 | push std::queue::push http://www.cppreference.com/wiki/stl/queue/push 231 | queue_constructors std::queue::queue_constructors http://www.cppreference.com/wiki/stl/queue/queue_constructors 232 | size std::queue::size http://www.cppreference.com/wiki/stl/queue/size 233 | queue std::queue http://www.cppreference.com/wiki/stl/queue/start 234 | begin std::set::begin http://www.cppreference.com/wiki/stl/set/begin 235 | clear std::set::clear http://www.cppreference.com/wiki/stl/set/clear 236 | count std::set::count http://www.cppreference.com/wiki/stl/set/count 237 | empty std::set::empty http://www.cppreference.com/wiki/stl/set/empty 238 | end std::set::end http://www.cppreference.com/wiki/stl/set/end 239 | equal_range std::set::equal_range http://www.cppreference.com/wiki/stl/set/equal_range 240 | erase std::set::erase http://www.cppreference.com/wiki/stl/set/erase 241 | find std::set::find http://www.cppreference.com/wiki/stl/set/find 242 | insert std::set::insert http://www.cppreference.com/wiki/stl/set/insert 243 | key_comp std::set::key_comp http://www.cppreference.com/wiki/stl/set/key_comp 244 | lower_bound std::set::lower_bound http://www.cppreference.com/wiki/stl/set/lower_bound 245 | max_size std::set::max_size http://www.cppreference.com/wiki/stl/set/max_size 246 | rbegin std::set::rbegin http://www.cppreference.com/wiki/stl/set/rbegin 247 | rend std::set::rend http://www.cppreference.com/wiki/stl/set/rend 248 | set_constructors std::set::set_constructors http://www.cppreference.com/wiki/stl/set/set_constructors 249 | set_operators std::set::set_operators http://www.cppreference.com/wiki/stl/set/set_operators 250 | size std::set::size http://www.cppreference.com/wiki/stl/set/size 251 | set std::set http://www.cppreference.com/wiki/stl/set/start 252 | swap std::set::swap http://www.cppreference.com/wiki/stl/set/swap 253 | upper_bound std::set::upper_bound http://www.cppreference.com/wiki/stl/set/upper_bound 254 | value_comp std::set::value_comp http://www.cppreference.com/wiki/stl/set/value_comp 255 | empty std::stack::empty http://www.cppreference.com/wiki/stl/stack/empty 256 | pop std::stack::pop http://www.cppreference.com/wiki/stl/stack/pop 257 | push std::stack::push http://www.cppreference.com/wiki/stl/stack/push 258 | size std::stack::size http://www.cppreference.com/wiki/stl/stack/size 259 | stack_constructors std::stack::stack_constructors http://www.cppreference.com/wiki/stl/stack/stack_constructors 260 | stack std::stack http://www.cppreference.com/wiki/stl/stack/start 261 | top std::stack::top http://www.cppreference.com/wiki/stl/stack/top 262 | make_pair std::utility::make_pair http://www.cppreference.com/wiki/stl/utility/make_pair 263 | pair std::utility::pair http://www.cppreference.com/wiki/stl/utility/pair 264 | utility std::utility http://www.cppreference.com/wiki/stl/utility/start 265 | assign std::vector::assign http://www.cppreference.com/wiki/stl/vector/assign 266 | at std::vector::at http://www.cppreference.com/wiki/stl/vector/at 267 | back std::vector::back http://www.cppreference.com/wiki/stl/vector/back 268 | begin std::vector::begin http://www.cppreference.com/wiki/stl/vector/begin 269 | capacity std::vector::capacity http://www.cppreference.com/wiki/stl/vector/capacity 270 | clear std::vector::clear http://www.cppreference.com/wiki/stl/vector/clear 271 | empty std::vector::empty http://www.cppreference.com/wiki/stl/vector/empty 272 | end std::vector::end http://www.cppreference.com/wiki/stl/vector/end 273 | erase std::vector::erase http://www.cppreference.com/wiki/stl/vector/erase 274 | front std::vector::front http://www.cppreference.com/wiki/stl/vector/front 275 | insert std::vector::insert http://www.cppreference.com/wiki/stl/vector/insert 276 | max_size std::vector::max_size http://www.cppreference.com/wiki/stl/vector/max_size 277 | pop_back std::vector::pop_back http://www.cppreference.com/wiki/stl/vector/pop_back 278 | push_back std::vector::push_back http://www.cppreference.com/wiki/stl/vector/push_back 279 | rbegin std::vector::rbegin http://www.cppreference.com/wiki/stl/vector/rbegin 280 | rend std::vector::rend http://www.cppreference.com/wiki/stl/vector/rend 281 | reserve std::vector::reserve http://www.cppreference.com/wiki/stl/vector/reserve 282 | resize std::vector::resize http://www.cppreference.com/wiki/stl/vector/resize 283 | size std::vector::size http://www.cppreference.com/wiki/stl/vector/size 284 | vector std::vector http://www.cppreference.com/wiki/stl/vector/start 285 | swap std::vector::swap http://www.cppreference.com/wiki/stl/vector/swap 286 | vector_constructors std::vector::vector_constructors http://www.cppreference.com/wiki/stl/vector/vector_constructors 287 | vector_operators std::vector::vector_operators http://www.cppreference.com/wiki/stl/vector/vector_operators 288 | -------------------------------------------------------------------------------- /Support/Platform/Makefile: -------------------------------------------------------------------------------- 1 | SDK=$(shell xcrun --sdk macosx --show-sdk-path) 2 | BUILD_DATE=$(shell date +%Y-%m-%d) 3 | LLVM=/usr/local/opt/llvm 4 | CC=xcrun clang 5 | CFLAGS=-Os -Wall -std=c++1y -lc++ --sysroot $(SDK) -DCOMPILE_DATE=\"$(BUILD_DATE)\" -framework Foundation -I$(LLVM)/include -L$(LLVM)/lib -lclang 6 | 7 | C_PATH='$(HOME)/Library/Application Support/TextMate/Bundles/c.tmbundle/Syntaxes/Platform' 8 | OBJC_PATH='$(HOME)/Library/Application Support/TextMate/Bundles/objective-c.tmbundle/Syntaxes/Platform' 9 | 10 | all: c objective-c 11 | 12 | c: generator 13 | ./generator --sdk=$(SDK) --grammar=$(C_PATH).tmLanguage --text=$(C_PATH).md --suffix='.c' includes.c 14 | 15 | objective-c: generator 16 | ./generator --sdk=$(SDK) --grammar=$(OBJC_PATH).tmLanguage --text=$(OBJC_PATH).md --suffix='.objc' --cocoa includes.mm 17 | 18 | generator: generator.mm Makefile 19 | @$(CC) $(CFLAGS) -o $@ $< 20 | 21 | .PHONY: all c objective-c 22 | -------------------------------------------------------------------------------- /Support/Platform/README.md: -------------------------------------------------------------------------------- 1 | The code in this directory is used to generate `Platform.tmLanguage`. 2 | 3 | It requires `libclang` and the clang C includes. This can be obtained by installing `llvm`: 4 | 5 | brew install llvm 6 | 7 | There is a `Makefile` which builds the `generator` executable and will also update `Platform.tmLanguage` in the C and Objective-C bundles. 8 | 9 | Before running `make` you should clone the respective bundles: 10 | 11 | ```shell 12 | cd ~/Library/Application\ Support/TextMate/Bundles 13 | git clone "git@github.com:textmate/c.tmbundle" 14 | git clone "git@github.com:textmate/objective-c.tmbundle" 15 | ``` 16 | 17 | ## How it Works 18 | 19 | We parse either `includes.c` or `includes.mm` (based on the `--cocoa` flag) using clang’s C interface. 20 | 21 | Once the file has been parsed we traverse the parse tree and harvest enumerations, functions, variable declarations, etc. 22 | 23 | For each symbol we check the path of the file path (from where the symbol came) against a list of regular expressions, this determines how to name the scope, and also means that if the file is not matched by any of our regular expressions, the symbol is left out. 24 | 25 | Here is an excerpt from the table: 26 | 27 | ```c 28 | struct { bool objC; std::string scope; std::regex pattern; } const headerTypes[] = 29 | { 30 | { false, ".pthread", std::regex(".*/_?pthread(/.*|\\.h)") }, 31 | { false, ".dispatch", std::regex(".*/dispatch/.*") }, 32 | { false, ".quartz", std::regex(".*/CoreGraphics\\.framework/.*") }, 33 | { false, ".mac-classic", std::regex(".*/MacTypes\\.h") }, 34 | { false, ".cf", std::regex(".*/CoreFoundation\\.framework/.*") }, 35 | { true, ".run-time", std::regex(".*?/objc/(?:objc|runtime|NSObjCRuntime).h") }, 36 | ⋮ 37 | }; 38 | ``` 39 | 40 | If you want to add more symbols to the generated `Platform.tmLanguage` file then you need to edit this table and you may also need to add new include statements to one or both of the `includes.{c,mm}` files. 41 | -------------------------------------------------------------------------------- /Support/Platform/generator.mm: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | 12 | static char const* const kAppVersion = "1.0"; 13 | 14 | #ifndef COMPILE_DATE 15 | #define COMPILE_DATE "YYYY-MM-DD" 16 | #endif 17 | 18 | static void visit (CXTranslationUnit tu, std::function callback) 19 | { 20 | std::set const desiredCursorKinds = { CXCursor_StructDecl, CXCursor_EnumDecl, CXCursor_TypedefDecl, CXCursor_FunctionDecl, CXCursor_ObjCProtocolDecl, CXCursor_ObjCInterfaceDecl, CXCursor_VarDecl, CXCursor_EnumConstantDecl }; 21 | clang_visitChildrenWithBlock(clang_getTranslationUnitCursor(tu), ^(CXCursor cursor, CXCursor parent){ 22 | CXCursorKind kind = clang_getCursorKind(cursor); 23 | if(desiredCursorKinds.find(kind) == desiredCursorKinds.end()) 24 | return CXChildVisit_Recurse; 25 | 26 | CXString name = clang_getCursorSpelling(cursor); 27 | std::string const symbol = clang_getCString(name); 28 | clang_disposeString(name); 29 | if(symbol.empty() || symbol.front() == '_') 30 | return clang_getCursorKind(cursor) == CXCursor_EnumDecl ? CXChildVisit_Recurse : CXChildVisit_Continue; 31 | 32 | CXSourceRange range = clang_getCursorExtent(cursor); 33 | CXSourceLocation location = clang_getRangeStart(range); 34 | CXFile file; 35 | clang_getFileLocation(location, &file, nullptr, nullptr, nullptr); 36 | CXString filename = clang_getFileName(file); 37 | std::string const header = clang_getCString(filename) ?: ""; 38 | clang_disposeString(filename); 39 | 40 | CXPlatformAvailability* available = nullptr; 41 | CXPlatformAvailability availability[4]; // macOS, iOS, watchOS, tvOS 42 | int n = clang_getCursorPlatformAvailability(cursor, nullptr, nullptr, nullptr, nullptr, &availability[0], sizeof(availability) / sizeof(availability[0])); 43 | for(int i = 0; i < n && !available; ++i) 44 | { 45 | if(strcmp("macos", clang_getCString(availability[i].Platform)) == 0) 46 | available = &availability[i]; 47 | } 48 | 49 | callback(symbol, kind, available, header, cursor); 50 | 51 | return clang_getCursorKind(cursor) == CXCursor_EnumDecl ? CXChildVisit_Recurse : CXChildVisit_Continue; 52 | }); 53 | } 54 | 55 | template 56 | std::string strings_to_regexp (_InputIter first, _InputIter last) 57 | { 58 | struct node_t 59 | { 60 | void add_string (std::string::const_iterator first, std::string::const_iterator last) 61 | { 62 | if(first == last) 63 | { 64 | _terminate = true; 65 | } 66 | else 67 | { 68 | auto it = _nodes.find(*first); 69 | if(it == _nodes.end()) 70 | it = _nodes.emplace(*first, node_t()).first; 71 | it->second.add_string(++first, last); 72 | } 73 | } 74 | 75 | void to_s (std::string& out) const 76 | { 77 | if(_nodes.empty()) 78 | return; 79 | 80 | out += _terminate || _nodes.size() > 1 ? "(?:" : ""; 81 | bool first = true; 82 | for(auto const& pair : _nodes) 83 | { 84 | if(!std::exchange(first, false)) 85 | out += '|'; 86 | out += pair.first; 87 | pair.second.to_s(out); 88 | } 89 | out += _terminate ? ")?" : (_nodes.size() > 1 ? ")" : ""); 90 | } 91 | 92 | private: 93 | std::map _nodes; 94 | bool _terminate = false; 95 | }; 96 | 97 | node_t n; 98 | for(auto it = first; it != last; ++it) 99 | n.add_string(it->begin(), it->end()); 100 | 101 | std::string res; 102 | n.to_s(res); 103 | return res; 104 | } 105 | 106 | static BOOL update_grammar (NSString* grammarPath, std::map> const& functions, std::map> const& protocols, std::map> const& other, NSString* comment) 107 | { 108 | NSMutableArray* patternRules = [NSMutableArray new]; 109 | NSMutableArray* functionRules = [NSMutableArray new]; 110 | NSMutableArray* protocolRules = [NSMutableArray new]; 111 | 112 | for(auto const& pair : functions) 113 | { 114 | NSString* match = [NSString stringWithFormat:@"\\b%@\\b", @(strings_to_regexp(pair.second.begin(), pair.second.end()).c_str())]; 115 | [functionRules addObject:@{ 116 | @"match" : [NSString stringWithFormat:@"(\\s*)(%@)", match], 117 | @"captures" : @{ 118 | @"1" : @{ @"name" : @"punctuation.whitespace.support.function.leading" }, 119 | @"2" : @{ @"name" : @(pair.first.c_str()) } 120 | } 121 | }]; 122 | } 123 | 124 | for(auto const& pair : protocols) 125 | { 126 | NSString* match = [NSString stringWithFormat:@"\\b%@\\b", @(strings_to_regexp(pair.second.begin(), pair.second.end()).c_str())]; 127 | [protocolRules addObject:@{ @"name" : @(pair.first.c_str()), @"match" : match }]; 128 | } 129 | 130 | for(auto const& pair : other) 131 | { 132 | NSString* match = [NSString stringWithFormat:@"\\b%@\\b", @(strings_to_regexp(pair.second.begin(), pair.second.end()).c_str())]; 133 | [patternRules addObject:@{ @"name" : @(pair.first.c_str()), @"match" : match }]; 134 | } 135 | 136 | if(NSMutableDictionary* plist = [NSMutableDictionary dictionaryWithContentsOfFile:grammarPath]) 137 | { 138 | plist[@"comment"] = comment ?: @"Generated"; 139 | plist[@"patterns"] = patternRules; 140 | NSMutableDictionary* repos = [NSMutableDictionary dictionaryWithDictionary:@{ 141 | @"functions" : @{ @"patterns" : functionRules }, 142 | }]; 143 | if(protocolRules.count) 144 | repos[@"protocols"] = @{ @"patterns" : protocolRules }; 145 | plist[@"repository"] = repos; 146 | return [plist writeToFile:grammarPath atomically:YES]; 147 | } 148 | return NO; 149 | } 150 | 151 | static void update_summary (char const* summaryPath, std::map> const& functions, std::map> const& protocols, std::map> const& other, NSString* comment) 152 | { 153 | std::map> const&> const types = 154 | { 155 | { "Functions", functions }, 156 | { "Protocols", protocols }, 157 | { "Other", other }, 158 | }; 159 | 160 | if(FILE* fp = fopen(summaryPath, "w")) 161 | { 162 | if(comment) 163 | fprintf(fp, "%s\n\n", [comment UTF8String]); 164 | 165 | for(auto const& type : types) 166 | { 167 | if(type.second.empty()) 168 | continue; 169 | 170 | fprintf(fp, "# %s\n", type.first.c_str()); 171 | for(auto const& pair : type.second) 172 | { 173 | fprintf(fp, "\n## %s\n\n", pair.first.c_str()); 174 | for(auto const& function : pair.second) 175 | fprintf(fp, "- `%s`\n", function.c_str()); 176 | } 177 | fprintf(fp, "\n"); 178 | } 179 | fclose(fp); 180 | } 181 | } 182 | 183 | static void version (FILE* io) 184 | { 185 | fprintf(io, "%1$s %2$s (" COMPILE_DATE ")\n", getprogname(), kAppVersion); 186 | } 187 | 188 | static void usage (FILE* io) 189 | { 190 | version(io); 191 | fprintf(io, 192 | "Usage: %1$s [-otsschv] source\n" 193 | "\n" 194 | "Options:\n" 195 | " -o, --grammar The tmGrammar file to generate/update.\n" 196 | " -t, --text Write all symbols to this file in a readable format.\n" 197 | " -S, --sdk Path to Xcode SDK.\n" 198 | " -s, --suffix Suffix to append to scopes, e.g. `.objc`.\n" 199 | " -c, --cocoa Generate grammar for Objective-C frameworks.\n" 200 | " -h, --help Show this information.\n" 201 | " -v, --version Print version information.\n" 202 | "\n", getprogname()); 203 | } 204 | 205 | int main (int argc, char const* argv[]) 206 | { 207 | extern char* optarg; 208 | extern int optind; 209 | extern int optreset; 210 | 211 | static struct option const longopts[] = { 212 | { "grammar", required_argument, 0, 'o' }, 213 | { "text", required_argument, 0, 't' }, 214 | { "sdk", required_argument, 0, 'S' }, 215 | { "suffix", required_argument, 0, 's' }, 216 | { "cocoa", no_argument, 0, 'c' }, 217 | { "help", no_argument, 0, 'h' }, 218 | { "version", no_argument, 0, 'v' }, 219 | { 0, 0, 0, 0 } 220 | }; 221 | 222 | char const* grammarPath = nullptr; 223 | char const* textPath = nullptr; 224 | char const* sdkPath = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"; 225 | char const* suffix = nullptr; 226 | bool isObjectiveC = false; 227 | 228 | int ch; 229 | while((ch = getopt_long(argc, (char**)argv, "o:t:S:s:chv", longopts, NULL)) != -1) 230 | { 231 | switch(ch) 232 | { 233 | case 'o': grammarPath = optarg; break; 234 | case 't': textPath = optarg; break; 235 | case 'S': sdkPath = optarg; break; 236 | case 's': suffix = optarg; break; 237 | case 'c': isObjectiveC = true; break; 238 | case 'h': usage(stdout); return EX_OK; 239 | case 'v': version(stdout); return EX_OK; 240 | case '?': /* unknown option */ return EX_USAGE; 241 | case ':': /* missing option */ return EX_USAGE; 242 | default: usage(stderr); return EX_USAGE; 243 | } 244 | } 245 | 246 | argc -= optind; 247 | argv += optind; 248 | 249 | if(argc != 1) 250 | { 251 | fprintf(stderr, "%s: Wrong number of argumetns, expected 1 but got %d\n", getprogname(), argc); 252 | return EX_USAGE; 253 | } 254 | 255 | char const* sourcePath = argv[0]; 256 | 257 | if(access(sourcePath, R_OK) != 0) 258 | { 259 | perror("error reading source"); 260 | return EX_USAGE; 261 | } 262 | 263 | if(access(sdkPath, R_OK) != 0) 264 | { 265 | perror("error reading SDK"); 266 | return EX_USAGE; 267 | } 268 | 269 | CXIndex index = clang_createIndex(0, 0); 270 | char const* args[] = { "-std=c++1y", "-stdlib=libc++", "--sysroot", sdkPath }; 271 | CXTranslationUnit tu = clang_parseTranslationUnit(index, sourcePath, args, sizeof(args) / sizeof(args[0]), nullptr, 0, CXTranslationUnit_None); 272 | 273 | std::map cursorTypes = 274 | { 275 | { CXCursor_StructDecl, "support.type" }, 276 | { CXCursor_EnumDecl, "support.type" }, 277 | { CXCursor_TypedefDecl, "support.type" }, 278 | { CXCursor_FunctionDecl, "support.function" }, 279 | { CXCursor_VarDecl, "support.variable" }, 280 | { CXCursor_EnumConstantDecl, "support.constant" }, 281 | { CXCursor_ObjCProtocolDecl, "support.other.protocol" }, 282 | { CXCursor_ObjCInterfaceDecl, "support.class" }, 283 | }; 284 | 285 | struct { bool objC; std::string scope; std::regex pattern; } const headerTypes[] = 286 | { 287 | { false, ".clib", std::regex(".*/(alloca|ctype|_?locale|math|_?select|setjmp|signal|stdarg|stddef|stdint|stdio|stdlib|string|strings|time|types|unistd|sys/(fcntl|resource|select|types|wait)|_types/.*)\\.h$") }, 288 | { false, ".pthread", std::regex(".*/_?pthread(/.*|\\.h)") }, 289 | { false, ".os", std::regex(".*/(OSByteOrder|gethostuuid)\\.h") }, 290 | { false, ".dispatch", std::regex(".*/dispatch/.*") }, 291 | { false, ".quartz", std::regex(".*/CoreGraphics\\.framework/.*") }, 292 | { false, ".mac-classic", std::regex(".*/MacTypes\\.h") }, 293 | { false, ".cf", std::regex(".*/CoreFoundation\\.framework/.*") }, 294 | { true, ".run-time", std::regex(".*?/objc/(?:objc|runtime|NSObjCRuntime).h") }, 295 | { true, ".cocoa", std::regex(".*?/(?:AddressBook|AppKit|ExceptionHandling|Foundation|UserNotifications|WebKit)\\.framework/(?!.*\\.framework/).*") }, 296 | }; 297 | 298 | std::map> functions; 299 | std::map> protocols; 300 | std::map> other; 301 | 302 | if(isObjectiveC) 303 | { 304 | other = { 305 | { "storage.type.objc", { "instancetype" } }, 306 | { "storage.type.cocoa.objc", { "IBOutlet", "IBAction", "IBInspectable", "IB_DESIGNABLE" } } // NSNibDeclarations.h 307 | }; 308 | } 309 | 310 | visit(tu, [&](std::string const& symbol, CXCursorKind kind, CXPlatformAvailability const* available, std::string const& header, CXCursor cursor){ 311 | for(auto const& match : headerTypes) 312 | { 313 | if(isObjectiveC != match.objC || !std::regex_match(header, match.pattern)) 314 | continue; 315 | 316 | std::string scope = cursorTypes[kind]; 317 | scope += match.scope; 318 | 319 | if(available && available->Deprecated.Major == 10) 320 | scope = "invalid.deprecated." + std::to_string(available->Deprecated.Major) + "." + std::to_string(available->Deprecated.Minor) + "." + scope; 321 | else if(available && available->Introduced.Major == 10 && available->Introduced.Minor > 7) 322 | scope += "." + std::to_string(available->Introduced.Major) + "." + std::to_string(available->Introduced.Minor); 323 | 324 | if(suffix) 325 | scope += suffix; 326 | 327 | if(kind == CXCursor_FunctionDecl) 328 | functions[scope].insert(symbol); 329 | else if(kind == CXCursor_ObjCProtocolDecl) 330 | protocols[scope].insert(symbol); 331 | else 332 | other[scope].insert(symbol); 333 | 334 | break; 335 | } 336 | }); 337 | 338 | NSString* comment = [NSString stringWithFormat:@"This file was generated with clang-C using %@", [@(sdkPath) lastPathComponent]]; 339 | if(grammarPath && !update_grammar(@(grammarPath), functions, protocols, other, comment)) 340 | { 341 | fprintf(stderr, "%s: error updating %s\n", getprogname(), grammarPath); 342 | return EX_IOERR; 343 | } 344 | 345 | if(textPath) 346 | update_summary(textPath, functions, protocols, other, comment); 347 | 348 | return EX_OK; 349 | } 350 | -------------------------------------------------------------------------------- /Support/Platform/includes.c: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | 12 | int main (int argc, char const* argv[]) 13 | { 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Support/Platform/includes.mm: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | 17 | int main (int argc, char const* argv[]) 18 | { 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /Support/SpecialRules.txt: -------------------------------------------------------------------------------- 1 | addObserver:selector:name:!!!#Notification 2 | notificationWithName:!!!#Notification 3 | postNotificationName:!!!#Notification 4 | removeObserver:name:!!!#Notification 5 | rangeOfString:options:!!!#Search 6 | rangeOfCharacterFromSet:options:!!!#Search 7 | compare:options:!!!#Search 8 | commonPrefixWithString:options:!!!#Search 9 | setLevel:!!!#WindowLevel 10 | addAttribute:!NSAttributedString!!#StandardAttributes 11 | setColorSpaceName:!!!#ColorSpace 12 | colorUsingColorSpaceName:!!!#ColorSpace 13 | initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:!!!#ColorSpace 14 | setData:forType:!!!#PboardType 15 | propertyListForType:!!!#PboardType 16 | dataForType:!!!#PboardType 17 | attribute:!!!#StandardAttributes 18 | setExceptionHandlingMask:!!!#NSLogUncaughtExceptionMask 19 | nextEventMatchingMask:!!!#Mask 20 | raise:!!!#Exception 21 | setAutoresizingMask:!!!#NSView 22 | contentRectForFrameRect:styleMask:!!!#WindowMask 23 | initWithContentRect:styleMask:!!!#WindowMask 24 | endSheet:returnCode:!!!#ReturnCode 25 | nextEventMatchingMask:untilDate:inMode:!!!#RunLoopModes -------------------------------------------------------------------------------- /Support/anonymousEnums.rb: -------------------------------------------------------------------------------- 1 | 2 | # find /System/Library/Frameworks/*.framework -name \*.h -exec awk '/\}/ { if(pr) print $0; pr = 0;} { if(pr) print $0; } /^enum .*\{[^}]*$/ { pr = 1; print $0; }' '{}' \; > anonut.txt 3 | s = STDIN.read 4 | def stripComments(line) 5 | line.gsub(/((['"])(?:\\.|.)*?\2)|\/\*.*?\*\/|\/\/[^\n\r]*/m) do |s| 6 | if $1 7 | s 8 | else 9 | ' ' * s.length() 10 | end 11 | end 12 | end 13 | 14 | 15 | def presuff(items)min_len = items.min{ |i,j| i.length <=> j.length }.length 16 | common_prefix = "" 17 | (0...min_len).each do |i| 18 | col = items.inject(""){ |sum,elem| sum << elem[i] }.squeeze 19 | if col.length > 1 20 | break 21 | end 22 | common_prefix << col 23 | end 24 | 25 | min_len = items.min{ |i,j| i.length <=> j.length }.length 26 | common_suffix = "" 27 | (0...min_len).each do |i| 28 | col = items.inject(""){ |sum,elem| sum << elem[-i-1] }.squeeze 29 | if col.length > 1 30 | break 31 | end 32 | common_suffix = col + common_suffix 33 | end 34 | common_prefix = "" unless common_prefix.length > 2 35 | common_suffix = "" unless common_suffix.length > 2 36 | r = common_prefix + common_suffix 37 | r = "NO_GUESS" if r == "" 38 | return r 39 | end 40 | 41 | require 'set' 42 | nameSet = Set.new 43 | s = stripComments(s).gsub(/(\w)\s*,\s*(\w)/, '\1, 44 | \2') 45 | l = s.scan(/enum\s*(?:\w+\s*)?\{.*?\}\;/m) 46 | l = l.sort.uniq 47 | list = [] 48 | l.each do |elem| 49 | if elemName = elem.match(/enum\s+(\w+)/) 50 | guess = elemName[1] 51 | end 52 | ms = elem.split("\n").select{|a| a.match(/^\s*[a-zA-Z0-9_]+\s*(=|,)/)}.collect{|b| b.match(/[a-zA-Z0-9_]+/)[0]} 53 | if ms && !ms.empty? 54 | unless elemName 55 | guess = presuff(ms) 56 | guess = ms[0] if ms.size == 1 57 | if guess == "StringEncoding" #special case 58 | guess = "NO_GUESS" 59 | noGo = true 60 | end 61 | end 62 | if nameSet.include?(guess) 63 | unless nameSet.include?(ms[0]) && ms.size > 1 64 | guess = ms[0] 65 | else 66 | puts "------" #these will have to be solved by hand 67 | end 68 | else 69 | nameSet.add(guess) 70 | end 71 | guess = "kException" if guess == "Exception" 72 | unless noGo 73 | ms.each do |k| 74 | puts k + "\t\t#"+ guess 75 | end 76 | end 77 | end 78 | end 79 | 80 | "NSAlertOtherReturn NSAlertReturn 81 | typedef unsigned int NSWorkspaceLaunchOptions; 82 | enum { 83 | NSWorkspaceLaunchAndPrint 84 | typedef unsigned int NSGlyph; 85 | enum { 86 | NSControlGlyph 87 | typedef unsigned int NSDragOperation; 88 | enum { 89 | NSDragOperationNone 90 | 91 | 92 | typedef unsigned int NSDatePickerElementFlags; 93 | enum { 94 | /* Time Elements */ 95 | NSHourMinuteDatePickerElementFlag = 0x000c, 96 | enum { 97 | NSKeyValueObservingOptionNew = 0x01, 98 | NSKeyValueObservingOptionOld = 0x02 99 | }; 100 | typedef unsigned int NSKeyValueObservingOptions;" 101 | -------------------------------------------------------------------------------- /Support/generateMethodList.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby18 2 | # run with find /System/Library/Frameworks/*.framework -name \*.h -print0 | ruby generateMethodList.rb 3 | translate = {"Message" => "Me", 4 | "AddressBook" => "AB", 5 | "SecurityFoundation" => "SF", 6 | "QTKit" => "QT", 7 | "IOBluetooth" => "Blue", 8 | "WebKit" => "WK", 9 | "SenTestingKit" => "Test", 10 | "InstallerPlugins" => "Ins", 11 | "CoreData" => "CD", 12 | "Carbon" => "Ca", 13 | "Automator" => "Au", 14 | "SyncServices" => "Sync", 15 | "AppKit" => "AK", 16 | "InterfaceBuilder" => "IB", 17 | "InstantMessage" => "IM", 18 | "DiscRecording" => "DR", 19 | "AppleScriptKit" => "ASK", 20 | "SecurityInterface" => "SI", 21 | "OSAKit" => "OSA", 22 | "QuartzCore" => "CI", 23 | "Foundation" => "F", 24 | "AudioUnit" => "AU", 25 | "ScreenSaver" => "Sav", 26 | "Quartz" => "Q", 27 | "PreferencePanes" => "Pref", 28 | "ExceptionHandling" => "Exc", 29 | "DiscRecordingUI" => "DRui", 30 | "CoreAudioKit" => "CAK", 31 | "XgridFoundation" => "Grid", 32 | "IOBluetoothUI" => "BUI", 33 | "UIKit" => "UI"} 34 | require 'optparse' 35 | 36 | 37 | options = {} 38 | OptionParser.new do |opts| 39 | opts.banner = "Usage: example.rb [options]" 40 | 41 | opts.on("-c", "--classOutput FILENAME", "Run verbosely") do |v| 42 | options[:class] = v 43 | end 44 | opts.on("-m", "--methodOutput FILENAME", "Run verbosely") do |v| 45 | options[:method] = v 46 | end 47 | opts.on("-w", "--withCocoaAncestry FILENAME", "Run verbosely") do |v| 48 | options[:super] = v 49 | end 50 | 51 | opts.on("-i", "--isCocoa", "Use this option if we are generating the Cocoa headers") do |v| 52 | options[:cocoa] = v 53 | end 54 | 55 | end.parse! 56 | 57 | p options 58 | def method_parse(k) 59 | l = k.scan /(\-|\+)\s*\((([^\(\)]|\([^\)]*\))*)\)|\((([^\(\)]|\([^\)]*\))*)\)\s*[a-zA-Z][a-zA-Z0-9]*|(([a-zA-Z][a-zA-Z0-9]*)?:)/ 60 | types = l.select {|item| item[1] || item[3] }.collect{|item| (item[1] || item[3]).gsub(/(\w)\*/,'\1 *') } 61 | 62 | methodList = l.reject {|item| item[5].nil? }.collect{|item| item[5] } 63 | if methodList.size > 0 64 | methodName = methodList.join 65 | elsif mn = k.match(/\)\s*([a-zA-Z][a-zA-Z0-9]*)/) 66 | methodName = mn[1] 67 | else 68 | methodName = k.match(/([a-zA-Z][a-zA-Z0-9]*)/)[1] 69 | end 70 | [methodName, types] 71 | 72 | end 73 | xlist = ["action:\tAK\tCl\tNSActionCell\tim\tvoid\tid", 74 | "alertDidEnd:returnCode:contextInfo:\tAK\tCl\tNSAlert\tim\tvoid\tNSAlert *\tint\tvoid *", 75 | "sheetDidEnd:returnCode:contextInfo:\tAK\tCl\tNSApplication\tim\tvoid\tNSWindow *\tint\tvoid *", 76 | "myCustomDrawMethod:\tAK\tCl\tNSCustomImageRep\tim\tvoid\tid", 77 | "document:didSave:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 78 | "document:shouldClose:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 79 | "didPresentErrorWithRecovery:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tBOOL\tvoid *", 80 | "document:didPrint:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 81 | "document:didRunPageLayoutAndUserAccepted:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 82 | "document:didRunPrintOperation:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 83 | "document:didSave:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 84 | "document:didSave:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 85 | "document:didSave:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 86 | "document:didSave:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 87 | "document:shouldClose:contextInfo:\tAK\tCl\tNSDocument\tim\tvoid\tNSDocument *\tBOOL\tvoid *", 88 | "documentController:didCloseAll:contextInfo:\tAK\tCl\tNSDocumentController\tim\tvoid\tNSDocumentController *\tBOOL\tvoid *", 89 | "didPresentErrorWithRecovery:contextInfo:\tAK\tCl\tNSDocumentController\tim\tvoid\tBOOL\tvoid *", 90 | "documentController:didReviewAll:contextInfo:\tAK\tCl\tNSDocumentController\tim\tvoid\tNSDocumentController *\tBOOL\tvoid *", 91 | "action:\tAK\tCl\tNSFontManager\tim\tvoid\tid", 92 | "action:\tAK\tCl\tNSMatrix\tim\tvoid\tid", 93 | "sortAction:\tAK\tCl\tNSMatrix\tim\tNSComparisonResult\tid", 94 | "editor:didCommit:contextInfo:\tAK\tCl\tNSObject\tim\tvoid\tid\tBOOL\tvoid *", 95 | "openPanelDidEnd:returnCode:contextInfo:\tAK\tCl\tNSOpenPanel\tim\tvoid\tNSSavePanel *\tint\tvoid *", 96 | "openPanelDidEnd:returnCode:contextInfo:\tAK\tCl\tNSOpenPanel\tim\tvoid\tNSSavePanel *\tint\tvoid *", 97 | "pageLayoutDidEnd:returnCode:contextInfo:\tAK\tCl\tNSPageLayout\tim\tvoid\tNSPageLayout *\tint\tvoid *", 98 | "printOperationDidRun:success:contextInfo:\tAK\tCl\tNSPrintOperation\tim\tvoid\tNSPrintOperation *\tBOOL\tvoid *", 99 | "printPanelDidEnd:returnCode:contextInfo:\tAK\tCl\tNSPrintPanel\tim\tvoid\tNSPrintPanel *\tint\tvoid *", 100 | "didPresentErrorWithRecovery:contextInfo:\tAK\tCl\tNSResponder\tim\tvoid\tBOOL\tvoid *", 101 | "savePanelDidEnd:returnCode:contextInfo:\tAK\tCl\tNSSavePanel\tim\tvoid\tNSSavePanel *\tint\tvoid *", 102 | "action:\tAK\tCl\tNSStatusItem\tim\tvoid\tid", 103 | "action:\tAK\tCl\tNSStatusItem\tim\tvoid\tid", 104 | "action:\tAK\tCl\tNSTableView\tim\tvoid\tid", 105 | "action:\tAK\tCl\tNSToolbarItem\tim\tvoid\tid", 106 | "action:\tAK\tCl\tNSBrowser\tim\tvoid\tid", 107 | "action:\tAK\tCl\tNSBrowser\tim\tvoid\tid", 108 | "action:\tAK\tCl\tNSColorPanel\tim\tvoid\tid", 109 | "editor:didCommit:contextInfo:\tAK\tCl\tNSController\tim\tvoid\tid\tBOOL\tvoid *", 110 | "action:\tAK\tCl\tNSMenu\tim\tvoid\tid", 111 | "action:\tAK\tCl\tNSMenu\tim\tvoid\tid", 112 | "action:\tAK\tCl\tNSMenu\tim\tvoid\tid", 113 | "action:\tAK\tCl\tNSMenuItem\tim\tvoid\tid", 114 | "action:\tAK\tCl\tNSMenuItem\tim\tvoid\tid", 115 | "action:\tAK\tCl\tNSPopUpButton\tim\tvoid\tid", 116 | "action:\tAK\tCl\tNSPopUpButtonCell\tim\tvoid\tid"] 117 | #headers = %x{find /System/Library/Frameworks/*.framework -name \*.h}.split("\n") 118 | headers = STDIN.read.split("\0") 119 | #headers = ["test.h"] 120 | rgxp = /^(((?:[A-Z_0-9]+\s+)?@interface)|(@end)|((\-|\+)\s*\()|((\-|\+)[^;]*\;)|(@protocol[^\n;]*\n))/ 121 | list = [] 122 | hash = {} 123 | classList = [] 124 | headers.each do |name| 125 | if mat = name.match(/(\w*)\.framework/) 126 | framework = mat[1] 127 | else 128 | framework = "Priv" 129 | end 130 | filename = name.match(/(\w*)\.h/)[1] 131 | unless framework == "JavaVM" || framework == "vecLib" 132 | #puts name 133 | open(name) do |file| 134 | str = file.read 135 | while m = str.match(rgxp) 136 | str = m[0] + m.post_match 137 | if m[2] 138 | k = str.match /@interface(?:\s|\n)+(\w+)(?:\s*:\s*(\w+))?[^\n]*/ 139 | if k 140 | methodType = "dm" if k[0].match /\(\s*\w*[Dd]elegate\w*\s*\)/ 141 | className = k[1] 142 | if translate[framework] 143 | frameworkName = translate[framework] 144 | else 145 | frameworkName = "NA" 146 | end 147 | if k[2] && k[2]!="" #&& options[:super] 148 | hash[className] = {:super => k[2]} 149 | hash[className][:cocoa] = true if options[:cocoa] 150 | end 151 | classList << "#{className}" 152 | classType = "Cl" 153 | inClass = true 154 | 155 | str = k.post_match 156 | else 157 | str = m.post_match 158 | end 159 | elsif m[3] 160 | inClass = false 161 | str = m.post_match 162 | elsif m[4] 163 | k = str.match /[^;{]+?(;|\{)/ 164 | if inClass && k 165 | methodName, types = method_parse(k[0]) 166 | na = className 167 | na += ";#{filename}" unless className == filename 168 | methodType = {"+" => "cm", "-" => "im"}[m[5]] unless methodType == "dm" 169 | if translate[framework] 170 | frameworkName = translate[framework] 171 | else 172 | frameworkName = "NA" 173 | end 174 | list << "#{methodName}\t#{frameworkName}\t#{classType}\t#{na}\t#{methodType}\t#{types.join("\t")}" 175 | str = k.post_match 176 | else 177 | str = m.post_match 178 | end 179 | 180 | elsif m[6] 181 | if inClass 182 | methodName, t = method_parse(m[6]) 183 | types = ["id"] 184 | types += t if t.size > 0 185 | na = className 186 | na += ";#{filename}" unless className == filename 187 | methodType = {"+" => "cm", "-" => "im"}[m[7]] unless methodType == "dm" 188 | if translate[framework] 189 | frameworkName = translate[framework] 190 | else 191 | frameworkName = "NA" 192 | end 193 | 194 | list << "#{methodName}\t#{frameworkName}\t#{classType}\t#{na}\t#{methodType}\t#{types.join("\t")}" 195 | end 196 | str = m.post_match 197 | elsif m[8] 198 | k = str.match /@protocol\s+(\w+)[^\n]*/ 199 | if k 200 | className = k[1] 201 | classType = "Pr" 202 | inClass = true 203 | str = k.post_match 204 | end 205 | else 206 | str = m.post_match 207 | end 208 | end 209 | end 210 | end 211 | end 212 | #puts hash.inspect 213 | 214 | if options.empty? 215 | print list.join("\n") 216 | else 217 | if !hash.empty? 218 | classList = [] # clear classList 219 | require 'set' 220 | if options[:super] && !options[:cocoa] 221 | require 'escape' 222 | cocoaSet = %x{gunzip -c #{e_sh options[:super]} |cut -f1}.split("\n").to_set 223 | hash.keys.each do |name| 224 | if cocoaSet.include? hash[name][:super] 225 | hash[name][:cocoa] = true 226 | else 227 | hash[name][:cocoa] = false 228 | end 229 | end 230 | else 231 | hash["NSObject"] = {:super => nil, :cocoa => true} 232 | hash["NSProxy"] = {:super => nil, :cocoa => true} 233 | end 234 | hash.keys.each do |name| 235 | 236 | tName = name 237 | tString = "#{name}\t#{name}:" 238 | i = 0 239 | until hash[tName].nil? || ((hash[tName][:cocoa] && options[:super] && !options[:cocoa])) || i > 10 240 | tName = hash[tName][:super] 241 | tString += "#{tName}:" if tName 242 | i += 1 243 | end 244 | 245 | tString += hash[tName][:super] if hash[tName] && hash[tName][:cocoa] 246 | classList << tString 247 | end 248 | end 249 | File.open(options[:class],"w")do |f| f.write(classList.uniq.join("\n")) end unless options[:class].nil? 250 | File.open(options[:method],"w")do |f| f.write(list.join("\n")) end unless options[:method].nil? 251 | end 252 | #s.split("\n").select{|a| a.match(/sel_of_type/)}.collect{|b| b.match(/"\(([^"]+)/)[0]} 253 | extra = ' 254 | cn = "" # use the xml exception files from BridgeSupport 255 | list = [] 256 | l.each do |elem| 257 | cn = elem.match(/class name=("|\')(.+?)\1/)[2] 258 | ms = elem.split("\n").select{|a| a.match(/sel_of_type/)}.collect{|b| b.match(/sel_of_type="([^"]+)/)} 259 | if ms && !ms.empty? 260 | ms.each do |k| 261 | puts k[1] 262 | #.inspect 263 | methodName, types = method_parse("-" + k[1]) 264 | list << "#{methodName}\tAK\tCl\t#{cn}\tim\t#{types.join("\t")}" 265 | end 266 | end 267 | end 268 | ' 269 | 270 | -------------------------------------------------------------------------------- /Support/lib/docset_query.rb: -------------------------------------------------------------------------------- 1 | SUPPORT = ENV['TM_SUPPORT_PATH'] 2 | 3 | require SUPPORT + '/lib/exit_codes' 4 | require SUPPORT + '/lib/escape' 5 | require SUPPORT + '/lib/osx/plist' 6 | require SUPPORT + '/lib/ui' 7 | 8 | def find_xcode_prefix 9 | if ENV['PATH'].split(':').find { |path| File.executable?(File.join(path, 'xcode-select')) } 10 | %x{xcode-select -print-path}.chomp 11 | else 12 | '/Developer' 13 | end 14 | end 15 | 16 | prefix = find_xcode_prefix 17 | 18 | DOCSET_CMD = "#{prefix}/usr/bin/docsetutil search -skip-text -query " 19 | DOCSETS = Dir.glob("{#{prefix}/Documentation/DocSets,{#{ENV['HOME']},}/Library/Developer/Shared/Documentation/DocSets}/*.docset") 20 | 21 | Man = Struct.new(:url, :language, :klass) 22 | class Man 23 | def title 24 | klass 25 | end 26 | end 27 | 28 | Ref = Struct.new(:docset, :language, :type, :klass, :thing, :path) 29 | class Ref 30 | TYPE_ABBREVIATIONS = {'cl' => 'Class', 'intf' => 'Protocol', 'cat' => 'Category', 31 | 'intfm' => 'Method', 'instm' => Method, 'econst' => 'Enum', 32 | 'tdef' => 'Typedef', 'macro' => 'Macro', 'data' => 'Data', 33 | 'func' => 'Function'} 34 | 35 | def url 36 | path[0] == ?/ ? path : docset + "/Contents/Resources/Documents/" + path 37 | end 38 | 39 | # A '-' as a title in the popup menu not very useful so use the type field instead. 40 | def title 41 | klass == '-' ? TYPE_ABBREVIATIONS[type] || type : klass 42 | end 43 | 44 | def exists? 45 | File.exists?(url.split('#').first) 46 | end 47 | 48 | # Test if we are referring to documentation about the same 49 | # thing, but from different docsets. (used by uniq). 50 | def eql? (other) 51 | language == other.language && type == other.type && 52 | klass == other.klass && thing == other.thing 53 | end 54 | 55 | # Also needed by uniq 56 | def hash 57 | (language + type + klass + thing).hash 58 | end 59 | end 60 | 61 | 62 | # Split the query result into its component types and document path. 63 | # language is 'Objective-C', 'C', 'C++' 64 | # type is 'instm' (nstance method), 'clsm' (class method, 'func' , 'econst', 'tag', 'tdef' and so on. 65 | # klass holds the class or '-' if no class is appropriate (for a C function, for example). 66 | # thing is the method, function, constant, etc. 67 | def parts_of_reference (docset, ref_str) 68 | ref = ref_str.split 69 | if ref.length != 2 70 | TextMate.exit_show_tool_tip "Cannot parse reference: #{str}" 71 | end 72 | 73 | language, type, klass, thing = ref[0].split('/') 74 | Ref.new(docset, language, type, klass, thing, ref[1]) 75 | end 76 | 77 | def search_docs (query) 78 | results, legacy = [], [] 79 | DOCSETS.each do |docset| 80 | cmd = DOCSET_CMD + query + ' ' + docset 81 | response = `#{cmd}` 82 | 83 | case response # elaborate for doc purposes 84 | when '' 85 | # Not found. 86 | when /Documentation set path does not exist/ 87 | # Docset not installed or moved somewhere else. 88 | else 89 | response.split("\n").each do |r| 90 | ref = parts_of_reference(docset, r) 91 | (docset =~ /Legacy/ ? legacy : results) << ref if ref.exists? 92 | end 93 | end 94 | end 95 | 96 | # Only add legacy documentation if we didn’t find a newer reference — this approach is required because WebObjects has a lot of legacy documentation on Foundation classes 97 | legacy.each { |match| results << match unless results.member? match } 98 | return results.uniq 99 | end 100 | 101 | def show_document (results, query) 102 | if results.nil? || results.empty? 103 | TextMate.exit_show_tool_tip "Cannot find documentation for: #{query}" 104 | elsif results.length == 1 105 | url = results[0].url 106 | else 107 | 108 | # Ask the user which class they are interested in. 109 | results.sort! {|a, b| a.klass <=> b.klass} 110 | if results.all? {|ref| ref.language == "Objective-C"} 111 | class_names = results.map {|ref| {'title' => ref.title, 'url' => ref.url}} 112 | else 113 | class_names = results.map {|ref| {'title' => "#{ref.language} #{ref.title}", 'url' => ref.url}} 114 | end 115 | class_names.sort! {|a, b| a['title'] <=> b['title']} 116 | url = get_user_selected_reference(class_names) 117 | end 118 | 119 | if url 120 | full = url =~ /^http:/ ? url : "file://#{url}" 121 | TextMate.exit_show_html "" 122 | else 123 | TextMate.exit_discard 124 | end 125 | end 126 | 127 | def man_page (query) 128 | pages = `man 2>&1 -S2:3 -w #{query}` 129 | if pages !~ /No manual entry/ 130 | pages.split("\n").map { |e| $1 if e =~ %r{/#{query}\.(.*?)(\.gz)?$} }.sort.uniq.collect do |sect| 131 | page = `#{e_sh SUPPORT}/bin/html_man.sh #{sect} #{query}` 132 | puts "#{query}(#{sect})" 133 | Man.new(page, 'C', "#{query}(#{sect})") 134 | end 135 | else 136 | nil 137 | end 138 | end 139 | 140 | Cxx = Struct.new(:url, :language, :title, :klass) 141 | 142 | def cxx_lookup (query) 143 | # find . -path './algorithm/start' -prune -or -type f -regex '\./.*/.*' -print|perl -pe 's|^./||; s|^algorithm/([a-z0-9_]+)$|$1\tstd::$1\thttp://www.cppreference.com/wiki/stl/$&|; s|^([a-z_]+)/start$|$1\tstd::$1\thttp://www.cppreference.com/wiki/stl/$&|; s|^([a-z_]+)/([a-z0-9_]+)$|$2\tstd::$1::$2\thttp://www.cppreference.com/wiki/stl/$&|' 144 | File.open("#{ENV['TM_BUNDLE_SUPPORT']}/CppReferenceWiki.tsf").grep(/^#{Regexp.escape query}\t([^\t]+)\t([^\t]+)$/) do 145 | Cxx.new($2, 'C++', $1, query) 146 | end 147 | end 148 | 149 | def get_user_selected_reference (class_names) 150 | plist = {'menuItems' => class_names}.to_plist 151 | res = OSX::PropertyList::load(%x{"$DIALOG" -up #{e_sh plist} }) 152 | res['selectedMenuItem'] ? res['selectedMenuItem']['url'] : nil 153 | end 154 | 155 | def search_docs_all(query) 156 | return nil if query.to_s.empty? 157 | 158 | results = search_docs(query) 159 | results.reject! { |e| e.url =~ %r{^/usr/share/man/|/ManPages/} } 160 | results.reject! { |e| e.language =~ /^Java(Script)?|Swift$/ } 161 | 162 | man = man_page(query) 163 | results << man if man 164 | 165 | results << cxx_lookup(query) 166 | 167 | return results.flatten 168 | end 169 | 170 | def documentation_for_word 171 | query = ENV['TM_SELECTED_TEXT'] || ENV['TM_CURRENT_WORD'] 172 | query = $& if query.to_s =~ /\w*/ 173 | 174 | if query.to_s.empty? 175 | query = %x{ /usr/bin/pbpaste -pboard find } 176 | query = $& if query =~ /\w+/ 177 | query = TextMate::UI.request_string :title => "Documentation Search", :default => query, :prompt => "Search documentation for word" 178 | TextMate.exit_discard if query.nil? 179 | end 180 | 181 | results = search_docs_all(query) 182 | show_document(results, query) 183 | end 184 | 185 | def documentation_for_selector 186 | lines = STDIN.readlines 187 | 188 | # selector = doc[(start_char + 1)...end_char] 189 | selector = lines.join(" ")[1..-2] 190 | 191 | # Whittle out everything but the selectors. 192 | selector.gsub!(/\n/m, ' ') # remove newlines 193 | selector.gsub!(/".*"\]/, ' ') # remove any string constants (may hold :) 194 | selector.gsub!(/@selector\([^\)]+\)/, '') # remove @selector()s 195 | selector.gsub!(/\[.*?\]/, ' ') # remove nested messages 196 | query = selector.scan(/\w+:/).join 197 | 198 | if query == '' 199 | # Must have a message with no : in it, i.e. [fred init] 200 | query = selector[/\w+\s*$/] 201 | end 202 | 203 | results = search_docs(query) 204 | 205 | # Filter out the non Objective-C responses. 206 | results.delete_if {|r| r.language != 'Objective-C'} 207 | 208 | show_document(results, query) 209 | end 210 | 211 | -------------------------------------------------------------------------------- /Support/objcParser.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby18 2 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 3 | require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes" 4 | 5 | class Lexer 6 | include Enumerable 7 | def initialize 8 | @label = nil 9 | @pattern = nil 10 | @handler = nil 11 | @input = nil 12 | 13 | reset 14 | 15 | yield self if block_given? 16 | end 17 | 18 | def input(&reader) 19 | if @input.is_a? self.class 20 | @input.input(&reader) 21 | else 22 | class << reader 23 | alias_method :next, :call 24 | end 25 | 26 | @input = reader 27 | end 28 | end 29 | 30 | def add_token(label, pattern, &handler) 31 | unless @label.nil? 32 | @input = clone 33 | end 34 | 35 | @label = label 36 | @pattern = /(#{pattern})/ 37 | @handler = handler || lambda { |label, match| [label, match] } 38 | 39 | reset 40 | end 41 | 42 | def next(peek = false) 43 | while @tokens.empty? and not @finished 44 | new_input = @input.next 45 | if new_input.nil? or new_input.is_a? String 46 | @buffer += new_input unless new_input.nil? 47 | new_tokens = @buffer.split(@pattern) 48 | while new_tokens.size > 2 or (new_input.nil? and not new_tokens.empty?) 49 | @tokens << new_tokens.shift 50 | @tokens << @handler[@label, new_tokens.shift] unless new_tokens.empty? 51 | end 52 | @buffer = new_tokens.join 53 | @finished = true if new_input.nil? 54 | else 55 | separator, new_token = @buffer.split(@pattern) 56 | new_token = @handler[@label, new_token] unless new_token.nil? 57 | @tokens.push( *[ separator, 58 | new_token, 59 | new_input ].select { |t| not t.nil? and t != "" } ) 60 | reset(:buffer) 61 | end 62 | end 63 | peek ? @tokens.first : @tokens.shift 64 | end 65 | 66 | def peek 67 | self.next(true) 68 | end 69 | 70 | def each 71 | while token = self.next 72 | yield token 73 | end 74 | end 75 | 76 | private 77 | 78 | def reset(*attrs) 79 | @buffer = String.new if attrs.empty? or attrs.include? :buffer 80 | @tokens = Array.new if attrs.empty? or attrs.include? :tokens 81 | @finished = false if attrs.empty? or attrs.include? :finished 82 | end 83 | end 84 | 85 | 86 | class ObjcParser 87 | 88 | attr_reader :list 89 | def initialize(args) 90 | @list = args 91 | end 92 | 93 | def get_position 94 | return nil,nil if @list.empty? 95 | has_message = true 96 | 97 | a = @list.pop 98 | endings = [:close,:post_op,:at_string,:at_selector,:identifier] 99 | openings = [:open,:return,:control] 100 | if a.tt == :identifier && !@list.empty? && endings.include?(@list[-1].tt) 101 | insert_point = find_object_start 102 | else 103 | @list << a 104 | has_message = false unless methodList 105 | insert_point = find_object_start 106 | end 107 | return insert_point, has_message 108 | end 109 | 110 | def methodList 111 | old = Array.new(@list) 112 | 113 | a = selector_loop(@list) 114 | if !a.nil? && a.tt == :selector 115 | if file_contains_selector? a.text 116 | return true 117 | else 118 | internal = Array.new(@list) 119 | b = a.text 120 | until internal.empty? 121 | tmp = selector_loop(internal) 122 | return true if tmp.nil? 123 | b = tmp.text + b 124 | if file_contains_selector? b 125 | @list = internal 126 | return true 127 | end 128 | end 129 | end 130 | else 131 | end 132 | @list = old 133 | return false 134 | end 135 | 136 | def file_contains_selector?(methodName) 137 | fileNames = ["#{ENV['TM_BUNDLE_SUPPORT']}/CocoaMethods.txt.gz"] 138 | userMethods = "#{ENV['TM_PROJECT_DIRECTORY']}/.methods.TM_Completions.txt.gz" 139 | 140 | fileNames += [userMethods] if File.exists? userMethods 141 | candidates = [] 142 | fileNames.each do |fileName| 143 | zGrepped = %x{zgrep ^#{e_sh methodName }[[:space:]] #{e_sh fileName }} 144 | candidates += zGrepped.split("\n") 145 | end 146 | 147 | return !candidates.empty? 148 | end 149 | 150 | def selector_loop(l) 151 | until l.empty? 152 | obj = l.pop 153 | case obj.tt 154 | when :selector 155 | return obj 156 | when :close 157 | return nil if match_bracket(obj.text,l).nil? 158 | when :open 159 | return nil 160 | end 161 | end 162 | return nil 163 | end 164 | 165 | def match_bracket(type,l) 166 | partner = {"]"=>"[",")"=>"(","}"=>"{"}[type] 167 | up = 1 168 | until l.empty? 169 | obj = l.pop 170 | case obj.text 171 | when type 172 | up +=1 173 | when partner 174 | up -=1 175 | end 176 | return obj.beg if up == 0 177 | end 178 | end 179 | 180 | def find_object_start 181 | openings = [:operator,:selector,:open,:return,:control,:terminator] 182 | until @list.empty? || openings.include?(@list[-1].tt) 183 | obj = @list.pop 184 | case obj.tt 185 | when :close 186 | tmp = match_bracket(obj.text, @list) 187 | b = tmp unless tmp.nil? 188 | when :star 189 | b, ate = eat_star(b,obj.beg) 190 | return b unless ate 191 | when :nil 192 | b = nil 193 | else 194 | b = obj.beg 195 | end 196 | end 197 | return b 198 | end 199 | 200 | def eat_star(prev, curr) 201 | openings = [:operator,:selector,:open,:return,:control,:star,:terminator] 202 | if @list.empty? || openings.include?(@list[-1].tt) 203 | return curr, true 204 | else 205 | return prev, false 206 | end 207 | end 208 | end 209 | -------------------------------------------------------------------------------- /Support/objc_selector_completion2.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby18 2 | require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes" 3 | require "#{ENV['TM_SUPPORT_PATH']}/lib/escape" 4 | require "#{ENV['TM_SUPPORT_PATH']}/lib/ui" 5 | 6 | class ObjcSelectorCompletion 7 | def initialize(line, caret_placement) 8 | @full = line 9 | if ENV['TM_INPUT_START_LINE'] 10 | tmp = ENV['TM_LINE_NUMBER'].to_i - ENV['TM_INPUT_START_LINE'].to_i 11 | else 12 | tmp = 0 13 | end 14 | l = line.split("\n") 15 | if l.empty? 16 | @line = "" 17 | else 18 | @line = l[tmp] 19 | end 20 | @car = caret_placement 21 | end 22 | 23 | def prettify(cand, call) 24 | stuff = cand.split("\t") 25 | out = stuff[0] 26 | return [out.chomp.strip, stuff[0], cand] 27 | end 28 | 29 | def snippet_generator(cand, start, call) 30 | stuff = cand[start..-1].split("\t") 31 | out = stuff[0] 32 | out = out.chomp.strip + "$0" 33 | return out 34 | end 35 | 36 | def pop_up(candidates, searchTerm, call = true) 37 | start = searchTerm.size 38 | prettyCandidates = candidates.map { |candidate| prettify(candidate,call) }.sort 39 | 40 | if prettyCandidates.size > 1 41 | require "enumerator" 42 | pruneList = [] 43 | 44 | prettyCandidates.each_cons(2) do |a| 45 | pruneList << (a[0][0] != a[1][0]) # check if prettified versions are the same 46 | end 47 | pruneList << true 48 | ind = -1 49 | prettyCandidates = prettyCandidates.select do |a| #remove duplicates 50 | pruneList[ind+=1] 51 | end 52 | end 53 | prettyCandidates = prettyCandidates.sort {|x,y| x[1].downcase <=> y[1].downcase } 54 | if prettyCandidates.size > 1 55 | #index = start 56 | #test = false 57 | #while !test 58 | # candidates.each_cons(2) do |a,b| 59 | # break if test = (a[index].chr != b[index].chr || a[index].chr == "\t") 60 | # end 61 | # break if test 62 | # searchTerm << candidates[0][index].chr 63 | # index +=1 64 | #end 65 | show_dialog(prettyCandidates, searchTerm, start) 66 | 67 | else 68 | snippet_generator( candidates[0], start, call ) 69 | end 70 | end 71 | 72 | def show_dialog(prettyCandidates,searchTerm,start) 73 | require "#{ENV['TM_SUPPORT_PATH']}/lib/osx/plist" 74 | pl = prettyCandidates.map { |pretty , junk1, junk2| { 'display' => junk1} } 75 | 76 | flags = {} 77 | flags[:extra_chars]= '_:' 78 | flags[:initial_filter]= searchTerm 79 | TextMate::UI.complete(pl, flags) 80 | 81 | TextMate.exit_discard 82 | 83 | end 84 | 85 | def candidates_or_exit(methodSearch, list, fileNames, notif = false) 86 | x = candidate_list(methodSearch, list, fileNames, notif) 87 | TextMate.exit_show_tool_tip "No completion available" if x.empty? 88 | return x 89 | end 90 | 91 | def candidate_list(methodSearch, list, fileNames, notif = false) 92 | candidates = [] 93 | fileNames.each do |fileName| 94 | zGrepped = %x{ zgrep ^#{e_sh methodSearch } #{e_sh ENV['TM_BUNDLE_SUPPORT']}/#{fileName} } 95 | candidates += zGrepped.split("\n") 96 | end 97 | # strip notifications 98 | if notif 99 | candidates = candidates.select {|cand| cand.match(/\tno\t/) } 100 | else 101 | candidates = candidates.reject {|cand| cand.match(/\tno\t/) } 102 | end 103 | return [] if candidates.empty? 104 | if list.nil? 105 | return candidates 106 | else 107 | n = [] 108 | candidates.each do |cand| 109 | n << cand if list.include?(cand.split("\t")[0]) 110 | end 111 | n = (n.empty? ? candidates : n) 112 | 113 | return n 114 | end 115 | end 116 | 117 | def print 118 | line = @line 119 | caret_placement = @car 120 | methodDeclaration = /^(?:@selector\()([_a-zA-Z][a-zA-Z0-9:]*)$/ 121 | 122 | if k = line[0..caret_placement].match(methodDeclaration) 123 | candidates = candidates_or_exit( k[1], nil, "CocoaMethods.txt.gz") 124 | res =pop_up(candidates, k[1]) 125 | TextMate.exit_discard if res == "$0" 126 | e_sn(line[0..caret_placement]) + res + e_sn(line[caret_placement + 1 .. -1]) 127 | else 128 | TextMate.exit_discard 129 | end 130 | end 131 | end -------------------------------------------------------------------------------- /Support/typedefdump.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby18 2 | 3 | # find /System/Library/Frameworks/{AppKit,Foundation}.framework -name \*.h -exec awk '/\}/ { if(pr) print $0; pr = 0; } { if(pr) print $0; } /^(typedef )enum .*\{[^}]*$/ { print $0 ;pr = 1}' '{}' \;|expand 4 | 5 | # NSStringEncodings are not defined as typedefed enum, add by hand 6 | 7 | str = open("typedefs.txt").read 8 | list = str.split(/\n/) 9 | out = [] 10 | typename = constantname = "" 11 | list.reverse_each do |x| 12 | if x =~ /\}\s*([A-Z][A-Z][a-zA-Z0-9*]*)/ 13 | typename = $1 14 | elsif x =~ /^\s*([A-Z][A-Z][A-Za-z0-9]*)/ 15 | constantname = $1 16 | out << "#{constantname}\t\t#{typename}" 17 | end 18 | end 19 | 20 | f = open("outConstants.txt","w") 21 | out.reverse_each do |x| f.write(x+"\n") end 22 | f.close 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Syntaxes/Objective-C++.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | mm 8 | M 9 | h 10 | 11 | keyEquivalent 12 | ^~O 13 | name 14 | Objective-C++ 15 | patterns 16 | 17 | 18 | include 19 | source.c++ 20 | 21 | 22 | include 23 | source.objc 24 | 25 | 26 | scopeName 27 | source.objc++ 28 | uuid 29 | FDAB1813-6B1C-11D9-BCAC-000D93589AF6 30 | 31 | 32 | -------------------------------------------------------------------------------- /Syntaxes/Strings File.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | strings 8 | 9 | name 10 | Strings File 11 | patterns 12 | 13 | 14 | begin 15 | /\* 16 | captures 17 | 18 | 0 19 | 20 | name 21 | punctuation.definition.comment.strings 22 | 23 | 24 | end 25 | \*/ 26 | name 27 | comment.block.strings 28 | 29 | 30 | begin 31 | " 32 | beginCaptures 33 | 34 | 0 35 | 36 | name 37 | punctuation.definition.string.begin.strings 38 | 39 | 40 | end 41 | " 42 | endCaptures 43 | 44 | 0 45 | 46 | name 47 | punctuation.definition.string.end.strings 48 | 49 | 50 | name 51 | string.quoted.double.strings 52 | patterns 53 | 54 | 55 | match 56 | \\(\\|[abefnrtv'"?]|[0-3]\d{0,2}|[4-7]\d?|x[a-zA-Z0-9]+) 57 | name 58 | constant.character.escape.strings 59 | 60 | 61 | match 62 | \\. 63 | name 64 | invalid.illegal.unknown-escape.strings 65 | 66 | 67 | match 68 | (?x)% 69 | (\d+\$)? # field (argument #) 70 | [#0\- +']* # flags 71 | [,;:_]? # separator character (AltiVec) 72 | ((-?\d+)|\*(-?\d+\$)?)? # minimum field width 73 | (\.((-?\d+)|\*(-?\d+\$)?)?)? # precision 74 | (hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier 75 | [@diouxXDOUeEfFgGaACcSspn%] # conversion type 76 | 77 | name 78 | constant.other.placeholder.strings 79 | 80 | 81 | match 82 | % 83 | name 84 | invalid.illegal.placeholder.c 85 | 86 | 87 | 88 | 89 | scopeName 90 | source.strings 91 | uuid 92 | 429E2DB7-EB4F-4B34-A4DF-DBFD3336C581 93 | 94 | 95 | -------------------------------------------------------------------------------- /Templates/Singleton/class_in.mm: -------------------------------------------------------------------------------- 1 | // 2 | // ${TM_NEW_FILE_BASENAME}.mm 3 | // 4 | // Created by ${TM_FULLNAME} on ${TM_DATE}. 5 | // Copyright (c) ${TM_YEAR} ${TM_ORGANIZATION_NAME}. All rights reserved. 6 | // 7 | 8 | #import "${TM_NEW_FILE_BASENAME}.h" 9 | 10 | static ${TM_NEW_FILE_BASENAME}* SharedInstance; 11 | 12 | @implementation ${TM_NEW_FILE_BASENAME} 13 | + (${TM_NEW_FILE_BASENAME}*)sharedInstance 14 | { 15 | return SharedInstance ?: [[self new] autorelease]; 16 | } 17 | 18 | - (id)init 19 | { 20 | if(SharedInstance) 21 | { 22 | [self release]; 23 | } 24 | else if(self = SharedInstance = [[super init] retain]) 25 | { 26 | /* init code */ 27 | } 28 | return SharedInstance; 29 | } 30 | @end 31 | -------------------------------------------------------------------------------- /Templates/Singleton/header_in.h: -------------------------------------------------------------------------------- 1 | // 2 | // ${TM_NEW_FILE_BASENAME}.h 3 | // 4 | // Created by ${TM_FULLNAME} on ${TM_DATE}. 5 | // Copyright (c) ${TM_YEAR} ${TM_ORGANIZATION_NAME}. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface ${TM_NEW_FILE_BASENAME} : NSObject 11 | { 12 | } 13 | + (${TM_NEW_FILE_BASENAME}*)sharedInstance; 14 | @end 15 | -------------------------------------------------------------------------------- /Templates/Singleton/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | command 6 | export TM_YEAR=`date +%Y` 7 | export TM_DATE=`date +%Y-%m-%d` 8 | TM_HEADER="$TM_NEW_FILE_DIRECTORY/$TM_NEW_FILE_BASENAME.h" 9 | 10 | if [[ ! (-f $TM_NEW_FILE || -f $TM_HEADER) ]]; then 11 | perl -pe 's/\$\{([^}]*)\}/$ENV{$1}/g' <class_in.mm >"$TM_NEW_FILE" 12 | perl -pe 's/\$\{([^}]*)\}/$ENV{$1}/g' <header_in.h >"$TM_HEADER" 13 | fi 14 | extension 15 | mm 16 | files 17 | printf "$TM_NEW_FILE\n$TM_NEW_FILE_DIRECTORY/$TM_NEW_FILE_BASENAME.h" 18 | name 19 | Singleton 20 | uuid 21 | BB1916F0-C021-11D9-93C5-000D93589AF6 22 | 23 | 24 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | contactEmailRot13 6 | gz-ohaqyrf@znpebzngrf.pbz 7 | contactName 8 | Allan Odgaard 9 | deleted 10 | 11 | 5C47CB6C-B163-4911-A8FB-C7EC64D8452B 12 | 06EDD9CF-2BD0-4A08-8BD9-FB6ABDCABE78 13 | FEB8D9A0-AC6A-4409-B352-D032D7E7445A 14 | 20805689-463C-4738-833E-009FB0943674 15 | A975FA00-98FE-11D9-9BB8-000A95A89C98 16 | 30C95C78-256F-49B9-B316-2B88CF38CA45 17 | 18 | description 19 | The language used for writing Cocoa applications. This bundle supports documentation lookups, method completion, and more. 20 | mainMenu 21 | 22 | excludedItems 23 | 24 | A3555C49-D367-4CF5-8032-13B291820CD3 25 | 478FBA1D-C11C-4D53-BE95-8B8ABB5F15DC 26 | 88754B0F-D8DB-4796-9D02-058B756C606D 27 | 30E93FBA-5A81-4D94-8A03-9CD46FCA3CFA 28 | 8AF46225-833C-473E-8EEC-F21C581636F6 29 | 8957C99F-88F5-42CC-B355-AAC6BF3FDF8D 30 | 122E10C1-DFA2-4A9E-9B17-8EBFA6E10CC7 31 | 35EB2F86-DEA0-443B-8DC2-4815F0478F67 32 | 013BFEBB-A744-46F1-94A5-F851635E00FA 33 | BA432891-294B-47A4-BECF-F3C95B3766C1 34 | C125E6DB-7FB5-4B19-8648-0A5617B1B5BC 35 | 325B0A2B-5939-4805-80A1-6DED5B373283 36 | 9D01148D-1073-40D2-936E-FFF67580D2B3 37 | 38 | items 39 | 40 | AFB40870-6F83-4211-9362-0538287B52A9 41 | 2E0F350A-7B23-11D9-B084-000D93589AF6 42 | ------------------------------------ 43 | 8EEE9B1D-1A26-4F2E-87D4-00379808AB03 44 | 7BA1259D-4C54-430B-8502-4D29631AC01E 45 | 7C8F9639-AEFD-4940-9759-3869FFF84E48 46 | 6506492D-4A59-4760-B8A4-25F7D8BEB3E0 47 | 858559E0-22A9-4C2D-8C35-B8078B13A9DE 48 | ------------------------------------ 49 | EA820F17-FD1D-4E7A-9961-E75F7D360968 50 | DA9B35AF-938D-4166-8576-E8E3C73F0739 51 | DB16585F-4D78-412B-B468-38AD54C254B5 52 | CB5EC7EC-35B7-4FD8-9045-31CCC379D474 53 | D9CA98D1-7564-4CCB-8156-9A06210A1A7F 54 | E802FA1A-1E2E-4F8A-957F-C1533CE57400 55 | ------------------------------------ 56 | 7829F2EC-B8BA-11D9-AE51-000393A143CC 57 | ------------------------------------ 58 | 42B1691B-DC28-4743-9B18-C8D51B70722C 59 | C5624A26-E661-46EE-AA6A-14E6B678CFF9 60 | F929835A-C9F7-4934-87BD-05FD11C4435B 61 | 62 | submenus 63 | 64 | 6506492D-4A59-4760-B8A4-25F7D8BEB3E0 65 | 66 | items 67 | 68 | BC8B9CAD-5F16-11D9-B9C3-000D93589AF6 69 | BC8B9D3A-5F16-11D9-B9C3-000D93589AF6 70 | 917BA9ED-9A62-11D9-9A65-000A95A89C98 71 | B07879C7-F1E0-4606-93F1-1A948965CD0E 72 | 73 | name 74 | Object Instantiations 75 | 76 | 7BA1259D-4C54-430B-8502-4D29631AC01E 77 | 78 | items 79 | 80 | EE603767-8BA3-4F54-8DE5-0C9E64BE5DF7 81 | C0B942C9-07CE-46B6-8FAE-CB8496F9F544 82 | ------------------------------------ 83 | 563B2FDB-A163-46FE-9380-4178EFC1AD14 84 | 5449EC50-98FE-11D9-9BB8-000A95A89C98 85 | 65844040-1D13-4F29-98CC-E742F151527F 86 | DADC6C91-415F-463A-9C24-7A059BB5EE56 87 | ------------------------------------ 88 | DECC6BAC-94AF-429A-8609-D101C940D18D 89 | 90 | name 91 | Accessor Methods For 92 | 93 | 7C8F9639-AEFD-4940-9759-3869FFF84E48 94 | 95 | items 96 | 97 | 59FC2842-A645-11D9-B2CB-000D93589AF6 98 | E8107901-70F1-45D9-8633-81BD5E57CC89 99 | 25AD69B4-905B-4EBC-A3B3-0BAB6D8BDD75 100 | ------------------------------------ 101 | 3EF96A1F-B597-11D9-A114-000D93589AF6 102 | 53672612-B597-11D9-A114-000D93589AF6 103 | ------------------------------------ 104 | 1251B7E8-6BF0-11D9-8384-000D93589AF6 105 | 9EF84198-BDAF-11D9-9140-000D93589AF6 106 | 107 | name 108 | Common Method Calls 109 | 110 | 858559E0-22A9-4C2D-8C35-B8078B13A9DE 111 | 112 | items 113 | 114 | 3F57DB1B-9373-46A6-9B6E-19F2D25658DE 115 | F2D5B215-2C10-40BC-B973-0A859A3E3CBD 116 | D402B10A-149B-414D-9961-110880389A8E 117 | ------------------------------------ 118 | 171FBCAE-0D6F-4D42-B24F-871E3BB6DFF0 119 | 622842E6-11F7-4D7B-A322-F1B8A1FE8CE5 120 | 121 | name 122 | Idioms 123 | 124 | 8EEE9B1D-1A26-4F2E-87D4-00379808AB03 125 | 126 | items 127 | 128 | 20241464-7299-11D9-813A-000D93589AF6 129 | 1E3A92DA-7299-11D9-813A-000D93589AF6 130 | ------------------------------------ 131 | BC8B9C24-5F16-11D9-B9C3-000D93589AF6 132 | BE0B2832-D88E-40BF-93EE-281DDA93840B 133 | 06F15373-9900-11D9-9BB8-000A95A89C98 134 | 27AC6270-9900-11D9-9BB8-000A95A89C98 135 | 3E270C37-E7E2-4D1D-B28F-CEDD8DE0041C 136 | 596B13EC-9900-11D9-9BB8-000A95A89C98 137 | ------------------------------------ 138 | BC8B9DD7-5F16-11D9-B9C3-000D93589AF6 139 | 366DBAB0-554B-4A38-966E-793DFE13A1EC 140 | 1251B9E2-6BF0-11D9-8384-000D93589AF6 141 | BC8B9E72-5F16-11D9-B9C3-000D93589AF6 142 | ------------------------------------ 143 | 30C260A7-AFB1-11D9-9D48-000D93589AF6 144 | 145 | name 146 | Language Boilerplate 147 | 148 | 149 | 150 | name 151 | Objective-C 152 | ordering 153 | 154 | 2E0F350A-7B23-11D9-B084-000D93589AF6 155 | 8AF46225-833C-473E-8EEC-F21C581636F6 156 | 8957C99F-88F5-42CC-B355-AAC6BF3FDF8D 157 | 122E10C1-DFA2-4A9E-9B17-8EBFA6E10CC7 158 | EA820F17-FD1D-4E7A-9961-E75F7D360968 159 | DA9B35AF-938D-4166-8576-E8E3C73F0739 160 | DB16585F-4D78-412B-B468-38AD54C254B5 161 | 7829F2EC-B8BA-11D9-AE51-000393A143CC 162 | 20241464-7299-11D9-813A-000D93589AF6 163 | 1E3A92DA-7299-11D9-813A-000D93589AF6 164 | 1251B7E8-6BF0-11D9-8384-000D93589AF6 165 | A3555C49-D367-4CF5-8032-13B291820CD3 166 | BC8B9C24-5F16-11D9-B9C3-000D93589AF6 167 | 06F15373-9900-11D9-9BB8-000A95A89C98 168 | BE0B2832-D88E-40BF-93EE-281DDA93840B 169 | 27AC6270-9900-11D9-9BB8-000A95A89C98 170 | 596B13EC-9900-11D9-9BB8-000A95A89C98 171 | 3E270C37-E7E2-4D1D-B28F-CEDD8DE0041C 172 | BC8B9CAD-5F16-11D9-B9C3-000D93589AF6 173 | BC8B9D3A-5F16-11D9-B9C3-000D93589AF6 174 | 917BA9ED-9A62-11D9-9A65-000A95A89C98 175 | BC8B9DD7-5F16-11D9-B9C3-000D93589AF6 176 | 325B0A2B-5939-4805-80A1-6DED5B373283 177 | 1251B9E2-6BF0-11D9-8384-000D93589AF6 178 | 9D01148D-1073-40D2-936E-FFF67580D2B3 179 | BC8B9E72-5F16-11D9-B9C3-000D93589AF6 180 | 366DBAB0-554B-4A38-966E-793DFE13A1EC 181 | 65844040-1D13-4F29-98CC-E742F151527F 182 | 013BFEBB-A744-46F1-94A5-F851635E00FA 183 | 5449EC50-98FE-11D9-9BB8-000A95A89C98 184 | 35EB2F86-DEA0-443B-8DC2-4815F0478F67 185 | 563B2FDB-A163-46FE-9380-4178EFC1AD14 186 | DECC6BAC-94AF-429A-8609-D101C940D18D 187 | C125E6DB-7FB5-4B19-8648-0A5617B1B5BC 188 | DADC6C91-415F-463A-9C24-7A059BB5EE56 189 | BA432891-294B-47A4-BECF-F3C95B3766C1 190 | 3EF96A1F-B597-11D9-A114-000D93589AF6 191 | 53672612-B597-11D9-A114-000D93589AF6 192 | 30C260A7-AFB1-11D9-9D48-000D93589AF6 193 | EE603767-8BA3-4F54-8DE5-0C9E64BE5DF7 194 | C0B942C9-07CE-46B6-8FAE-CB8496F9F544 195 | 59FC2842-A645-11D9-B2CB-000D93589AF6 196 | E8107901-70F1-45D9-8633-81BD5E57CC89 197 | 3F57DB1B-9373-46A6-9B6E-19F2D25658DE 198 | E0C97B6C-E546-4B73-9BEE-1207F6F920C3 199 | 9EF84198-BDAF-11D9-9140-000D93589AF6 200 | 171FBCAE-0D6F-4D42-B24F-871E3BB6DFF0 201 | 622842E6-11F7-4D7B-A322-F1B8A1FE8CE5 202 | B07879C7-F1E0-4606-93F1-1A948965CD0E 203 | F2D5B215-2C10-40BC-B973-0A859A3E3CBD 204 | 25AD69B4-905B-4EBC-A3B3-0BAB6D8BDD75 205 | D402B10A-149B-414D-9961-110880389A8E 206 | F85CC716-6B1C-11D9-9A20-000D93589AF6 207 | FDAB1813-6B1C-11D9-BCAC-000D93589AF6 208 | 429E2DB7-EB4F-4B34-A4DF-DBFD3336C581 209 | 512175CE-933E-4312-BBF2-D744700CB4CA 210 | ADFCD53A-3CC4-4C31-88C4-BB607684951A 211 | BB1916F0-C021-11D9-93C5-000D93589AF6 212 | 478FBA1D-C11C-4D53-BE95-8B8ABB5F15DC 213 | 30E93FBA-5A81-4D94-8A03-9CD46FCA3CFA 214 | 88754B0F-D8DB-4796-9D02-058B756C606D 215 | 42B1691B-DC28-4743-9B18-C8D51B70722C 216 | E802FA1A-1E2E-4F8A-957F-C1533CE57400 217 | 0D675D9D-B93C-400D-B8D6-C9888F7FAAE4 218 | C41409C1-97FD-4326-A8E9-7BF89ED6BEAF 219 | AFB40870-6F83-4211-9362-0538287B52A9 220 | F929835A-C9F7-4934-87BD-05FD11C4435B 221 | C5624A26-E661-46EE-AA6A-14E6B678CFF9 222 | CB5EC7EC-35B7-4FD8-9045-31CCC379D474 223 | D9CA98D1-7564-4CCB-8156-9A06210A1A7F 224 | 225 | require 226 | 227 | 228 | name 229 | C 230 | uuid 231 | 4675A940-6227-11D9-BFB1-000D93589AF6 232 | 233 | 234 | uuid 235 | 4679484F-6227-11D9-BFB1-000D93589AF6 236 | 237 | 238 | --------------------------------------------------------------------------------