├── Commands ├── Align column assignments.tmCommand ├── Complete across current open files.tmCommand ├── Ensure trailing newline on save.tmCommand ├── Open Project in Terminal.tmCommand ├── Open file as reference.tmCommand ├── Open global _tm_properties.tmCommand ├── Open project _tm_properties.tmCommand ├── Save Project.tmCommand ├── Strip trailing whitespace on save.tmCommand └── Toggle Status Bar.tmCommand ├── MIT-LICENSE ├── Macros ├── Move down with cursor.tmMacro ├── Move to BOL and Insert LF.tmMacro └── Move up.tmMacro ├── Preferences └── Completion: Character Class indifferent.tmPreferences ├── README.md ├── Support └── lib │ └── doctohtml.rb └── info.plist /Commands/Align column assignments.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | # 10 | # Assignment block tidier, version 0.1. 11 | # 12 | # Copyright Chris Poirier 2006. 13 | # Licensed under the Academic Free License version 3.0. 14 | # 15 | # This script can be used as a command for TextMate to align all 16 | # of the equal signs within a block of text. When using it with 17 | # TextMate, set the command input to "Selected Text" or "Document", 18 | # and the output to "Replace Selected Text". Map it to a key 19 | # equivalent, and any time you want to tidy up a block, either 20 | # select it, or put your cursor somewhere within it; then hit the 21 | # key equivalent. Voila. 22 | # 23 | # Note that this is the first version of the script, and it hasn't 24 | # been heavily tested. You might encounter a bug or two. 25 | # 26 | # Per the license, use of this script is ENTIRELY at your own risk. 27 | # See the license for full details (they override anything I've 28 | # said here). 29 | 30 | lines = STDIN.readlines 31 | selected_text = ENV.member?("TM_SELECTED_TEXT") 32 | 33 | relevant_line_pattern = /^[^:]+:[^:]/ 34 | column_search_pattern = /\w:/ 35 | 36 | 37 | # 38 | # If called on a selection, every assignment statement 39 | # is in the block. If called on the document, we start on the 40 | # current line and look up and down for the start and end of the 41 | # block. 42 | 43 | if selected_text then 44 | block_top = 1 45 | block_bottom = lines.length 46 | else 47 | 48 | # 49 | # We start looking on the current line. However, if the 50 | # current line doesn't match the pattern, we may be just 51 | # after or just before a block, and we should check. If 52 | # neither, we are done. 53 | 54 | start_on = ENV["TM_LINE_NUMBER"].to_i 55 | block_top = lines.length + 1 56 | block_bottom = 0 57 | search_top = 1 58 | search_bottom = lines.length 59 | search_failed = false 60 | 61 | if lines[start_on - 1] !~ relevant_line_pattern then 62 | if lines[start_on - 2] =~ relevant_line_pattern then 63 | search_bottom = start_on = start_on - 1 64 | elsif lines[start_on] =~ relevant_line_pattern then 65 | search_top = start_on = start_on 66 | else 67 | search_failed = true 68 | end 69 | end 70 | 71 | # 72 | # Now with the search boundaries set, start looking for 73 | # the block top and bottom. 74 | 75 | unless search_failed 76 | start_on.downto(search_top) do |number| 77 | if lines[number-1] =~ relevant_line_pattern then 78 | block_top = number 79 | else 80 | break 81 | end 82 | end 83 | 84 | start_on.upto(search_bottom) do |number| 85 | if lines[number-1] =~ relevant_line_pattern then 86 | block_bottom = number 87 | else 88 | break 89 | end 90 | end 91 | end 92 | end 93 | 94 | 95 | # 96 | # Now, iterate over the block and find the best column number 97 | # for the = sign. The pattern will tell us the position of the 98 | # first bit of whitespace before the equal sign. We put the 99 | # equals sign to the right of the furthest-right one. Note that 100 | # we cannot assume every line in the block is relevant. 101 | 102 | best_column = 0 103 | block_top.upto(block_bottom) do |number| 104 | line = lines[number - 1] 105 | if line =~ relevant_line_pattern then 106 | m = column_search_pattern.match(line) 107 | best_column = m.begin(0) if m.begin(0) > best_column 108 | end 109 | end 110 | 111 | 112 | # 113 | # Reformat the block. Again, we cannot assume all lines in the 114 | # block are relevant. 115 | 116 | split_pattern = /[ \t]*:[ \t]*/ 117 | 118 | block_top.upto(block_bottom) do |number| 119 | if lines[number-1] =~ relevant_line_pattern then 120 | before, after = lines[number-1].split(split_pattern, 2) 121 | lines[number-1] = [(before+': ').ljust(best_column+3), after].join('') 122 | end 123 | end 124 | 125 | 126 | # 127 | # Output the replacement text 128 | 129 | lines.each do |line| 130 | puts line 131 | end 132 | 133 | input 134 | selection 135 | inputFormat 136 | text 137 | isDisabled 138 | 139 | keyEquivalent 140 | ^~@] 141 | name 142 | Align column assignments 143 | outputCaret 144 | afterOutput 145 | outputFormat 146 | text 147 | outputLocation 148 | replaceInput 149 | scope 150 | source 151 | uuid 152 | D28A5629-8967-4CC4-9CCA-E7766D2E35E4 153 | version 154 | 2 155 | 156 | 157 | -------------------------------------------------------------------------------- /Commands/Complete across current open files.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | @loader = Thread.new { require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' } 11 | 12 | project_dir = ENV['TM_PROJECT_DIRECTORY'] 13 | current_word = ENV["TM_CURRENT_WORD"].to_s.scan(/([\w_]+)/).flatten.last 14 | exit if current_word.nil? 15 | 16 | regexp = /\b(#{Regexp.escape current_word}[\w_]+)/ 17 | 18 | open_files = `lsof +D "#{project_dir}" -a -c TextMate -Fn`.split("\n").map do |line| 19 | next unless line =~ /^n/ 20 | line = line[1..-1].strip # lines are printed by `lsof` with a leading "n" because of `-Fn` 21 | next if File.directory? line 22 | line 23 | end.compact 24 | 25 | choices = open_files.map do |file_name| 26 | Thread.new do 27 | file_contents = File.read(file_name) 28 | file_contents.scan(regexp).flatten 29 | end 30 | end.map {|t| t.join; t.value} 31 | 32 | @loader.join 33 | 34 | choices.flatten!.uniq! 35 | if choices.size == 1 36 | print choices.first[current_word.size..-1] 37 | else 38 | TextMate::UI.complete(choices, :initial_filter => current_word) 39 | end 40 | 41 | input 42 | word 43 | inputFormat 44 | text 45 | keyEquivalent 46 | ^ 47 | name 48 | Complete across current tabs 49 | outputCaret 50 | afterOutput 51 | outputFormat 52 | text 53 | outputLocation 54 | afterInput 55 | uuid 56 | A9BE20F2-425D-4734-82EB-A5A67FF4F607 57 | version 58 | 2 59 | 60 | 61 | -------------------------------------------------------------------------------- /Commands/Ensure trailing newline on save.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | command 6 | #!/usr/bin/env ruby18 -wKU 7 | 8 | content = STDIN.read 9 | 10 | if ENV['TM_ENSURE_TRAILING_NEWLINE_ON_SAVE'] == 'true' 11 | content << "\n" unless content.end_with? "\n" 12 | end 13 | 14 | print content 15 | 16 | input 17 | document 18 | name 19 | Ensure trailing newline on save 20 | outputCaret 21 | interpolateByLine 22 | outputLocation 23 | replaceDocument 24 | semanticClass 25 | callback.document.will-save 26 | uuid 27 | B0C7D023-CB2B-4A76-BDA1-EDF87D3A3AD5 28 | 29 | 30 | -------------------------------------------------------------------------------- /Commands/Open Project in Terminal.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env bash 9 | 10 | env -i open "$TM_PROJECT_DIRECTORY" -a "${TM_TERMINAL_APP:-Terminal.app}" 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | keyEquivalent 17 | ^~@t 18 | name 19 | Open Project in Terminal 20 | outputCaret 21 | afterOutput 22 | outputFormat 23 | text 24 | outputLocation 25 | toolTip 26 | uuid 27 | F2C95C06-3A20-41DF-A192-AF59906E20D3 28 | version 29 | 2 30 | 31 | 32 | -------------------------------------------------------------------------------- /Commands/Open file as reference.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -rjcode -wKU 9 | 10 | require "#{ENV['TM_BUNDLE_SUPPORT']}/lib/doctohtml.rb" 11 | require "#{ENV['TM_SUPPORT_PATH']}/lib/progress.rb" 12 | unit = ENV.has_key?('TM_SELECTED_TEXT') ? 'selection' : 'document' 13 | html = nil 14 | TextMate.call_with_progress(:message => "Creating HTML version of #{unit}…") do 15 | html = document_to_html( STDIN.read, :include_css => !ENV.has_key?('TM_SELECTED_TEXT') ) 16 | end 17 | 18 | puts html 19 | 20 | input 21 | document 22 | inputFormat 23 | xml 24 | keyEquivalent 25 | ^~@l 26 | name 27 | Keep current file as reference (…waiting for split panes) 28 | outputCaret 29 | afterOutput 30 | outputFormat 31 | html 32 | outputLocation 33 | newWindow 34 | uuid 35 | A42F5C67-B0A0-46FC-B181-A450AF3128C4 36 | version 37 | 2 38 | 39 | 40 | -------------------------------------------------------------------------------- /Commands/Open global _tm_properties.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | path = File.expand_path('~/.tm_properties') 11 | system 'touch', path 12 | system 'open', "txmt://open?url=file://#{path}" 13 | input 14 | none 15 | inputFormat 16 | text 17 | keyEquivalent 18 | ~@, 19 | name 20 | Open global .tm_properties 21 | outputCaret 22 | afterOutput 23 | outputFormat 24 | text 25 | outputLocation 26 | discard 27 | uuid 28 | EA02BF9B-ECD7-4B2A-9432-9C7B220E460D 29 | version 30 | 2 31 | 32 | 33 | -------------------------------------------------------------------------------- /Commands/Open project _tm_properties.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | project_dir = ENV['TM_PROJECT_DIRECTORY'] 11 | 12 | unless project_dir 13 | puts "Not in a project!" 14 | exit 15 | end 16 | 17 | path = File.join(project_dir, '.tm_properties') 18 | system 'touch', path 19 | system 'open', "txmt://open?url=file://#{path}" 20 | 21 | input 22 | none 23 | inputFormat 24 | text 25 | keyEquivalent 26 | ^~@, 27 | name 28 | Open project .tm_properties 29 | outputCaret 30 | afterOutput 31 | outputFormat 32 | text 33 | outputLocation 34 | toolTip 35 | uuid 36 | 2FB5FB79-4B89-48AF-84FE-9832F905C439 37 | version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Commands/Save Project.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | # TM_PROPERTIES 11 | 12 | require 'pathname' 13 | 14 | # puts *ENV.select{|k,v| k =~ /^TM/}.map{|k,v| "#{k} => #{v}"} 15 | tm_properties = File.join(ENV['TM_PROJECT_DIRECTORY'], '.tm_properties') 16 | unless File.exist? tm_properties 17 | File.open(tm_properties, 'w') do |f| 18 | f.puts 'projectDirectory = "$CWD"' 19 | default_properties = ENV['TM_PROJECT_PROPERTIES'] 20 | f.puts default_properties if default_properties 21 | if ENV['AVIAN_MISSING_DEFAULT_WINDOW_TITLE'] 22 | f.puts 'projectName = "${projectDirectory/.*\\///}"' 23 | f.puts 'windowTitle = "$TM_DISPLAYNAME ☛${TM_SCM_BRANCH}' \ 24 | ' [${projectName}]"' 25 | end 26 | end 27 | end 28 | sleep 0.01 29 | system 'open', 'txmt://open?url=file://' << tm_properties << '&line=-1' 30 | 31 | # FAVS 32 | 33 | unless ENV['AVIAN_MISSING_SKIP_FAV'] 34 | project_dir = File.expand_path(ENV['TM_PROJECT_DIRECTORY']) 35 | favorites_dir = File.expand_path( 36 | '~/Library/Application Support/TextMate/Favorites' 37 | ) 38 | favorites = Dir.glob("#{favorites_dir}/*").map do |path| 39 | Pathname.new(path).realpath.to_s 40 | end 41 | unless favorites.include? project_dir 42 | system 'ln', '-s', project_dir, favorites_dir 43 | end 44 | end 45 | 46 | input 47 | none 48 | inputFormat 49 | text 50 | keyEquivalent 51 | ^@s 52 | name 53 | Save Project 54 | outputCaret 55 | afterOutput 56 | outputFormat 57 | text 58 | outputLocation 59 | atCaret 60 | uuid 61 | 2556BFD8-AA62-4950-BFD9-A4D738A0B15A 62 | version 63 | 2 64 | 65 | 66 | -------------------------------------------------------------------------------- /Commands/Strip trailing whitespace on save.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | content = STDIN.read 10 | 11 | if ENV['TM_STRIP_WHITESPACE_ON_SAVE'] == 'true' 12 | content.gsub! /[\t ]+$/, '' 13 | content << "\n" unless content.end_with? "\n" 14 | end 15 | 16 | print content 17 | 18 | input 19 | document 20 | inputFormat 21 | text 22 | name 23 | Strip trailing whitespace on save 24 | outputCaret 25 | interpolateByLine 26 | outputFormat 27 | text 28 | outputLocation 29 | replaceDocument 30 | semanticClass 31 | callback.document.export 32 | uuid 33 | 4B145342-1E44-4B8B-8E28-4F7E1458F546 34 | version 35 | 2 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/Toggle Status Bar.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env bash 9 | (test `defaults read "$TM_APP_IDENTIFIER" hideStatusBar 2> /dev/null` == 1) && 10 | (defaults write "$TM_APP_IDENTIFIER" hideStatusBar -bool NO && echo 'visible.') || 11 | (defaults write "$TM_APP_IDENTIFIER" hideStatusBar -bool YES && echo 'hidden.') 12 | 13 | osascript -e "tell application \"$(basename "$TM_APP_PATH")\" to activate" 14 | input 15 | none 16 | inputFormat 17 | text 18 | name 19 | Toggle Status Bar 20 | outputCaret 21 | afterOutput 22 | outputFormat 23 | text 24 | outputLocation 25 | toolTip 26 | uuid 27 | 3CFDE182-FB93-447F-9AA8-5A84D75E103E 28 | version 29 | 2 30 | 31 | 32 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Elia Schito 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Macros/Move down with cursor.tmMacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | commands 6 | 7 | 8 | command 9 | moveDown: 10 | 11 | 12 | command 13 | moveDown: 14 | 15 | 16 | command 17 | moveDown: 18 | 19 | 20 | command 21 | moveDown: 22 | 23 | 24 | command 25 | moveDown: 26 | 27 | 28 | command 29 | moveDown: 30 | 31 | 32 | command 33 | moveDown: 34 | 35 | 36 | command 37 | moveDown: 38 | 39 | 40 | command 41 | moveDown: 42 | 43 | 44 | command 45 | moveDown: 46 | 47 | 48 | command 49 | moveDown: 50 | 51 | 52 | command 53 | moveDown: 54 | 55 | 56 | command 57 | moveDown: 58 | 59 | 60 | command 61 | moveDown: 62 | 63 | 64 | command 65 | moveDown: 66 | 67 | 68 | command 69 | moveDown: 70 | 71 | 72 | command 73 | moveDown: 74 | 75 | 76 | command 77 | moveDown: 78 | 79 | 80 | command 81 | moveDown: 82 | 83 | 84 | command 85 | centerSelectionInVisibleArea: 86 | 87 | 88 | keyEquivalent 89 | ~ 90 | name 91 | Move down 92 | uuid 93 | FD7919B4-D538-4312-A87D-B4854608EAFE 94 | 95 | 96 | -------------------------------------------------------------------------------- /Macros/Move to BOL and Insert LF.tmMacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | changed 6 | 7 | commands 8 | 9 | 10 | command 11 | moveToBeginningOfLine: 12 | 13 | 14 | command 15 | insertNewline: 16 | 17 | 18 | command 19 | moveUp: 20 | 21 | 22 | argument 23 | a 24 | command 25 | insertText: 26 | 27 | 28 | command 29 | indent: 30 | 31 | 32 | command 33 | deleteBackward: 34 | 35 | 36 | keyEquivalent 37 | ~ 38 | 39 | deleted 40 | 41 | scope 42 | 43 | isDelta 44 | 45 | uuid 46 | DE720B53-107F-4AF8-8768-96D25AEBEE6C 47 | 48 | 49 | -------------------------------------------------------------------------------- /Macros/Move up.tmMacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | commands 6 | 7 | 8 | command 9 | moveUp: 10 | 11 | 12 | command 13 | moveUp: 14 | 15 | 16 | command 17 | moveUp: 18 | 19 | 20 | command 21 | moveUp: 22 | 23 | 24 | command 25 | moveUp: 26 | 27 | 28 | command 29 | moveUp: 30 | 31 | 32 | command 33 | moveUp: 34 | 35 | 36 | command 37 | moveUp: 38 | 39 | 40 | command 41 | moveUp: 42 | 43 | 44 | command 45 | moveUp: 46 | 47 | 48 | command 49 | moveUp: 50 | 51 | 52 | command 53 | moveUp: 54 | 55 | 56 | command 57 | moveUp: 58 | 59 | 60 | command 61 | moveUp: 62 | 63 | 64 | command 65 | moveUp: 66 | 67 | 68 | command 69 | moveUp: 70 | 71 | 72 | command 73 | moveUp: 74 | 75 | 76 | command 77 | moveUp: 78 | 79 | 80 | command 81 | moveUp: 82 | 83 | 84 | command 85 | centerSelectionInVisibleArea: 86 | 87 | 88 | keyEquivalent 89 | ^ 90 | name 91 | Move up 92 | uuid 93 | 14D704E1-2896-4327-89E6-9484AB309A29 94 | 95 | 96 | -------------------------------------------------------------------------------- /Preferences/Completion: Character Class indifferent.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Completion: Character Class indifferent 7 | scope 8 | source, text 9 | settings 10 | 11 | completionCommand 12 | #!/usr/bin/env ruby18 -wKU 13 | word_begin, current_word = ENV["TM_CURRENT_WORD"].scan(/^([^\w_]+)?([\w_]+)/).first 14 | 15 | exit if current_word.nil? 16 | 17 | regexp = /\b(#{Regexp.escape current_word}[\w_]*)/ 18 | current_line = ENV["TM_LINE_NUMBER"].to_i 19 | current_index = ENV["TM_LINE_INDEX"].to_i 20 | pre = "" 21 | post = "" 22 | completions = [] 23 | 24 | STDIN.each_with_index do |line, line_number| 25 | line_number += 1 26 | if line_number < current_line 27 | pre << line 28 | elsif line_number == current_line 29 | pre << line[0...current_index] 30 | post << line[current_index..-1] 31 | else 32 | post << line 33 | end 34 | end 35 | 36 | # contents.scan(regexp).flatten 37 | pre.scan(regexp) do |match| 38 | pos = Regexp.last_match.end(0) 39 | completions << [pre.size-pos, "#{word_begin}#{match}"] 40 | end 41 | 42 | post.scan(regexp) do |match| 43 | pos = Regexp.last_match.begin(0) 44 | completions << [pos, "#{word_begin}#{match}"] 45 | end 46 | 47 | puts completions.sort.map(&:last).uniq 48 | 49 | 50 | uuid 51 | 9DBFFF91-3757-4A47-A46E-786923C3E03C 52 | 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Avian Missing 2 | 3 | ## Installation 4 | 5 | ```bash 6 | gem install tmbundle-manager --pre # sudo might be needed 7 | tmb install elia/avian-missing 8 | ``` 9 | 10 | ### Update 11 | 12 | ```bash 13 | tmb update avian-missing 14 | ``` 15 | 16 | 17 | 18 | ## Usage 19 | 20 | This is a collection of missing features from [TextMate 2.0 Alpha](http://blog.macromates.com/2011/textmate-2-0-alpha/). 21 | This bundle includes: 22 | 23 | ### ⌃⌘S Save Project 24 | 25 | The save project command will now create a `.tm_properties` in the current file browser folder 26 | precompiled with `projectDirectory` set and an example `windowTitle` featuring the 27 | current scm-branch and the `$projectDirectory` basename 28 | 29 | **Example:** 30 | ``` 31 | application.rb ☛master [awesome-app] 32 | ``` 33 | 34 | This command also saves the project in the favorities (accessible with `⌘⇧O`). 35 | 36 | 37 | ### Character class indifferent completion 38 | 39 | TextMate 2 [introduced](http://blog.macromates.com/2012/clever-completion/) strict …err …clever completion, which will not cross boundaries between character classes anymore. For example in Ruby typing `au` and hitting `⎋` for autocompletion will not pick `:auto` or `@autocomplete` since they have a leading `:` and `@` and the belong to the *symbol* and *instance variable* character classes. 40 | 41 | This bundle reintroduces the TM1 behavior. 42 | 43 | 44 | ### ⌃⎋ Cross tab completion 45 | 46 | [RubyAMP](http://code.leadmediapartners.com/) used to have this. 47 | 48 | 49 | ### ⌃⌥⌘T Open Project directory in terminal 50 | 51 | _NOTE: requires OSX Lion_ 52 | 53 | Opens the current project directory in the terminal (not really present in TM1, but useful anyway). 54 | 55 | By default will open Terminal, if you prefer anoter terminal app you can set in `.tm_properties` a variable: `TM_TERMINAL_APP = "iTerm.app"` 56 | 57 | 58 | ### ⌃⌥⌘L Keep current file as reference 59 | 60 | > …waiting for split panes 61 | 62 | Outputs the current source into the bottom html pane, this makes the current file source visible while changing tabs. 63 | 64 | Seems that most of the need for split panes is to keep one file as a reference, this solves this particular issue. 65 | 66 | 67 | ### ⌥⌘, Open the global `.tm_properties` 68 | 69 | Tired of opening `.tm_properties` from the terminal or browsing to it by hand? 70 | 71 | Now you can just hit `⌥⌘,` and bring up your alternative preferences (from you the home folder). 72 | 73 | 74 | ### ⌃⌥⌘, Open the project `.tm_properties` 75 | 76 | Now you can just hit `⌃⌥⌘,` and bring up your alternative preferences (from the current project). 77 | 78 | 79 | ### ⌘S Strip trailing whitespace on save 80 | 81 | Just add `TM_STRIP_WHITESPACE_ON_SAVE = true` to your `.tm_properties`. 82 | Ending newline fix is included. 83 | 84 | **BEWARE:** The command **strips whitespace before writing to disk but not in the editor window**, this is a feature to me 85 | but I understand that some users would prefer to have the editor updated. If you're of that kind you'll have to modify the bundle manually 86 | and replace `callback.document.export` with `callback.document.will-save` 87 | ([screenshot](http://cl.ly/image/0r2s3s3v3d0t/Screen%20Shot%202014-07-21%20at%2001.44.46.png)). 88 | 89 | ### ⌘S Add newline at end of file 90 | 91 | Just add `TM_ENSURE_TRAILING_NEWLINE_ON_SAVE = true` to your `.tm_properties`. 92 | 93 | This won't add a second newline if you also have `TM_STRIP_WHITESPACE_ON_SAVE`. 94 | 95 | ### ⌃⌘N New File⇧⌘N (builtin) 96 | 97 | Removed as ⇧⌘N has been introduced as a builtin command. 98 | 99 | ### ⌥⏎ Insert new line above 100 | 101 | This is like `O` (vs. `o` which is ⌘⏎) in `vim`. 102 | 103 | 104 | 105 |

106 | 107 | 108 | ## Contributing 109 | 110 | 1. Fork it 111 | 2. Create your feature branch (`git checkout -b my-new-feature`) 112 | 3. Commit your changes (`git commit -am 'Added some feature'`) 113 | 4. Push to the branch (`git push origin my-new-feature`) 114 | 5. Create new Pull Request 115 | 116 | 117 | ## Copyright 118 | 119 | Copyright © 2012 Elia Schito. See MIT-LICENSE for details. 120 | -------------------------------------------------------------------------------- /Support/lib/doctohtml.rb: -------------------------------------------------------------------------------- 1 | # By Brad Choate -- http://bradchoate.com/ 2 | 3 | $: << ENV['TM_SUPPORT_PATH'] + '/lib' 4 | require "textmate" 5 | 6 | # Provides CSS-friendly variations of common Mac fonts that you 7 | # may use in TextMate. Feel free to edit these to your liking... 8 | FONT_MAP = { 9 | /\bcourier\b/i => 'Courier, "MS Courier New"', 10 | /\bbitstream.*mono\b/i => '"Bitstream Vera Sans Mono"', 11 | /\bandale\b/i => '"Andale Mono"', 12 | /\bDejaVuSansMono\b/i => '"DejaVu Sans Mono"' 13 | } 14 | 15 | # Search heuristic is based on the Theme Builder bundle's 16 | # "Create for Current Language" command 17 | def theme_plist 18 | @theme_plist ||= OSX::PropertyList.load(File.open(ENV['TM_CURRENT_THEME_PATH'])) 19 | end 20 | 21 | def to_rgba(color) 22 | colors = color.scan(/^#(..)(..)(..)(..)?/) 23 | r = colors[0][0].hex 24 | g = colors[0][1].hex 25 | b = colors[0][2].hex 26 | a = colors[0][3] ? colors[0][3].hex : 253 27 | return "rgba(#{r}, #{g}, #{b}, #{ format '%0.02f', a / 255.0 })" 28 | end 29 | 30 | def generate_stylesheet_from_theme(theme_class = nil) 31 | theme_class = '' if theme_class == nil 32 | require "#{ENV['TM_SUPPORT_PATH']}/lib/osx/plist" 33 | 34 | # Load TM preferences to discover the current theme and font settings 35 | textmate_pref_file = "~/Library/Preferences/#{`defaults read "$TM_APP_PATH/Contents/Info" CFBundleIdentifier`.chomp}.plist" 36 | prefs = OSX::PropertyList.load(File.open(File.expand_path(textmate_pref_file))) 37 | # Load the active theme. Unfortunately, this requires us to scan through 38 | # all discoverable theme files... 39 | unless theme_plist 40 | print "Could not locate your theme file!" 41 | abort 42 | end 43 | 44 | theme_comment = theme_plist['comment'] 45 | theme_name = theme_plist['name'] 46 | theme_class.replace(theme_name) 47 | theme_class.downcase! 48 | theme_class.gsub!(/[^a-z0-9_-]/, '_') 49 | theme_class.gsub!(/_+/, '_') 50 | 51 | font_name = prefs['OakTextViewNormalFontName'] || 'Monaco' 52 | font_size = (prefs['OakTextViewNormalFontSize'] || 11).to_s 53 | font_size.sub!(/\.\d+$/, '') 54 | 55 | FONT_MAP.each do | font_re, font_alt | 56 | if (font_re.match(font_name)) 57 | font_name = font_alt 58 | break 59 | end 60 | end 61 | 62 | font_name = '"' + font_name + '"' if font_name.include?(' ') && 63 | !font_name.include?('"') 64 | 65 | theme_styles = '' 66 | body_fg = '' 67 | body_bg = '' 68 | selection_bg = '' 69 | pre_selector = "pre.textmate-source.#{theme_class}" 70 | 71 | theme_plist['settings'].each do | setting | 72 | if (!setting['name'] and setting['settings']) 73 | body_bg = setting['settings']['background'] || '#ffffff' 74 | body_fg = setting['settings']['foreground'] || '#000000' 75 | selection_bg = setting['settings']['selection'] 76 | body_bg = to_rgba(body_bg) if body_bg =~ /#.{8}/ 77 | body_fg = to_rgba(body_fg) if body_fg =~ /#.{8}/ 78 | # Force the selection background to be rgba. If solid, will generate 79 | # (e.g.) "rgba(63, 63, 63, 0.99)"; specifying the alpha value is 80 | # required because WebKit will apply a default alpha of 0.5 to the 81 | # `::selection` pseudo-element. 82 | # See: http://stackoverflow.com/questions/7224445/css3-selection-behaves-differently-in-ff-chrome 83 | selection_bg = to_rgba(selection_bg) if selection_bg 84 | next 85 | end 86 | next unless setting['name'] and setting['scope'] 87 | theme_styles << "/* " + setting['name'] + " */\n" 88 | scope_name = setting['scope'] 89 | scope_name.gsub!(/(^|[ ])-[^ ]+/, '') # strip negated scopes 90 | scope_name.gsub!(/\./, '_') # change inner '.' to '_' 91 | scope_name.gsub!(/(^|[ ])/, '\1.') 92 | scope_name.gsub!(/(^|,\s+)/m, '\1' + pre_selector + ' ') 93 | theme_styles << "#{scope_name} {\n" 94 | if (color = setting['settings']['foreground']) 95 | color = to_rgba(color) if color =~ /#.{8}/ 96 | theme_styles << "\tcolor: " + color + ";\n" 97 | end 98 | if (style = setting['settings']['fontStyle']) 99 | theme_styles << "\tfont-style: italic;\n" if style =~ /\bitalic\b/i 100 | theme_styles << "\ttext-decoration: underline;\n" if style =~ /\bunderline\b/i 101 | theme_styles << "\tfont-weight: bold;\n" if style =~ /\bbold\b/i 102 | end 103 | if (color = setting['settings']['background']) 104 | color = to_rgba(color) if color =~ /#.{8}/ 105 | theme_styles << "\tbackground-color: " + color + ";\n" 106 | end 107 | theme_styles << "}\n\n" 108 | end 109 | 110 | if (selection_bg) 111 | # currently, -moz-selection doesn't appear to support alpha transparency 112 | # so, i'm not assigning it until it does. 113 | selection_style = "#{pre_selector} ::selection { 114 | background-color: #{selection_bg}; 115 | }" 116 | else 117 | selection_style = "" 118 | end 119 | 120 | return <<-CSS 121 | /* Stylesheet generated from TextMate theme 122 | * 123 | * #{theme_name} 124 | * #{theme_comment} 125 | * 126 | */ 127 | 128 | /* Mostly to improve view within the TextMate HTML viewer */ 129 | body { 130 | margin: 0; 131 | padding: 0; 132 | background-color: #{body_bg}; 133 | } 134 | 135 | pre.textmate-source { 136 | margin: 0; 137 | padding: 1em 0.3em; 138 | font-family: #{font_name}, monospace; 139 | font-size: #{font_size}px; 140 | line-height: 1.3em; 141 | word-wrap: break-word; 142 | white-space: pre; 143 | white-space: pre-wrap; 144 | white-space: -moz-pre-wrap; 145 | white-space: -o-pre-wrap; 146 | } 147 | 148 | pre.textmate-source.#{theme_class} { 149 | color: #{body_fg}; 150 | background-color: #{body_bg}; 151 | } 152 | 153 | pre.textmate-source .linenum { 154 | width: 75px; 155 | padding: 0.1em 1em 0.2em 0; 156 | color: #888; 157 | background-color: #eee; 158 | } 159 | pre.textmate-source.#{theme_class} span { 160 | padding-top: 0.2em; 161 | padding-bottom: 0.1em; 162 | } 163 | #{selection_style} 164 | #{theme_styles} 165 | 166 | CSS 167 | end 168 | 169 | def detab(str, width) 170 | lines = str.split(/\n/) 171 | lines.each do | line | 172 | line_sans_markup = line.gsub(/<[^>]*>/, '').gsub(/&[^;]+;/i, '.') 173 | while (index = line_sans_markup.index("\t")) 174 | tab = line_sans_markup[0..index].jlength - 1 175 | padding = " " * ((tab / width + 1) * width - tab) 176 | line_sans_markup.sub!("\t", padding) 177 | line.sub!("\t", padding) 178 | end 179 | end 180 | return lines.join("\n") 181 | end 182 | 183 | def number(str) 184 | # number each line of input 185 | lines = str.split(/\n/) 186 | n = 0 187 | lines.each do | line | 188 | n += 1 189 | line.gsub!(/^(<\/span>)?/, "\\1#{ sprintf("%5d", n) } ") 190 | end 191 | return lines.join("\n") 192 | end 193 | 194 | def document_to_html(input, opt = {}) 195 | # Read the source document / selection 196 | # Convert tabs to spaces using configured tab width 197 | input = detab(input, (ENV['TM_TAB_SIZE'] || '8').to_i) 198 | 199 | html = '' 200 | 201 | theme_class = '' 202 | if opt[:include_css] 203 | # If you declare a 'http://...' link as a TM_SOURCE_STYLESHEET 204 | # shell variable, that will be used instead of generating a stylesheet 205 | # based on the current theme. 206 | if (ENV['TM_SOURCE_STYLESHEET']) 207 | styles = "\t\n" 208 | else 209 | styles = generate_stylesheet_from_theme(theme_class) 210 | end 211 | 212 | # Head block 213 | html = %{ 214 | 215 | 216 | #{ ENV['TM_FILENAME'] || 'untitled' } 217 | 220 | 221 | 222 | } 223 | end 224 | 225 | # Meat. The poor-man's tokenizer. Fortunately, our input is simple 226 | # and easy to parse. 227 | tokens = input.split(/(<[^>]*>)/) 228 | code_html = '' 229 | tokens.each do |token| 230 | case token 231 | when /^<\// 232 | code_html << "" 233 | when /^<>$/ 234 | # skip empty tags, resulting from name = '' 235 | when /^]+)>$/ 237 | classes = $1.split(/\./) 238 | list = [] 239 | begin 240 | list.push(classes.join('_')) 241 | end while classes.pop 242 | code_html << "" 243 | end 244 | else 245 | code_html << token 246 | end 247 | end 248 | 249 | code_html = number(code_html) if opt[:line_numbers] 250 | 251 | html << "
#{code_html}
" 254 | 255 | if opt[:include_css] 256 | # Closing 257 | html << "\n\n" 258 | end 259 | 260 | return html 261 | end 262 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | contactEmailRot13 6 | ryvn@fpuvgb.zr 7 | contactName 8 | Elia Schito 9 | description 10 | # Avian Missing 11 | 12 | This is a collection of missing features from TextMate2-alpha. 13 | 14 | 15 | ## Copyright 16 | 17 | Copyright © 2012 Elia Schito. See MIT-LICENSE for details. 18 | 19 | name 20 | Avian Missing 21 | uuid 22 | 74BB950F-06E8-4D6E-B061-1C3A0D9114B9 23 | 24 | 25 | --------------------------------------------------------------------------------