├── 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 /^
236 | if token =~ /^<([^>]+)>$/
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