├── .gitignore ├── Commands ├── Add files to the index.tmCommand ├── Amend Last Commit.tmCommand ├── Browse Annotated File (blame).tmCommand ├── Clear Stash.tmCommand ├── Commit.tmCommand ├── Compare Branches.tmCommand ├── Compare Revisions.tmCommand ├── Config.tmCommand ├── Create Branch.tmCommand ├── Create Tag.tmCommand ├── Delete Branch.tmCommand ├── Edit Conflicted File.tmCommand ├── Fetch.tmCommand ├── Fixup!.tmCommand ├── Git Init.tmCommand ├── Git Resolve Conflicts.tmCommand ├── Merge.tmCommand ├── Outgoing.tmCommand ├── Pop Stash.tmCommand ├── Pull.tmCommand ├── Push.tmCommand ├── Revert.tmCommand ├── SVN Dcommit.tmCommand ├── SVN Fetch.tmCommand ├── SVN Rebase.tmCommand ├── Show Log.tmCommand ├── Show Stash.tmCommand ├── Show Uncommitted Changes.tmCommand ├── Start Gitk.tmCommand ├── Stash.tmCommand ├── Status.tmCommand ├── Submodules.tmCommand ├── Switch to Branch.tmCommand ├── Use Git-Gui.tmCommand ├── Use GitX.tmCommand └── Use Gitnub.tmCommand ├── MIT-LICENSE ├── Macros └── Next Rebase Command.tmMacro ├── Preferences ├── Comments: Git Config.tmPreferences ├── Folding - Git Commit Message.tmPreferences ├── Spell Checking: Disable.tmPreferences ├── Style: Diff.tmPreferences ├── Symbol Popup: Git Config Subsection.tmPreferences └── Symbol Popup: Git Config.tmPreferences ├── README.textile ├── Support ├── Gemfile ├── Gemfile.lock ├── app │ ├── controllers │ │ ├── annotate_controller.rb │ │ ├── branch_controller.rb │ │ ├── commit_controller.rb │ │ ├── config_controller.rb │ │ ├── diff_controller.rb │ │ ├── log_controller.rb │ │ ├── misc_controller.rb │ │ ├── remote_controller.rb │ │ ├── stash_controller.rb │ │ ├── status_controller.rb │ │ ├── submodule_controller.rb │ │ ├── svn_controller.rb │ │ └── tag_controller.rb │ ├── helpers │ │ ├── annotate_helper.rb │ │ ├── application_helper.rb │ │ ├── config_helper.rb │ │ ├── diff_helper.rb │ │ └── submodule_helper.rb │ └── views │ │ ├── annotate │ │ ├── _content.html.erb │ │ ├── _navigate_box.html.erb │ │ ├── _select_revision.html.erb │ │ └── index.html.erb │ │ ├── branch │ │ └── merge.html.erb │ │ ├── commit │ │ ├── _commit_result.html.erb │ │ ├── merge_commit.html.erb │ │ └── not_on_a_branch.html.erb │ │ ├── config │ │ └── index.html.erb │ │ ├── diff │ │ ├── _diff_check_result.html.erb │ │ ├── _diff_result.html.erb │ │ ├── _diff_results.html.erb │ │ └── _submodule_diff_result.html.erb │ │ ├── layouts │ │ └── application.html.erb │ │ ├── log │ │ ├── _log_entry.html.erb │ │ └── log_entries.html.erb │ │ ├── status │ │ └── _status.html.erb │ │ └── submodule │ │ ├── index.html.erb │ │ └── list.html.erb ├── dispatch.rb ├── environment.rb ├── gateway │ └── commit_dialog_helper.rb ├── lib │ ├── auto_load.rb │ ├── commands │ │ ├── branch.rb │ │ ├── config.rb │ │ ├── proxy_command_base.rb │ │ ├── remote.rb │ │ ├── stash.rb │ │ ├── submodule.rb │ │ └── svn.rb │ ├── date_helpers.rb │ ├── git.rb │ ├── parsers.rb │ ├── partial_commit_worker.rb │ ├── stream_progress_methods.rb │ └── ui.rb ├── nibs │ ├── CompareBranches.nib │ │ ├── designable.nib │ │ └── keyedobjects.nib │ └── RevisionSelector.nib │ │ ├── designable.nib │ │ └── keyedobjects.nib ├── resource │ ├── git-logo.png │ ├── prototype.js │ ├── rb_gateway.js │ ├── style.css │ └── toggle.js ├── spec │ ├── controllers │ │ ├── annotate_controller_spec.rb │ │ ├── branch_controller_spec.rb │ │ ├── commit_controller_spec.rb │ │ ├── config_controller_spec.rb │ │ ├── diff_controller_spec.rb │ │ ├── log_controller_spec.rb │ │ ├── misc_controller_spec.rb │ │ ├── remote_controller_spec.rb │ │ ├── stash_controller_spec.rb │ │ ├── submodule_controller_spec.rb │ │ └── tag_controller_spec.rb │ ├── fixtures │ │ ├── annotate.txt │ │ ├── annotate_renamed.txt │ │ ├── blame.txt │ │ ├── changed_files.diff │ │ ├── changed_files_with_break.diff │ │ ├── commit_result.txt │ │ ├── config_listing.txt │ │ ├── conflict.txt │ │ ├── fetch_1_5_4_3_output.txt │ │ ├── log.txt │ │ ├── log_with_diffs.txt │ │ ├── new_line_at_end.diff │ │ ├── pull_1_5_4_3_output.txt │ │ ├── push_1_5_4_3_output.txt │ │ ├── small.diff │ │ ├── stash_list_response_many_stashes.txt │ │ ├── status_output.txt │ │ └── submodules.diff │ ├── lib │ │ ├── commands │ │ │ ├── annotate_spec.rb │ │ │ ├── branch_spec.rb │ │ │ ├── commit_spec.rb │ │ │ ├── config_spec.rb │ │ │ ├── diff_spec.rb │ │ │ ├── log_spec.rb │ │ │ ├── merge_spec.rb │ │ │ ├── pull_spec.rb │ │ │ ├── push_spec.rb │ │ │ ├── remote_spec.rb │ │ │ ├── status_spec.rb │ │ │ └── submodule_spec.rb │ │ ├── git_spec.rb │ │ └── partial_commit_worker_spec.rb │ ├── run_all_spec.rb │ ├── spec.opts │ └── spec_helper.rb └── tmvc │ ├── lib │ ├── application_controller.rb │ ├── application_helper.rb │ ├── erb_stdout.rb │ ├── format_helpers │ │ └── tag_helper.rb │ ├── hash.rb │ ├── html_helpers.rb │ ├── ruby_tm_helpers.rb │ └── string.rb │ ├── spec │ ├── hash_spec.rb │ ├── html_helpers_spec.rb │ ├── spec_helper.rb │ ├── spec_helpers.rb │ ├── string_spec.rb │ └── tag_helper_spec.rb │ └── tmvc.rb ├── Syntaxes ├── Git Commit Message.tmLanguage ├── Git Config.tmLanguage └── Git Rebase Message.tmLanguage ├── TODO └── info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | /scratchpad.rb 2 | /Support/DEBUG 3 | /Support/log -------------------------------------------------------------------------------- /Commands/Add files to the index.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "commit", :action => "add" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Add to Index 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.add 43 | uuid 44 | E0901B2E-8953-4A2F-A872-8DBE1A047370 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Amend Last Commit.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch(:controller => "commit", :type => "amend") 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Amend Last Commit… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.amend 43 | uuid 44 | 2F24C9CB-23D0-4FDA-9C8D-210027DCEB27 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Browse Annotated File (blame).tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch(:controller => "annotate") 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Browse Annotated File (Blame) 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.blame 43 | uuid 44 | B3577B4D-A3F1-4CB4-94B0-7A87CA658664 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Clear Stash.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch :controller => "stash", :action => "clear" 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 |  Clear Stash… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other.stash 43 | uuid 44 | 6AA96188-1428-4E09-94D8-755107CFC48E 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Commit.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch(:controller => "commit") 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Commit… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.commit 43 | uuid 44 | 55CCBE51-3C13-46D8-92D9-52EAD7A5D2D6 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Compare Branches.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/osx/plist' 12 | 13 | git = Git.new 14 | 15 | branches = git.branch.list(:all) 16 | parameters = { "branches" => branches.map { |e| { "name" => e[:name] } } } 17 | 18 | token = open('|"$DIALOG" -a CompareBranches', 'r+') { |io| io << parameters.to_plist; io.close_write; io.read.chomp } 19 | res = open('|"$DIALOG" -w' + token) { |io| OSX::PropertyList.load(io) } 20 | open('|"$DIALOG" -x' + token) { |io| } 21 | 22 | if res && res['returnArgument'] 23 | parent = res['returnArgument'].first['name'] 24 | current = res['currentBranch'].first['name'] 25 | dispatch(:controller => "diff", :action => "diff", :branches => [parent, current]) 26 | end 27 | 28 | input 29 | none 30 | inputFormat 31 | text 32 | name 33 | Compare Branches… 34 | outputCaret 35 | afterOutput 36 | outputFormat 37 | html 38 | outputLocation 39 | newWindow 40 | requiredCommands 41 | 42 | 43 | command 44 | git 45 | locations 46 | 47 | /usr/local/git/bin/git 48 | /opt/local/bin/git 49 | /usr/local/bin/git 50 | 51 | variable 52 | TM_GIT 53 | 54 | 55 | scope 56 | attr.scm.git 57 | semanticClass 58 | action.scm.diff 59 | uuid 60 | E56D4990-B615-4788-A46C-5D0CDE750D56 61 | version 62 | 2 63 | 64 | 65 | -------------------------------------------------------------------------------- /Commands/Compare Revisions.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "diff", :action => "compare_revisions" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Compare Revisions… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.diff 43 | uuid 44 | E9180CC9-BA7D-4271-A0A4-0263D8A71F46 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Config.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "config", :action => "index" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Config… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | -attr.scm, attr.scm.git 41 | semanticClass 42 | action.scm.preferences 43 | uuid 44 | 794C7EF9-B0A5-4B27-90BD-000837237B85 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Create Branch.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "branch", :action => "create") 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Create Branch… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.branches 43 | uuid 44 | FF012371-E6C2-4D97-BCD2-9B6237C9BF5B 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Create Tag.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "tag", :action => "create" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Create Tag… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.tag 43 | uuid 44 | C6CD5A2A-E1DA-4D94-B561-331A2366AAC8 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Delete Branch.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch(:controller => "branch", :action => "delete") 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Delete Branch... 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.branches 43 | uuid 44 | 508C7FCD-E5DD-4E60-88C3-A668C48273B7 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Edit Conflicted File.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "status", :action => "edit_conflicted_file" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Edit Conflicted File… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.conflicts 43 | uuid 44 | 0DBC221A-B726-4367-A5E1-04AB999F8CC2 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Fetch.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "remote", :action => "fetch" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Fetch 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.fetch 43 | uuid 44 | 491D8DB3-8CB2-4888-ACD8-C94FAB125B38 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Fixup!.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | def escape(choice) 11 | choice.gsub(/[,|\\$]/, '\\\\\0') 12 | end 13 | 14 | choices = %x{ cd "$TM_PROJECT_DIRECTORY" && "${TM_GIT:-git}" log --pretty=tformat:'%s' -n15 }.split(/\n/) 15 | choices.reject! { |choice| choice =~ /^(fixup|squash)\b/ } 16 | choices.map! { |choice| escape choice } 17 | 18 | STDOUT << "fixup! ${1|#{choices.join ','}|}" 19 | 20 | input 21 | none 22 | inputFormat 23 | text 24 | name 25 | Fixup! 26 | outputCaret 27 | afterOutput 28 | outputFormat 29 | snippet 30 | outputLocation 31 | atCaret 32 | requiredCommands 33 | 34 | 35 | command 36 | git 37 | locations 38 | 39 | /usr/local/git/bin/git 40 | /opt/local/bin/git 41 | /usr/local/bin/git 42 | 43 | variable 44 | TM_GIT 45 | 46 | 47 | scope 48 | text.git-commit 49 | tabTrigger 50 | fix 51 | uuid 52 | 11CB0218-E38D-4ACE-9504-77BB3A224C15 53 | version 54 | 2 55 | 56 | 57 | -------------------------------------------------------------------------------- /Commands/Git Init.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "misc", :action => "init" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Initialize Repository 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | -attr.scm 41 | semanticClass 42 | action.scm.new 43 | uuid 44 | 556EF65D-C59B-4A15-BA4A-D5D87C2695A0 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Git Resolve Conflicts.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | # Resolve conflicts command for git/FileMerge 11 | # By Tim Harper 12 | # http://code.leadmediapartners.com/ 13 | 14 | require "fileutils" 15 | FM="#{`"$TM_SUPPORT_PATH/bin/find_app" FileMerge.app`}/Contents/MacOS/FileMerge" 16 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 17 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape.rb' 18 | 19 | state = :both 20 | 21 | input_file_path = ENV['TM_FILEPATH'] 22 | input_filename = File.basename(input_file_path) 23 | 24 | input = $<.read 25 | 26 | left = "" 27 | right = "" 28 | 29 | 30 | input.each { |line| 31 | if /^(<{7}|={7}|>{7})($| )/.match(line) 32 | state = 33 | case $1 34 | when "<<<<<<<" then :left 35 | when "=======" then :right 36 | when ">>>>>>>" then :both 37 | end 38 | next 39 | end 40 | left << line if state == :left || state == :both 41 | right << line if state == :right || state == :both 42 | } 43 | 44 | if left==right 45 | puts "No conflicts to resolve in #{input_file_path}." 46 | exit 47 | end 48 | 49 | filename = "git-conflict-resolve" 50 | tmp_path = "#{ENV['TMPDIR']}/git-conflict-resolve/" 51 | 52 | FileUtils.rm_rf(tmp_path) 53 | FileUtils.mkdir_p(tmp_path) 54 | 55 | left_file = "#{tmp_path}left-#{input_filename}.rb" 56 | right_file = "#{tmp_path}right-#{input_filename}.rb" 57 | File.open(left_file, "w") { |f| f.puts left } 58 | File.open(right_file, "w") { |f| f.puts right } 59 | 60 | %x{#{FM} -left #{e_sh left_file} -right #{e_sh right_file} -merge #{e_sh input_file_path} &>/dev/null & } 61 | 62 | input 63 | document 64 | inputFormat 65 | text 66 | name 67 | Edit Conflicts With FileMerge… 68 | outputCaret 69 | afterOutput 70 | outputFormat 71 | text 72 | outputLocation 73 | toolTip 74 | requiredCommands 75 | 76 | 77 | command 78 | git 79 | locations 80 | 81 | /usr/local/git/bin/git 82 | /opt/local/bin/git 83 | /usr/local/bin/git 84 | 85 | variable 86 | TM_GIT 87 | 88 | 89 | scope 90 | attr.scm.git 91 | semanticClass 92 | action.scm.conflicts 93 | uuid 94 | 7CE2C842-EBC4-443C-8DDB-3B16AC593D9A 95 | version 96 | 2 97 | 98 | 99 | -------------------------------------------------------------------------------- /Commands/Merge.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => 'branch', :action => 'merge' 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Merge… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.branches 43 | uuid 44 | 246BC5D6-F4DC-458B-8966-C601B65AA1E9 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Outgoing.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "log", :action => "outgoing" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Outgoing 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other 43 | uuid 44 | 1D25F132-718E-4B97-95CC-724AAC35E46C 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Pop Stash.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "stash", :action => "pop" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Pop Stash (Apply then drop) 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other.stash 43 | uuid 44 | 47EB2C81-B093-4627-9DE7-454A60C3A98C 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Pull.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "remote", :action => "pull" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Pull 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.pull 43 | uuid 44 | 6494E41A-04CE-4D30-BD9A-B50056A7C13F 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Push.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "remote", :action => "push" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Push Current Branch 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.push 43 | uuid 44 | 3F84F9EB-027A-4200-B29B-C99EFA09F453 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Revert.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | # encoding: utf-8 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' 12 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape.rb' 13 | 14 | git = SCM::Git.new 15 | paths = git.paths(:unique => true, :fallback => :current_file) 16 | 17 | display = paths.map { |e| File.basename(e) }.join("”, “") 18 | plural = (paths.size == 1) ? '' : 's' 19 | files = (paths.size == 1) ? "“#{display}”" : 'files' 20 | 21 | if 'Revert' == TextMate::UI.alert(:warning, "Revert #{files}?", "Do you really want to revert the file#{plural} “#{display}” and lose all local changes?", 'Revert', 'Cancel') 22 | 23 | puts git.revert(paths) 24 | 25 | end 26 | 27 | input 28 | none 29 | inputFormat 30 | text 31 | name 32 | Revert… 33 | outputCaret 34 | afterOutput 35 | outputFormat 36 | text 37 | outputLocation 38 | toolTip 39 | requiredCommands 40 | 41 | 42 | command 43 | git 44 | locations 45 | 46 | /usr/local/git/bin/git 47 | /opt/local/bin/git 48 | /usr/local/bin/git 49 | 50 | variable 51 | TM_GIT 52 | 53 | 54 | scope 55 | attr.scm.git 56 | semanticClass 57 | action.scm.revert 58 | uuid 59 | CDEA521C-8963-414F-8F8E-F9B81EF79ADA 60 | version 61 | 2 62 | 63 | 64 | -------------------------------------------------------------------------------- /Commands/SVN Dcommit.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "svn", :action => "dcommit" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | SVN Dcommit 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | uuid 40 | 8FD8CC00-0A38-4472-9C3A-F22AE289B3A9 41 | version 42 | 2 43 | 44 | 45 | -------------------------------------------------------------------------------- /Commands/SVN Fetch.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "svn", :action => "fetch" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | SVN Fetch 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | uuid 40 | 1CCC4394-A243-4E78-A720-B2DA1BC37DC0 41 | version 42 | 2 43 | 44 | 45 | -------------------------------------------------------------------------------- /Commands/SVN Rebase.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "svn", :action => "rebase" 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | SVN Rebase 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | uuid 40 | CFB9BB9D-4F47-47DA-819B-58F0B29FA560 41 | version 42 | 2 43 | 44 | 45 | -------------------------------------------------------------------------------- /Commands/Show Log.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "log", :action => "index" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Log 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.log 43 | uuid 44 | 46662F92-7739-42A7-B7CD-0527A0474BDC 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Show Stash.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch :controller => "stash", :action => "show" 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Show Stash 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other.stash 43 | uuid 44 | 5E37F050-85A0-4CAE-91D1-DC50E2F65024 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Show Uncommitted Changes.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "diff", :action => "uncommitted_changes" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Show Uncommitted Changes 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.status 43 | uuid 44 | 37CC38F5-AF4C-4915-B925-1DC810C25C8A 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Start Gitk.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "misc", :action => "gitk") 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Visualize Branch History With GitK 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | discard 24 | scope 25 | attr.scm.git 26 | semanticClass 27 | action.scm.other 28 | uuid 29 | 20F5C491-F71C-4963-9C61-DF7294976550 30 | version 31 | 2 32 | 33 | 34 | -------------------------------------------------------------------------------- /Commands/Stash.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch :controller => "stash", :action => "save" 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Stash 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other.stash 43 | uuid 44 | 917D405B-0488-4FDE-966A-54E1F922FCBD 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Status.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "status") 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Status 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.status 43 | uuid 44 | 41F8764A-63DE-4965-9192-918E49E15907 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Submodules.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | 10 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 11 | dispatch :controller => "submodule", :action => "index" 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Submodules… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | html 22 | outputLocation 23 | newWindow 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.other 43 | uuid 44 | 3F77F0FC-F476-4B83-92D1-77D854A9D64D 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Switch to Branch.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "branch", :action => "switch") 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Branches (Show/Switch)… 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | toolTip 24 | requiredCommands 25 | 26 | 27 | command 28 | git 29 | locations 30 | 31 | /usr/local/git/bin/git 32 | /opt/local/bin/git 33 | /usr/local/bin/git 34 | 35 | variable 36 | TM_GIT 37 | 38 | 39 | scope 40 | attr.scm.git 41 | semanticClass 42 | action.scm.branches 43 | uuid 44 | 7F8D2058-E106-40DC-9FBE-F32A1202D158 45 | version 46 | 2 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Use Git-Gui.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "misc", :action => "gitgui") 11 | input 12 | selection 13 | inputFormat 14 | text 15 | name 16 | Open Git-Gui 17 | outputCaret 18 | afterOutput 19 | outputFormat 20 | text 21 | outputLocation 22 | discard 23 | scope 24 | attr.scm.git 25 | uuid 26 | D0DF4B19-F311-48CC-BF68-F8B33CD051D3 27 | version 28 | 2 29 | 30 | 31 | -------------------------------------------------------------------------------- /Commands/Use GitX.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "misc", :action => "gitx") 11 | 12 | input 13 | none 14 | inputFormat 15 | text 16 | name 17 | Visualize History with GitX 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | discard 24 | scope 25 | attr.scm.git 26 | semanticClass 27 | action.scm.other 28 | uuid 29 | 1C12DE42-78A9-4DCA-BB55-2B8E6328C72D 30 | version 31 | 2 32 | 33 | 34 | -------------------------------------------------------------------------------- /Commands/Use Gitnub.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 9 | require ENV['TM_BUNDLE_SUPPORT'] + '/environment.rb' 10 | dispatch(:controller => "misc", :action => "gitnub") 11 | 12 | input 13 | selection 14 | inputFormat 15 | text 16 | name 17 | Visualize History with Gitnub 18 | outputCaret 19 | afterOutput 20 | outputFormat 21 | text 22 | outputLocation 23 | discard 24 | scope 25 | attr.scm.git 26 | semanticClass 27 | action.scm.other 28 | uuid 29 | 1FF5FF82-13A0-4C83-BAD6-D67AE8180FA9 30 | version 31 | 2 32 | 33 | 34 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 Tim Harper 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Macros/Next Rebase Command.tmMacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | commands 6 | 7 | 8 | argument 9 | 10 | action 11 | findNext 12 | findInProjectIgnoreCase 13 | 14 | findString 15 | ^\s*(pick|p|reword|r|edit|e|squash|s|fixup|f) 16 | ignoreCase 17 | 18 | regularExpression 19 | 20 | replaceAllScope 21 | document 22 | wrapAround 23 | 24 | 25 | command 26 | findWithOptions: 27 | 28 | 29 | keyEquivalent 30 | ^n 31 | name 32 | Next Rebase Command 33 | scope 34 | text.git-rebase 35 | uuid 36 | 683BF855-9BC9-47A6-89DD-7C2192E62FD7 37 | 38 | 39 | -------------------------------------------------------------------------------- /Preferences/Comments: Git Config.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Comments: Git Config 7 | scope 8 | source.git-config 9 | settings 10 | 11 | shellVariables 12 | 13 | 14 | name 15 | TM_COMMENT_START 16 | value 17 | # 18 | 19 | 20 | name 21 | TM_COMMENT_START_2 22 | value 23 | ; 24 | 25 | 26 | 27 | uuid 28 | 1E1882B3-9578-427F-9EF8-3C56EF407F13 29 | 30 | 31 | -------------------------------------------------------------------------------- /Preferences/Folding - Git Commit Message.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Folding (Git Commit Message) 7 | scope 8 | text.git-commit 9 | settings 10 | 11 | foldingStartMarker 12 | ^\+\+\+ 13 | foldingStopMarker 14 | ^--- 15 | 16 | uuid 17 | 1A0DB209-7219-4BA5-BB32-3A282919890B 18 | 19 | 20 | -------------------------------------------------------------------------------- /Preferences/Spell Checking: Disable.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Spell Checking: Disable 7 | scope 8 | meta.scope.metadata.git-commit 9 | settings 10 | 11 | spellChecking 12 | 0 13 | 14 | uuid 15 | 5CF68FFF-6562-4A58-8056-6034EF93E88A 16 | 17 | 18 | -------------------------------------------------------------------------------- /Preferences/Style: Diff.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Style: Diff 7 | scope 8 | text.git-commit source.diff 9 | settings 10 | 11 | softWrap 12 | 13 | 14 | uuid 15 | EFA849A8-00DF-4D9A-BA37-504323969746 16 | 17 | 18 | -------------------------------------------------------------------------------- /Preferences/Symbol Popup: Git Config Subsection.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol Popup: Git Config Subsection 7 | scope 8 | entity.name.section.subsection.git-config - punctuation.definition.section.subsection 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 15 | s/^/ /; # indent subsections 16 | 17 | 18 | uuid 19 | E6D2DCFE-A40D-4BF1-9B43-7E3199CF00B4 20 | 21 | 22 | -------------------------------------------------------------------------------- /Preferences/Symbol Popup: Git Config.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol Popup: Git Config Section 7 | scope 8 | entity.name.section.git-config 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | 14 | uuid 15 | 3E646038-6F79-46BE-96A3-9802E7011162 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. The Git Textmate Bundle 2 | 3 | h2. Installation 4 | 5 | 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. 6 | 7 | * Many shortcuts are available from the SCM shortcut ⌘Y Subversion commands are ⌘⌥G. Less frequent commands are accessed via the menu. 8 | 9 | h2. Support 10 | 11 | * "Issue tracker":https://github.com/textmate/git.tmbundle/issues 12 | * "Repository":https://github.com/textmate/git.tmbundle 13 | 14 | The "Mailing list":http://groups.google.com/group/git-tmbundle has now been closed. Please feel free to report issues using the "Issue tracker":https://github.com/textmate/git.tmbundle/issues. 15 | 16 | h2. Theme notes: 17 | 18 | The "Git Commit Message" Language defines two scopes that can be used by a theme to generate "line too long" warnings for the first line of the commit: 19 | 20 | * invalid.deprecated.line-too-long.git-commit 21 | * invalid.illegal.line-too-long.git-commit 22 | 23 | The warning scope triggers when the first line exceeds 50 characters; the error scope over 65 characters. These aren't generally-used TextMate scopes, so you can add new rules to your preferred themes, such as orange background/red background. You can also edit the regex to change the preferred character counts. 24 | 25 | h2. Development 26 | 27 | h3. Running Specs 28 | 29 | The specs must be run with Ruby 1.8.7 (p358). Use your Ruby version manager of choice to install this version. Then, with this version activated (and @Support/@ as current directory), run @gem install --file Gemfile@ to install the appropriate versions of RSpec and hpricot. 30 | 31 | When running the specs from the command line you need to set @TM_SUPPORT_PATH@ explicitly. The following should work: 32 | 33 | 34 | export TM_SUPPORT_PATH=~/Library/Application\ Support/TextMate/Managed/Bundles/Bundle\ Support.tmbundle/Support/shared 35 | 36 | 37 | To run the specs then use: 38 | 39 | 40 | spec spec/ 41 | 42 | 43 | h2. Who: 44 | 45 | h3. Previous Maintainers 46 | 47 | * January 2010 - 2012: "James Conroy-Finn":http://jamesconroyfinn.com/ 48 | * January 2008 - December 2009: "Tim Harper":http://tim.theenchanter.com/ (with "Lead Media Partners":http://leadmediapartners.com). 49 | 50 | h2. Git-tmbundle superstars 51 | 52 | The Git TextMate Bundle wouldn't be possible without the contributions of the following fine gentlemen: 53 | 54 | h3. Major Contributions 55 | 56 | * Allan Odgaard - Started the bundle, got it rolling. Many patches. Oh, and TextMate :-). 57 | * Sam Granieri - GitK, Many of the git-svn commands, Git initialize repository command, menu layouting, create-tag. 58 | * Johan Sørensen - Contributing the CSS styling. 59 | 60 | Please feel free to send a pull request if you've added any functionality to this bundle that you think the rest of the git-loving, TextMate-using world would appreciate! 61 | -------------------------------------------------------------------------------- /Support/Gemfile: -------------------------------------------------------------------------------- 1 | # This Gemfile is needed only for running the specs 2 | source "https://rubygems.org" 3 | 4 | gem "rspec", "~> 1.3" 5 | gem "hpricot" 6 | -------------------------------------------------------------------------------- /Support/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | hpricot (0.8.6) 5 | rspec (1.3.2) 6 | 7 | PLATFORMS 8 | ruby 9 | 10 | DEPENDENCIES 11 | hpricot 12 | rspec (~> 1.3) 13 | -------------------------------------------------------------------------------- /Support/app/controllers/annotate_controller.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class AnnotateController < ApplicationController 4 | include DateHelpers 5 | include AnnotateHelper 6 | layout "application", :except => "update" 7 | def index 8 | @file_path = params[:file_path] || ENV['TM_FILEPATH'] 9 | @annotations = git.annotate(@file_path) 10 | 11 | if @annotations.nil? 12 | puts "Error. Aborting" 13 | abort 14 | end 15 | 16 | @log_entries = git.log(:path => @file_path, :follow => true, :name => true) 17 | render "index" 18 | end 19 | 20 | def update 21 | file_path = params[:filepath] || ENV['TM_FILEPATH'] 22 | revision = params[:revision] 23 | 24 | @annotations = git.annotate(file_path, revision) 25 | 26 | if @annotations.nil? 27 | puts "Error. Aborting" 28 | abort 29 | end 30 | 31 | # f = Formatters::Annotate.new(:selected_revision => revision, :as_partial => true) 32 | # f.header "Annotations for ‘#{htmlize(shorten(file_path))}’" 33 | # f.content annotations 34 | render "_content", :locals => { :annotations => @annotations, :revision => revision } 35 | render "_select_revision", :locals => { :revision => revision} 36 | end 37 | end -------------------------------------------------------------------------------- /Support/app/controllers/commit_controller.rb: -------------------------------------------------------------------------------- 1 | require LIB_ROOT + '/partial_commit_worker.rb' 2 | class CommitController < ApplicationController 3 | layout "application", :except => [:add] 4 | 5 | def index 6 | if git.merge_message 7 | @status = git.status 8 | @message = git.merge_message 9 | render "merge_commit" 10 | else 11 | run_partial_commit 12 | end 13 | end 14 | 15 | def merge_commit 16 | message = params[:message] 17 | statuses = git.status(git.path) 18 | files = statuses.map { |status_options| (status_options[:status][:short] == "G") ? git.make_local_path(status_options[:path]) : nil }.compact 19 | 20 | git.auto_add_rm(files) 21 | res = git.commit(message, []) 22 | 23 | render "_commit_result", :locals => { :result => res, :files => files, :message => message } 24 | end 25 | 26 | def add 27 | paths = git.paths(:unique => true, :fallback => :current_file) 28 | git.add(paths) 29 | paths.each { |file| puts "Added '#{git.relative_path_for(file)}' to the index" } 30 | exit_show_tool_tip 31 | end 32 | 33 | protected 34 | def run_partial_commit 35 | puts "

#{commit_worker.title}…

" 36 | result = commit_worker.run 37 | render "_commit_result", :locals => result if result 38 | rescue PartialCommitWorker::NotOnBranchException 39 | render "not_on_a_branch" 40 | false 41 | rescue PartialCommitWorker::NothingToCommitException 42 | puts(git.clean_directory? ? "Working directory is clean (nothing to commit)" : "No changes to commit within the current scope. (Try selecting the root folder in the project drawer?)") 43 | rescue PartialCommitWorker::NothingToAmendException 44 | puts "Nothing to amend." 45 | rescue PartialCommitWorker::CommitCanceledException 46 | suppress_output 47 | end 48 | 49 | def commit_worker 50 | @commit_worker ||= PartialCommitWorker.factory(params[:type], git) 51 | end 52 | end -------------------------------------------------------------------------------- /Support/app/controllers/config_controller.rb: -------------------------------------------------------------------------------- 1 | class ConfigController < ApplicationController 2 | include ConfigHelper 3 | def index 4 | render "index" 5 | end 6 | 7 | def set 8 | value = params[:value] 9 | git.config[(params[:scope] || "local"), params[:key]] = params[:value] 10 | end 11 | end -------------------------------------------------------------------------------- /Support/app/controllers/diff_controller.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class DiffController < ApplicationController 4 | include SubmoduleHelper 5 | include DiffHelper 6 | def diff 7 | show_diff_title unless params[:layout].to_s=="false" 8 | @rev = params[:rev] 9 | @title = params[:title] || "Diff result" 10 | params[:context_lines] = git.config.context_lines if git.config.context_lines 11 | 12 | render("_diff_results", :locals => { 13 | :diff_check_results => git.config.show_diff_check? ? git.with_path(params[:git_path]).diff_check(params.filter(:path, :revision, :context_lines, :revisions, :branches, :tags, :since)) : [], 14 | :diff_results => git.with_path(params[:git_path]).diff(params.filter(:path, :revision, :context_lines, :revisions, :branches, :tags, :since)), 15 | :git => git.with_path(params[:git_path]) 16 | }) 17 | end 18 | 19 | def uncommitted_changes 20 | paths = case 21 | when params[:path] 22 | [params[:path]] 23 | else 24 | git.paths 25 | end 26 | base = git.path 27 | open_in_tm_link 28 | puts "

Uncommitted Changes for ‘#{htmlize(paths.map{|path| shorten(path, base)} * ', ')}’ on branch ‘#{git.branch.current_name}’

" 29 | 30 | paths.each do |path| 31 | render("_diff_results", :locals => { 32 | :diff_check_results => git.config.show_diff_check? ? git.diff_check(:path => path, :since => "HEAD") : [], 33 | :diff_results => git.diff(:path => path, :since => "HEAD") 34 | }) 35 | 36 | git.submodule.all(:path => path).each do |submodule| 37 | next if (diff_results = submodule.git.diff(:since => "HEAD")).blank? 38 | render_submodule_header(submodule) 39 | render("_diff_results", :locals => {:git => submodule.git, :diff_results => diff_results, :diff_check_results => git.config.show_diff_check? ? git.diff_check(:path => path, :since => "HEAD") : []}) 40 | end 41 | end 42 | end 43 | 44 | def compare_revisions 45 | file_paths = git.paths 46 | if file_paths.length > 1 47 | base = git.nca(file_paths) 48 | else 49 | base = file_paths.first 50 | end 51 | 52 | log = LogController.new 53 | revisions = log.choose_revision(base, "Choose revisions for #{file_paths.map{|f| git.make_local_path(f)}.join(',')}", :multiple, :sort => true) 54 | 55 | if revisions.nil? 56 | puts "Canceled" 57 | return 58 | end 59 | 60 | render_component(:controller => "diff", :action => "diff", :revisions => revisions, :path => base) 61 | end 62 | 63 | protected 64 | def open_in_tm_link 65 | tmp_file = "#{ENV['TMPDIR']}/output.diff" 66 | File.unlink(tmp_file) if File.exist? tmp_file 67 | puts <<-EOF 68 | Open diff in TextMate 69 | EOF 70 | end 71 | 72 | def show_diff_title 73 | puts "

" 74 | case 75 | when params[:branches] 76 | branches = params[:branches] 77 | branches = branches.split("..") if params[:branches].is_a?(String) 78 | puts "Comparing branches #{branches.first}..#{branches.last}" 79 | when params[:revisions] 80 | revisions = params[:revisions] 81 | revisions = revisions.split("..") if params[:revisions].is_a?(String) 82 | puts "Comparing branches #{revisions.first}..#{revisions.last}" 83 | end 84 | puts "

" 85 | end 86 | 87 | def extract_diff_params(params) 88 | diff_params = params.dup.delete_if do |key, value| 89 | ! [:revisions, :revision, :branches, :tags, :path].include?(key) 90 | end 91 | diff_params[:context_lines] = git.config["git-tmbundle.log.context-lines"] if git.config["git-tmbundle.log.context-lines"] 92 | diff_params 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /Support/app/controllers/misc_controller.rb: -------------------------------------------------------------------------------- 1 | class MiscController < ApplicationController 2 | layout "application", :only => [:init] 3 | def init 4 | puts "

Initializing Git Repository in #{ENV['TM_PROJECT_DIRECTORY']}

" 5 | puts htmlize(git.init(ENV["TM_PROJECT_DIRECTORY"])) 6 | end 7 | 8 | def gitk 9 | run_detached("PATH=#{File.dirname(git.git)}:$PATH && gitk --all", "Wish Shell") 10 | end 11 | 12 | def gitgui 13 | run_detached("PATH=#{File.dirname(git.git)}:$PATH && git gui", "Git Gui") 14 | end 15 | 16 | def gitnub 17 | cmd = first_which(git.config["git-tmbundle.gitnub-path"], "nub", "/Applications/GitNub.app/Contents/MacOS/GitNub") 18 | if cmd 19 | run_detached(cmd + " #{ENV['TM_PROJECT_DIRECTORY']}", "Gitnub") 20 | else 21 | puts "Unable to find Gitnub. Use the config dialog to set the Gitnub path to where you've installed it." 22 | output_show_tool_tip 23 | end 24 | end 25 | 26 | def gitx 27 | cmd = first_which(git.config["git-tmbundle.gitx-path"], "gitx", "/Applications/GitX.app/Contents/Resources/gitx") 28 | if cmd 29 | run_detached("cd '#{ENV['TM_DIRECTORY']}';" + cmd, "GitX") 30 | else 31 | puts "Unable to find GitX. Use the config dialog to set the GitX path to where you've installed it." 32 | output_show_tool_tip 33 | end 34 | end 35 | 36 | protected 37 | def first_which(*args) 38 | args.map do |arg| 39 | next if arg.blank? 40 | result = `which '#{arg}'`.strip 41 | return result unless result.empty? 42 | end 43 | nil 44 | end 45 | 46 | def run_detached(cmd, app_name) 47 | exit if fork # Parent exits, child continues. 48 | Process.setsid # Become session leader. 49 | exit if fork # Zap session leader. 50 | 51 | # After this point you are in a daemon process 52 | pid = fork do 53 | STDOUT.reopen(open('/dev/null')) 54 | STDERR.reopen(open('/dev/null')) 55 | Thread.new do 56 | sleep 1.5 57 | %x{osascript -e 'tell app "#{app_name}" to activate'} 58 | exit 59 | end 60 | system(cmd) 61 | end 62 | 63 | Process.detach(pid) 64 | #inspired by http://andrejserafim.wordpress.com/2007/12/16/multiple-threads-and-processes-in-ruby/ 65 | end 66 | 67 | end -------------------------------------------------------------------------------- /Support/app/controllers/stash_controller.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' 3 | 4 | class StashController < ApplicationController 5 | include DiffHelper 6 | 7 | layout "application", :except => ["clear"] 8 | def show 9 | if git.stash.list.empty? 10 | puts "Stash list is empty" 11 | end 12 | 13 | stash_item = select_stash 14 | 15 | if stash_item.nil? 16 | puts "Aborted" 17 | return 18 | end 19 | 20 | puts "

Diff for stash ‘#{stash_item[:description]}’

" 21 | render("diff/_diff_results", :locals => {:diff_results => (git.stash.diff(stash_item[:name]))}) 22 | end 23 | 24 | def pop 25 | stash_item = select_stash(:prompt => "Select a stash to pop") 26 | if stash_item.nil? 27 | puts "Cancelled" 28 | return 29 | end 30 | puts "

Popping stash '#{stash_item[:description]}'

" 31 | flush 32 | 33 | stash_diff = git.stash.diff(stash_item[:name]) 34 | 35 | stash_it = lambda { 36 | git.stash.pop(stash_item[:name]) 37 | } 38 | 39 | result = stash_it.call 40 | 41 | if result.match(/Cannot restore on top of a dirty state/) 42 | response = TextMate::UI.alert(:warning, "You're not on a clean working copy", "You may want to commit your outstanding changes before stashing.\nWould you like to apply your stash anyways? (could cause conflicts)", "No", "Yes") 43 | if response == "Yes" 44 | git.command("add", ".") 45 | result = stash_it.call 46 | git.command("reset") 47 | else 48 | return 49 | end 50 | end 51 | 52 | status_data = git.parse_status(result) 53 | if status_data.empty? 54 | puts "I didn't understand git's response. Perhaps you can?" 55 | puts "
#{result}
" 56 | return 57 | end 58 | 59 | puts "

Successfully applied

" 60 | puts "

Project Status:

" 61 | render "status/_status", :locals => {:status_data => status_data} 62 | 63 | puts "

Diff of stash applied:

" 64 | render("/diff/_diff_results", :locals => {:diff_results => stash_diff}) 65 | end 66 | 67 | def save 68 | untracked_files = git.list_files(git.path, :type => "o") 69 | if untracked_files.length >= 1 70 | response = TextMate::UI.alert(:warning, "Untracked files in working copy", "Would you like to include the following untracked files in your stash?:\n#{untracked_files * "\n"}\n", "Add them", "Leave them out", "Cancel") 71 | case response 72 | when "Add them" 73 | git.command("add", ".") 74 | when "Cancel", nil 75 | return exit_discard 76 | end 77 | end 78 | 79 | stash_description = TextMate::UI.request_string(:title => "Stash", :prompt => "Describe stash:", :default => "WIP: ") 80 | if stash_description.nil? 81 | return exit_discard 82 | end 83 | stash_description = "WIP" if stash_description.empty? 84 | 85 | result = git.stash.save(stash_description) 86 | if result.match(/Saved working directory and index state/) 87 | 88 | end 89 | puts result 90 | end 91 | 92 | def clear 93 | if git.stash.list.empty? 94 | puts "No stashes for current branch (#{git.branch.current_name})" 95 | return 96 | end 97 | 98 | stash_text_list = git.stash.list.map{|s| "#{s[:id]} - #{s[:description]}"} * "\n" 99 | response = TextMate::UI.alert(:warning, "Clear all stashes?", "Do you really want to clear the following stashes? \n#{stash_text_list}", 'Yes', 'Cancel') 100 | if response == 'Yes' 101 | git.stash.clear 102 | puts "Stash cleared" 103 | else 104 | puts "Cancelled" 105 | end 106 | end 107 | 108 | protected 109 | def select_stash(options={}) 110 | options = {:title => "Select stash", :prompt => "Select a stash", :items => git.stash.list.map{|s| "#{s[:id]} - #{s[:description]}"}}.merge(options) 111 | TextMate::UI.request_item(options) do |stash_id| 112 | selected_stash_entry = git.stash.list.find { |s| s[:id].to_i == stash_id.to_i } 113 | return selected_stash_entry 114 | end 115 | nil 116 | end 117 | end -------------------------------------------------------------------------------- /Support/app/controllers/status_controller.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require LIB_ROOT + '/ui.rb' 3 | 4 | class StatusController < ApplicationController 5 | layout "application", :except => [:edit_conflicted_file] 6 | 7 | include SubmoduleHelper 8 | def index 9 | file_or_path = *(params[:path] || git.paths.first) 10 | puts '

Status for ' + file_or_path.map { |e| "‘#{htmlize(shorten(e))}’" }.join(', ') + " on branch ‘#{git.branch.current_name}’

" 11 | status_data = git.status(file_or_path) 12 | render "_status", :locals => {:status_data => status_data} 13 | 14 | git.submodule.all(:path => file_or_path).each do |submodule| 15 | next if (status_data = submodule.git.status).blank? 16 | render_submodule_header(submodule) 17 | render "_status", :locals => {:status_data => status_data, :git => submodule.git} 18 | end 19 | end 20 | 21 | def edit_conflicted_file 22 | file_or_path = git.path 23 | conflicts = git.status(file_or_path).select { |file_status| file_status[:status][:short] == "C" } 24 | if conflicts.empty? 25 | puts "No conflicted files" 26 | exit_show_tool_tip 27 | end 28 | index = TextMate::UI.menu(conflicts.map { |conflict| conflict[:display] }) 29 | tm_open(conflicts[index][:path]) if index 30 | exit_discard 31 | end 32 | end -------------------------------------------------------------------------------- /Support/app/controllers/submodule_controller.rb: -------------------------------------------------------------------------------- 1 | require LIB_ROOT + '/ui.rb' 2 | 3 | class SubmoduleController < ApplicationController 4 | def index 5 | render "index" 6 | end 7 | 8 | def list 9 | @submodules = git.submodule.all 10 | render "list" 11 | end 12 | 13 | def add 14 | (repository_path = prompt_repository_path) && 15 | (parent_folder = prompt_parent_folder) && 16 | (module_name = prompt_module_name(repository_path)) || 17 | (cancel and return) 18 | 19 | # This is messy, but I'm not entirely sure what is going to happen with this yet (there may be some parsing going on that will require interaction between the view and the controller) 20 | puts "
"
21 |       stream = git.submodule.add(repository_path, File.join(parent_folder, module_name))
22 |       stream.pipe_to(STDOUT)
23 |     puts "
" 24 | 25 | puts htmlize(git.submodule.init_and_update) 26 | 27 | puts <<-EOF 28 |

Done.

29 | EOF 30 | end 31 | 32 | def update 33 | puts "
"
34 |     puts git.submodule.init_and_update
35 |     puts "
" 36 | end 37 | 38 | # 39 | ## 40 | ### 41 | protected 42 | def prompt_repository_path 43 | TextMate::UI.request_string(:title => "Add submodule", :prompt => "Enter the submodule clone URL") 44 | end 45 | 46 | def prompt_parent_folder 47 | TextMate::UI.request_directory("Select the parent folder for the submodule:", :initial_directory => git.path) 48 | end 49 | 50 | def prompt_module_name(repository_path = "") 51 | /([^\/]+?)(.git){0,1}$/.match(repository_path) 52 | module_name = TextMate::UI.request_string(:title => "What do you want to call the module (will be the folder name)?", :default => $1 ) 53 | end 54 | 55 | def cancel 56 | puts "Canceled" 57 | true 58 | end 59 | end -------------------------------------------------------------------------------- /Support/app/controllers/svn_controller.rb: -------------------------------------------------------------------------------- 1 | class SvnController < ApplicationController 2 | def dcommit 3 | puts "

Committing to Subversion Repository

" 4 | puts htmlize(git.svn.dcommit) 5 | end 6 | 7 | def rebase 8 | puts "

Rebasing Subversion Repository

" 9 | puts htmlize(git.svn.rebase) 10 | end 11 | 12 | def fetch 13 | puts "

Fetching Subversion Repository

" 14 | puts htmlize(git.svn.fetch) 15 | end 16 | 17 | end -------------------------------------------------------------------------------- /Support/app/controllers/tag_controller.rb: -------------------------------------------------------------------------------- 1 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' 2 | 3 | class TagController < ApplicationController 4 | def create 5 | if ! (name = prompt_tag_name) 6 | puts "Aborted" 7 | return 8 | end 9 | 10 | if git.create_tag(name) == true 11 | puts "Tag #{name} created" 12 | flush 13 | render_component(:controller => "remote", :action => "push_tag", :tag => name) if prompt_want_to_push_remote 14 | end 15 | end 16 | 17 | def prompt_tag_name 18 | TextMate::UI.request_string(:title => "Create Tag", :prompt => "Enter the name of the new tag:") 19 | end 20 | 21 | def prompt_want_to_push_remote 22 | TextMate::UI.alert(:warning, "Push tag to remote servers", "Would you like to push this tag to your remote repository(s)", 'Yes', 'No') == "Yes" 23 | end 24 | 25 | end -------------------------------------------------------------------------------- /Support/app/helpers/annotate_helper.rb: -------------------------------------------------------------------------------- 1 | module AnnotateHelper 2 | def selected_line_range 3 | lines = parse_selection_string(ENV['TM_SELECTION']).flatten 4 | [lines.min, lines.max] 5 | end 6 | 7 | # Parses the selection string and includes an array containing the lines 8 | # selected in the document 9 | def parse_selection_string(str) 10 | str.split('&').map do |range| 11 | if range =~ /(\d+)(?::(\d+))?(?:\+\d+)?(?:([-x])(\d+)(?::(\d+))?(?:\+\d+)?)?/ 12 | l1, l2, c1, c2 = $1.to_i, ($4 ? $4.to_i : nil), ($2 || 1).to_i, ($5 || 1).to_i 13 | l1, l2, c1, c2 = l2, l1, c2, c1 if l2 && (l1 > l2 || l1 == l2 && c1 > c2) 14 | 15 | case $3 16 | when 'x' 17 | [ l1, l2 ] 18 | when '-' 19 | l2 -= 1 if c2 == 1 20 | [ l1, l2 ] 21 | else 22 | [ l1, l1 ] 23 | end 24 | else 25 | abort "unsupported selection string syntax: ‘#{range}’" 26 | end 27 | end 28 | end 29 | end -------------------------------------------------------------------------------- /Support/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def short_rev(rev) 3 | rev.to_s[0..7] 4 | end 5 | 6 | def git 7 | @git ||= Git.new 8 | end 9 | 10 | def link_to_relative_file(git, file_path, line = nil, title = nil) 11 | if line 12 | link_to_textmate(title || git.root_relative_path_for(file_path), git.path_for(file_path), line) 13 | else 14 | link_to_mate(title || git.root_relative_path_for(file_path), git.path_for(file_path)) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /Support/app/helpers/config_helper.rb: -------------------------------------------------------------------------------- 1 | module ConfigHelper 2 | def config_text_field(local_or_global, config_key, options = {}) 3 | content_tag :input, {:type => "text", :value => git.config[local_or_global, config_key], :onchange => "dispatch({controller: 'config', action: 'set', scope: '#{local_or_global}', key: '#{config_key}', value: $F(this)})"}.merge(options) 4 | end 5 | end -------------------------------------------------------------------------------- /Support/app/helpers/diff_helper.rb: -------------------------------------------------------------------------------- 1 | module DiffHelper 2 | def extract_submodule_revisions(diff_result) 3 | diff_result[:lines].map do |line| 4 | line[:text].gsub("Subproject commit ", "") 5 | end 6 | end 7 | 8 | def htmlize_highlight_trailing_whitespace (text) 9 | if text =~ /[ \t]+$/ 10 | htmlize($`) + content_tag(:span, $&, :class => "trailing-whitespace") 11 | else 12 | htmlize(text) 13 | end 14 | end 15 | end -------------------------------------------------------------------------------- /Support/app/helpers/submodule_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module SubmoduleHelper 4 | module Update 5 | def with_submodule_updating(&block) 6 | old_modules = get_submodule_hash 7 | begin 8 | yield 9 | ensure 10 | new_modules = get_submodule_hash 11 | 12 | submodule_paths = (new_modules.keys + old_modules.keys).sort.uniq 13 | return if submodule_paths.empty? 14 | submodule_paths.each do |path| 15 | old_module, new_module = old_modules[path], new_modules[path] 16 | case 17 | when old_module && old_module.modified? 18 | puts "

Not updating submodule #{new_module.path.inspect}, because it's revision pointer change isn't committed.

" 19 | when new_module && ! new_module.cloned? 20 | puts "

Cloning new submodule #{new_module.path.inspect}

" 21 | puts "
#{h new_module.init}\n#{h new_module.update}
" 22 | when old_module && ! new_module 23 | puts "

Cacheing submodule #{old_module.path.inspect} to #{old_module.git.root_relative_path_for(old_module.abs_cache_path).inspect}

" 24 | old_module.cache 25 | when new_module && new_module.cached? 26 | puts "

Restoring submodule #{new_module.path.inspect} from cache.

" 27 | puts "Restoration failed: a folder is in the way." unless new_module.restore 28 | update_submodule(new_module) if new_module.modified? 29 | when ( ! old_module ) || ( ! old_module.modified? ) && new_module.modified? 30 | puts "

Updating submodule #{new_module.path.inspect}

" 31 | update_submodule(new_module) 32 | end 33 | flush 34 | end 35 | end 36 | end 37 | 38 | def get_submodule_hash 39 | git.submodule.all.inject({}) { |h, sm| h[sm.path] = sm; h } 40 | end 41 | 42 | def update_submodule(submodule) 43 | puts "
#{h submodule.update}
" 44 | end 45 | end 46 | 47 | def render_submodule_header(submodule) 48 | puts "

... in submodule ‘#{link_to_mate(submodule.path, submodule.git.path)}’

" 49 | end 50 | end -------------------------------------------------------------------------------- /Support/app/views/annotate/_content.html.erb: -------------------------------------------------------------------------------- 1 | <% 2 | # puts annotations.inspect 3 | last_formatted_line = {} 4 | 5 | range_min, range_max = selected_line_range 6 | 7 | formatted_annotations = annotations.map do |annotation| 8 | line_class = [] 9 | 10 | if (range_min == range_max) && range_min == annotation[:ln].to_i 11 | line_class << "selected" 12 | elsif range_min == annotation[:ln].to_i 13 | line_class << "ranged-top" 14 | elsif range_max == annotation[:ln].to_i 15 | line_class << "ranged-bottom" 16 | elsif annotation[:ln].to_i.between?(range_min, range_max) 17 | line_class << "ranged-middle" 18 | end 19 | 20 | line_class << "ins" if annotation[:rev] == "-current-" || annotation[:rev] == revision 21 | line_class = line_class * " " 22 | formatted_line = { 23 | :rev => annotation[:rev], 24 | :author => annotation[:author], 25 | :date => relative_date(annotation[:date]), 26 | :ln => annotation[:ln], 27 | :text => annotation[:text] 28 | } 29 | display = formatted_line.dup 30 | 31 | [:rev, :author, :date].each { |k| display[k] = "…" } if display[:rev]==last_formatted_line[:rev] 32 | 33 | friendly_date = annotation[:date].is_a?(Time) ? annotation[:date].to_friendly : annotation[:date] 34 | 35 | display[:rev_tooltip] = < 46 | 47 | 48 | 49 | <% unless @as_partial %>
<% end %> 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 61 | 62 | <% for display in formatted_annotations %> 63 | 64 | 65 | 72 | 73 | 74 | 75 | 76 | 77 | <% end %> 78 | 79 |
revisionauthordateline 59 |
66 | <% if display[:rev]=="…" %> 67 | <%= display[:rev] %> 68 | <% else %> 69 | <%= link_to_function display[:rev], "show_annotation('#{display[:rev]}');", :title => htmlize_attr(display[:rev_tooltip]) %> 70 | <% end %> 71 | <%= make_non_breaking display[:author] %><%= make_non_breaking display[:date] %><%= display[:ln] %><%= htmlize(display[:text]) %>
80 | <% unless @as_partial %>
<% end %> 81 |
-------------------------------------------------------------------------------- /Support/app/views/annotate/_navigate_box.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Support/app/views/annotate/_select_revision.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Support/app/views/annotate/index.html.erb: -------------------------------------------------------------------------------- 1 | <% render "_navigate_box", :locals => { :log_entries => @log_entries, :revision => @revision } %> 2 | <% render "_content", :locals => { :annotations => @annotations, :revision => @revision } %> 3 | 4 | <% content_for :javascript do %> 5 | 87 | <% end %> -------------------------------------------------------------------------------- /Support/app/views/branch/merge.html.erb: -------------------------------------------------------------------------------- 1 |
 2 |   <%= @result[:text] %>
 3 | 
4 | 5 | <% unless @result[:conflicts].empty? %> 6 |

Conflicts - resolve each of the following then commit:

7 | <% @result[:conflicts].each do |conflicted_file| %> 8 | <% full_path = File.join(git.path, conflicted_file) %> 9 |
10 | <%= link_to_textmate conflicted_file, full_path %> 11 |
12 | <% end %> 13 | <% end %> 14 | -------------------------------------------------------------------------------- /Support/app/views/commit/_commit_result.html.erb: -------------------------------------------------------------------------------- 1 |

Result:

2 | 3 |
<%= htmlize(result[:output]) %>
4 | 5 |

Commit Files:

6 | 11 | 12 |

Using Message:

13 |
<%= htmlize_attr(message) %>
14 | 15 | <% if result[:rev] %> 16 |

Diff of committed changes:

17 | <% render_component(:controller => "diff", :action => "diff", :path => ".", :revisions => "#{result[:rev]}^..#{result[:rev]}") %> 18 | <% end %> 19 | -------------------------------------------------------------------------------- /Support/app/views/commit/merge_commit.html.erb: -------------------------------------------------------------------------------- 1 |

Resolve a merge conflict

2 | 3 | <% if @status.any? {|status_options| status_options[:status][:short] == "C"} %> 4 |

You still have outstanding merge conflicts. Resolve them, and try to commit again.

5 | <% else %> 6 |

Commit the result of a merge conflict

7 |
8 |

Message:

9 |
10 | 11 |
12 | 13 | 14 |
15 | <% end %> 16 | -------------------------------------------------------------------------------- /Support/app/views/commit/not_on_a_branch.html.erb: -------------------------------------------------------------------------------- 1 |

Eegad! You're not on a branch

2 |

3 | To make this commit, first checkout the branch you'd like to commit to, then make the commit. 4 |

5 |

Suggested branches:

6 |
<%= git.command("branch", "--contains", "HEAD", "-a").gsub(/^.+no branch.*$/, "") %>
-------------------------------------------------------------------------------- /Support/app/views/config/index.html.erb: -------------------------------------------------------------------------------- 1 |

Git Config

2 |

Values are saved when the form-field loses focus.

3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% 15 | tabindex = 0 16 | [ 17 | ["Name", "user.name", [:global]], 18 | ["Email", "user.email", [:global]], 19 | [], 20 | ["Log limit", "git-tmbundle.log.limit", [:global, :local], {:style => "width: 40px"}], 21 | ["Log context lines", "git-tmbundle.log.context-lines", [:global, :local], {:style => "width: 40px"}], 22 | ["Show diff check (yes or no)", "git-tmbundle.show-diff-check", [:global, :local], {:style => "width: 40px"}], 23 | [], 24 | ["Gitnub path", "git-tmbundle.gitnub-path", [:global], {:style => "width: 250px"}], 25 | ["GitX path", "git-tmbundle.gitx-path", [:global], {:style => "width: 250px"}], 26 | ].each do |label, key, scopes, input_options| 27 | %> 28 | 29 | <% [:global, :local].each do |scope| %> 30 | <% if scopes && scopes.include?(scope) 31 | tabindex += 1 %> 32 | 33 | 34 | <% else %> 35 | 36 | 37 | <% end %> 38 | <% end %> 39 | 40 | <% end %> 41 | 42 |
GlobalLocal
<%= label %><%= config_text_field scope, key, {:tabindex => tabindex}.merge(input_options || {}) %>  
43 | 44 |
45 | 46 | -------------------------------------------------------------------------------- /Support/app/views/diff/_diff_check_result.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | <% diff_result[:lines].each do |line| 10 | next if @diff_line_count >= Git::DEFAULT_DIFF_LIMIT 11 | @diff_line_count += 1 12 | line_num_class, row_class = case line[:type] 13 | when :deletion then ["", "del"] 14 | when :insertion then ["", "ins"] 15 | when :eof then ["line-num-eof", "eof"] 16 | when :cut then ["line-num-cut", "cut-line"] 17 | else 18 | ["", "unchanged"] 19 | end 20 | %> 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <% end %> 30 | 31 |
5 | <%= link_to_relative_file(git, diff_result[:file_path], diff_result[:file_line]) %>
<%= htmlize(diff_result[:warning]) %>
<%= diff_result[:file_line] %><%= htmlize(line[:text]) %>
32 | -------------------------------------------------------------------------------- /Support/app/views/diff/_diff_result.html.erb: -------------------------------------------------------------------------------- 1 | <% 2 | file_path_right = diff_result[:right][:file_path] 3 | start_line_right = diff_result[:right][:ln_start] 4 | 5 | open_links = {} 6 | files = [:left, :right].map do |lr| 7 | file_path = diff_result[lr][:file_path] 8 | next "(none)" unless file_path 9 | 10 | side_revision = case 11 | when revision.blank? && lr == :right 12 | nil 13 | when revision.blank? && lr == :left 14 | "HEAD" 15 | when revision 16 | lr == :left ? "#{revision}^" : revision 17 | end 18 | open_links[lr] = link_to_remote(lr, :params => { :controller => "log", :action => "open_revision", :file_path => file_path, :revision => side_revision, :line => diff_result[lr][:ln_start], :git_path => git.path }) 19 | 20 | file_path_right ? link_to_relative_file(git, file_path_right, start_line_right) : git.root_relative_path_for(file_path) 21 | end 22 | %> 23 | 24 |

<%= files.uniq * ' --> ' %>

25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | <% diff_result[:lines].each do |line| 35 | next if @diff_line_count >= Git::DEFAULT_DIFF_LIMIT 36 | @diff_line_count += 1 37 | text = line[:text] 38 | escape_html = true 39 | 40 | line_num_class, row_class = case line[:type] 41 | when :insertion 42 | text = htmlize_highlight_trailing_whitespace(text) 43 | escape_html = false # set to false since the above function escapes HTML 44 | ["", "ins"] 45 | 46 | when :deletion then ["", "del"] 47 | when :eof then ["line-num-eof", "eof"] 48 | when :cut then ["line-num-cut", "cut-line"] 49 | else 50 | ["", "unchanged"] 51 | end 52 | 53 | text = htmlize(text) if escape_html 54 | 55 | ln_right = line[:ln_right] 56 | ln_right = link_to_relative_file(git, diff_result[:right][:file_path], ln_right, ln_right) unless [ :deletion, :eof, :cut ].include?(line[:type]) 57 | %> 58 | 59 | 60 | 61 | 62 | <% end %> 63 | 64 |
<%= open_links[:left] %><%= open_links[:right] %> 31 |
<%= line[:ln_left] %><%= ln_right %><%= text %>
65 | -------------------------------------------------------------------------------- /Support/app/views/diff/_diff_results.html.erb: -------------------------------------------------------------------------------- 1 | <% @diff_line_count = 0 %> 2 | <% revision ||= nil %> 3 | 4 | <% if not (diff_check_results||=[]).empty? %> 5 | <% diff_check_results.each do |diff_result| %> 6 | <% render "diff/_diff_check_result", :locals => {:git => git, :diff_result => diff_result } %> 7 | <% flush %> 8 | <% end %> 9 | <% end %> 10 | <% diff_results.each do |diff_result| %> 11 | <% next if @diff_line_count >= Git::DEFAULT_DIFF_LIMIT %> 12 | <% if diff_result[:mode] == Git::SUBMODULE_MODE %> 13 | <% render "diff/_submodule_diff_result", :locals => {:git => git, :diff_result => diff_result, :revision => revision } %> 14 | <% else %> 15 | <% render "diff/_diff_result", :locals => {:git => git, :diff_result => diff_result, :revision => revision } %> 16 | <% end %> 17 | <% flush %> 18 | <% end %> 19 | 20 | <% if @diff_line_count >= Git::DEFAULT_DIFF_LIMIT %> 21 |

Diff taking to long to render... aborted

22 | <% end %> -------------------------------------------------------------------------------- /Support/app/views/diff/_submodule_diff_result.html.erb: -------------------------------------------------------------------------------- 1 | <% 2 | case diff_result[:status] 3 | when :new 4 | %> 5 |

Submodule added: <%= link_to_relative_file(git, diff_result[:right][:file_path]) %>

6 | <% 7 | when :deleted 8 | %> 9 |

Submodule deleted: <%= link_to_relative_file(git, diff_result[:left][:file_path]) %>

10 | <% 11 | when :modified 12 | file_path = diff_result[:left][:file_path] 13 | revision_left, revision_right = extract_submodule_revisions(diff_result) 14 | 15 | revision_right = diff_result[:lines][1][:text].gsub("Subproject commit ", "") 16 | %> 17 |

Submodule modified: <%= link_to_relative_file(git, diff_result[:left][:file_path]) %>

18 | <% 19 | revisions = [git.short_rev(revision_left), git.short_rev(revision_right)] * ".." 20 | expanded_detail_dom_id = "log_" + revisions.gsub(".", "_") 21 | %> 22 | + 23 |

<%= revisions %>

24 | <%= content_tag :div, :class => "log", :style => "display: none;", :revisions => revisions, :git_path => git.path_for(file_path), :id => expanded_detail_dom_id %> 25 | 26 | <% 27 | end 28 | %> -------------------------------------------------------------------------------- /Support/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | <% script_tag = javascript_include_tag("prototype", "rb_gateway", "toggle") %> 2 | 3 | 4 | 5 | 6 | <% if @script_at_top %> 7 | <%= script_tag %> 8 | <% end %> 9 | 10 | 11 |
12 | <% yield %> 13 | 14 | 15 | <% unless @script_at_top %> 16 | <%= script_tag %> 17 | <% end %> 18 | <%= @content_for_javascript %> 19 | <% if params[:on_complete] %> 20 | 25 | <% end %> 26 | 27 | -------------------------------------------------------------------------------- /Support/app/views/log/_log_entry.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | <% expanded_detail_dom_id = "detail_#{branch_name}_#{log_entry[:rev]}" %> 4 | + 5 | 6 | <%= short_rev(log_entry[:rev]) %> 7 | committed by 8 | <%= log_entry[:author] %> 9 | 10 | 11 | 12 | 13 | <%= htmlize(relative_date(log_entry[:date])) %> ago 14 | 15 | 16 |
17 |
18 |
19 |
20 | <%= htmlize(log_entry[:msg])%> 21 |
22 |
23 | <%= content_tag :div, :class => "diff", :style => "display: none;", :rev => log_entry[:rev], :path => path, :git_path => git.path, :id => expanded_detail_dom_id %> 24 |
25 |
-------------------------------------------------------------------------------- /Support/app/views/log/log_entries.html.erb: -------------------------------------------------------------------------------- 1 |

Log entries

2 | 3 | <% @log_entries.each do |log_entry| %> 4 | <% render("_log_entry", :locals => {:git => git, :log_entry => log_entry, :branch_name => @branch_name, :path => @path }) %> 5 | <% flush %> 6 | <% end %> 7 | -------------------------------------------------------------------------------- /Support/app/views/status/_status.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <% status_data.each do |e| %> 3 | 4 | 9 | 16 | 17 | <% end %> 18 |
5 | 6 | <%= htmlize(e[:status][:short]) %> 7 | 8 | 10 | <% if e[:path][-1..-1]=="/" %> 11 | <%= htmlize(git.root_relative_path_for(e[:display])) %> 12 | <% else %> 13 | <%= link_to_relative_file(git, e[:path]) %> 14 | <% end %> 15 |
-------------------------------------------------------------------------------- /Support/app/views/submodule/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_tag :h1, "Submodules on branch ‘#{git.branch.current_name}’"%> 2 | 3 |
4 | <% render_component(:controller => "submodule", :action => "list", :layout => false) %> 5 |
6 | <%= button_to_remote("Add...", :params => {:controller => "submodule", :action => "add" }, 7 | :on_complete => remote_function(:params => {:controller => "submodule", :action => "list"}, :update => "submodules"), 8 | :update_streaming => "iframe_output") 9 | %> 10 | 11 | <%= button_to_remote("Force Update", :params => {:controller => "submodule", :action => "update" }, 12 | :on_complete => remote_function(:params => {:controller => "submodule", :action => "list"}, :update => "submodules"), 13 | :update_streaming => "iframe_output") 14 | %> 15 | 16 | -------------------------------------------------------------------------------- /Support/app/views/submodule/list.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | <% @submodules.each do |submodule| %> 13 | 14 | 15 | 16 | 17 | 18 | 19 | <% end %> 20 | <% if @submodules.empty? %> 21 | 22 | 23 | 24 | <% end %> 25 | 26 |
StatusNameRevisionTag
<%= submodule.modified? ? "M" : "" %><%= link_to_mate submodule.name, File.join(git.path, submodule.name) %><%= git.short_rev(submodule.current_revision) %><%= submodule.current_revision_description %>
No submodules defined.
-------------------------------------------------------------------------------- /Support/dispatch.rb: -------------------------------------------------------------------------------- 1 | $dispatch_loaded = true 2 | require File.dirname(__FILE__) + "/environment.rb" 3 | 4 | dispatch(ARGV) if $0 == __FILE__ && ! $dispatched 5 | -------------------------------------------------------------------------------- /Support/environment.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/tmvc/tmvc.rb' 2 | 3 | LIB_ROOT = ROOT + "/lib" 4 | %w[auto_load date_helpers git].each do |filename| 5 | require "#{LIB_ROOT}/#{filename}.rb" 6 | end 7 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape.rb' 8 | require 'shellwords' 9 | require 'set' 10 | 11 | def shorten(path, base = nil) 12 | return if path.blank? 13 | base = base.gsub(/\/$/, "") if base 14 | project_path = 15 | home_path = ENV['HOME'] 16 | case 17 | when base && path =~ /^#{Regexp.escape base}\/(.+)$/ 18 | $1 19 | when base && path =~ /^#{Regexp.escape base}\/?$/ 20 | "./" 21 | when path == project_path 22 | File.basename(path) 23 | when ENV['TM_PROJECT_DIRECTORY'] && path =~ /^#{Regexp.escape ENV['TM_PROJECT_DIRECTORY']}\/(.+)$/ 24 | $1 25 | when ENV['HOME'] && path =~ /^#{Regexp.escape ENV['HOME']}\/(.+)$/ 26 | '~/' + $1 27 | else 28 | path 29 | end 30 | end 31 | 32 | class Module 33 | def alias_method_chain(target, feature) 34 | # Strip out punctuation on predicates or bang methods since 35 | # e.g. target?_without_feature is not a valid method name. 36 | aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 37 | yield(aliased_target, punctuation) if block_given? 38 | 39 | with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" 40 | 41 | alias_method without_method, target 42 | alias_method target, with_method 43 | 44 | case 45 | when public_method_defined?(without_method) 46 | public target 47 | when protected_method_defined?(without_method) 48 | protected target 49 | when private_method_defined?(without_method) 50 | private target 51 | end 52 | end 53 | end 54 | 55 | class Array 56 | def with_this_at_front(front_matcher) 57 | case front_matcher 58 | when Array 59 | (front_matcher + self).uniq 60 | when String, Symbol 61 | ([front_matcher] + self).uniq 62 | when Regexp 63 | (self.grep(front_matcher) + self).uniq 64 | else 65 | self 66 | end 67 | end 68 | end -------------------------------------------------------------------------------- /Support/gateway/commit_dialog_helper.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby18 2 | require File.dirname(__FILE__) + '/../environment.rb' 3 | git = Git.new 4 | command = ARGV.shift 5 | case command 6 | when "delete" 7 | file_path = ARGV.shift 8 | File.delete(git.path_for(file_path)) 9 | puts "\000 #{file_path}asdf" 10 | when "revert" 11 | file_path = ARGV.shift 12 | File.open("#{ENV['TMPDIR']}/output", "wb") {|f| f.puts ARGV.inspect} 13 | git.revert(file_path) 14 | puts "\000 #{file_path}" 15 | end 16 | 17 | -------------------------------------------------------------------------------- /Support/lib/auto_load.rb: -------------------------------------------------------------------------------- 1 | module AutoLoad 2 | def const_missing(name) 3 | name = name.to_s 4 | case name 5 | when /Controller$/ 6 | path = "/app/controllers" 7 | when /Helper$/ 8 | path = "/app/helpers" 9 | else 10 | return super 11 | end 12 | 13 | @last_try||=nil 14 | super if @last_try==name 15 | @last_try = name 16 | 17 | file = File.join(ROOT, path, name.to_s.underscore + ".rb") 18 | require file 19 | name.constantize 20 | klass = const_get(name) 21 | rescue LoadError 22 | super 23 | end 24 | end 25 | 26 | Object.send :extend, AutoLoad -------------------------------------------------------------------------------- /Support/lib/commands/config.rb: -------------------------------------------------------------------------------- 1 | class SCM::Git::Config < SCM::Git::CommandProxyBase 2 | DEFAULT_LOG_LIMIT = 100 3 | def [](*params) 4 | scope, key = process_keys(params) 5 | r = base.command(*(["config"] + config_args(scope) + [key])) 6 | r.blank? ? nil : r.gsub(/\n$/, '') 7 | end 8 | 9 | def []=(*params) 10 | value = params.pop 11 | scope, key = process_keys(params) 12 | args = ["config"] + config_args(scope) 13 | if value 14 | args += [key, value] 15 | else 16 | args += ["--unset", key] 17 | end 18 | base.command(*args) 19 | end 20 | 21 | def log_limit 22 | self["git-tmbundle.log.limit"] || DEFAULT_LOG_LIMIT 23 | end 24 | 25 | def show_diff_check? 26 | %w[yes 1 auto].include?(self["git-tmbundle.show-diff-check"].to_s.downcase.strip) 27 | end 28 | 29 | def context_lines 30 | self["git-tmbundle.log.context-lines"] 31 | end 32 | 33 | protected 34 | def config_args(scope) 35 | case scope.to_s 36 | when "global" 37 | ["--global"] 38 | when "local", "file" 39 | ["--file", File.join(@base.path, ".git/config")] 40 | when "default" 41 | [] 42 | else 43 | raise "I don't understand the scope #{scope.inspect}" 44 | end 45 | end 46 | 47 | def process_keys(params) 48 | params = [:default, params.first] if params.length == 1 49 | params 50 | end 51 | end -------------------------------------------------------------------------------- /Support/lib/commands/proxy_command_base.rb: -------------------------------------------------------------------------------- 1 | module SCM 2 | class Git 3 | class CommandProxyBase 4 | attr_accessor :base 5 | def initialize(base) 6 | @base = base 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /Support/lib/commands/remote.rb: -------------------------------------------------------------------------------- 1 | class SCM::Git::Remote < SCM::Git::CommandProxyBase 2 | def [](name) 3 | @remotes ||= {} 4 | @remotes[name] ||= SCM::Git::Remote::RemoteProxy.new(@base, self, name) 5 | end 6 | 7 | def all 8 | names.map do |name| 9 | RemoteProxy.new(self, @base, name) 10 | end 11 | end 12 | 13 | def names 14 | @base.command("remote").split("\n") 15 | end 16 | 17 | class RemoteProxy 18 | attr_reader :name 19 | 20 | def initialize(base, parent, name, options = {}) 21 | @base = base 22 | @parent = parent 23 | @name = name 24 | end 25 | 26 | def fetch_refspec(reload = false) 27 | @fetch_refspec = nil if reload 28 | @fetch_refspec ||= @base.config["remote.#{name}.fetch"] 29 | end 30 | 31 | def remote_branch_name_for(branch_name, format = :short) 32 | branch_name = "refs/heads/#{branch_name}" unless branch_name[0..10] == "refs/heads/" 33 | sub_from, sub_to = fetch_refspec.scan(/\+?(.+)\*:(.+)\*$/).flatten 34 | branch_name = branch_name.gsub(sub_from, sub_to) 35 | if format == :short 36 | branch_name.gsub("refs/remotes/", "") 37 | else 38 | branch_name 39 | end 40 | end 41 | 42 | def remote_branch_prefix 43 | /\*:(.+)\*/.match(fetch_refspec) 44 | $1 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /Support/lib/commands/stash.rb: -------------------------------------------------------------------------------- 1 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' 2 | 3 | class SCM::Git::Stash < SCM::Git::CommandProxyBase 4 | def list 5 | base.command("stash", "list").split("\n").map do |line| 6 | /^(.+?):(.+)$/.match(line) 7 | name = $1 8 | description = $2 9 | /([0-9]+)/.match(name) 10 | {:id => $1.to_i, :name => name, :description => description} 11 | end 12 | end 13 | 14 | def save(desciption = "") 15 | params = [] 16 | params << desciption unless desciption.nil? || desciption.empty? 17 | base.command("stash", "save", *params) 18 | end 19 | 20 | def diff(name) 21 | base.parse_diff(base.command("stash", "show", "-p", name)) 22 | end 23 | 24 | def apply(name) 25 | args = ["stash", "apply"] 26 | args << "--index" if options[:index] 27 | args << name 28 | base.command(*args) 29 | end 30 | 31 | def pop(name, options = {}) 32 | args = ["stash", "pop"] 33 | args << "--index" if options[:index] 34 | args << name 35 | base.command(*args) 36 | end 37 | 38 | def clear 39 | base.command("stash", "clear") 40 | end 41 | end -------------------------------------------------------------------------------- /Support/lib/commands/submodule.rb: -------------------------------------------------------------------------------- 1 | require 'digest/md5' 2 | require 'fileutils' 3 | 4 | class SCM::Git::Submodule < SCM::Git::CommandProxyBase 5 | def init_and_update 6 | output = @base.command("submodule", "init") 7 | output << @base.command("submodule", "update") 8 | output 9 | end 10 | 11 | def all(options = {}) 12 | list(options).map do |sm| 13 | SubmoduleProxy.new(@base, self, sm) 14 | end 15 | end 16 | 17 | def add(repository, path) 18 | path = @base.make_local_path(path) 19 | @base.popen_command("submodule", "add", "--", repository, path) 20 | end 21 | 22 | protected 23 | def list(options = {}) 24 | args = ["ls-files", "--stage"] 25 | args << options[:path] if options[:path] 26 | @base.command(*args).split("\n").grep(/^160000 /).map do |line| 27 | next unless line.match(/^160000\s*([a-f0-9]+)\s*([0-9]+)\s*(.+)/) 28 | { 29 | :revision => $1, 30 | :path => $3 31 | } 32 | end.compact 33 | end 34 | 35 | class SubmoduleProxy 36 | attr_reader :revision, :path, :tag, :state 37 | 38 | def initialize(base, parent, options = {}) 39 | @base, @parent, @tag = base, parent, tag 40 | options.each do |key, value| 41 | instance_variable_set("@#{key}", value) 42 | end 43 | end 44 | 45 | def url 46 | @url ||= @base.config[:local, "submodule.#{path}.url"] 47 | end 48 | 49 | def name 50 | path 51 | end 52 | 53 | def abs_cache_path 54 | @abs_cache_path ||= File.join(@base.path, ".git/submodule_cache", Digest::MD5.hexdigest("#{path} #{url}")) 55 | end 56 | 57 | def abs_path 58 | @abs_path ||= File.join(@base.path, @path) 59 | end 60 | 61 | def cache 62 | if cloned? 63 | if File.exist?(abs_cache_path) 64 | puts "

Cowardly refusing to overwrite cached submodule in #{abs_cache_path} (please look at the contents of that folder, move it out of the way, then try again)

" 65 | abort 66 | end 67 | 68 | FileUtils.mkdir_p(File.dirname(abs_cache_path)) 69 | FileUtils.mv(abs_path, abs_cache_path, :force => true) 70 | true 71 | end 72 | end 73 | 74 | def restore 75 | return false if Dir.has_a_file?(abs_path) 76 | if cached? 77 | FileUtils.rm_rf(abs_path) 78 | FileUtils.mkdir_p(File.dirname(abs_path)) 79 | FileUtils.mv(abs_cache_path, abs_path, :force => true) 80 | end 81 | true 82 | end 83 | 84 | def git 85 | @git ||= @base.with_path(abs_path) 86 | end 87 | 88 | def current_revision(reload = false) 89 | @current_revision = nil if reload 90 | @current_revision ||= git.current_revision 91 | end 92 | 93 | def current_revision_description 94 | @current_revision_description ||= git.describe(current_revision) 95 | end 96 | 97 | def revision_description 98 | @revision_description ||= git.describe(revision) 99 | end 100 | 101 | def modified? 102 | return false unless cloned? 103 | current_revision != revision 104 | end 105 | 106 | def cloned? 107 | File.exist?(File.join(abs_path, ".git")) || cached? 108 | end 109 | 110 | def cached? 111 | File.exist?(abs_cache_path) 112 | end 113 | 114 | def update 115 | @base.command("submodule", "update", path) 116 | end 117 | 118 | def init 119 | @base.command("submodule", "init", path) 120 | end 121 | end 122 | end 123 | 124 | class Dir 125 | def self.has_a_file?(abs_path) 126 | Dir[abs_path + "/**/*"].any? {|f| File.file?(f) } 127 | end 128 | end -------------------------------------------------------------------------------- /Support/lib/commands/svn.rb: -------------------------------------------------------------------------------- 1 | class SCM::Git::Svn < SCM::Git::CommandProxyBase 2 | 3 | def dcommit 4 | base.command("svn","dcommit") 5 | end 6 | 7 | def fetch 8 | base.command("svn","fetch") 9 | end 10 | 11 | def rebase 12 | base.command("svn","rebase") 13 | end 14 | end -------------------------------------------------------------------------------- /Support/lib/date_helpers.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'date.rb' 3 | require 'time.rb' 4 | 5 | module FriendlyTime 6 | def to_friendly(time=true) 7 | time=false if Date==self.class 8 | 9 | ret_val = if time 10 | strftime "%b %d, %Y %I:%M %p" + (time=="zone"? " %Z" : "") 11 | else 12 | strftime "%b %d, %Y" 13 | end 14 | 15 | ret_val.gsub(" 0", " ") 16 | end 17 | end 18 | 19 | class Time; include FriendlyTime; end 20 | class Date; include FriendlyTime; end 21 | class DateTime; include FriendlyTime; end 22 | 23 | module DateHelpers 24 | def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false) 25 | from_time = from_time.to_time if from_time.respond_to?(:to_time) 26 | to_time = to_time.to_time if to_time.respond_to?(:to_time) 27 | distance_in_minutes = (((to_time - from_time).abs)/60).round 28 | distance_in_seconds = ((to_time - from_time).abs).round 29 | 30 | case distance_in_minutes 31 | when 0..1 32 | return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds 33 | case distance_in_seconds 34 | when 0..4 then '< 5 seconds' 35 | when 5..9 then '< 10 seconds' 36 | when 10..19 then '< 20 seconds' 37 | when 20..39 then '½ minute' 38 | when 40..59 then '< a minute' 39 | else '1 minute' 40 | end 41 | 42 | when 2..44 then "#{distance_in_minutes} minutes" 43 | when 45..89 then '~1 hour' 44 | when 90..1439 then "~#{(distance_in_minutes.to_f / 60.0).round} hours" 45 | when 1440..2879 then '1 day' 46 | when 2880..43199 then "#{(distance_in_minutes / 1440).round} days" 47 | when 43200..86399 then '~1 month' 48 | when 86400..525599 then "#{(distance_in_minutes / 43200).round} months" 49 | when 525600..1051199 then '~1 year' 50 | else "> #{(distance_in_minutes / 525600).round} years" 51 | end 52 | end 53 | 54 | def relative_date(date) 55 | return date if date.is_a?(String) 56 | distance_of_time_in_words(Time.now, date) 57 | end 58 | end -------------------------------------------------------------------------------- /Support/lib/partial_commit_worker.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module PartialCommitWorker 4 | class NotOnBranchException < Exception; end 5 | class NothingToCommitException < Exception; end 6 | class NothingToAmendException < Exception; end 7 | class CommitCanceledException < Exception; end 8 | 9 | def self.factory(_type, *args) 10 | klass = (_type == "amend" ? PartialCommitWorker::Amend : PartialCommitWorker::Normal) 11 | klass.new(*args) 12 | end 13 | 14 | class Base 15 | COMMIT_CONTINUE = 'TM_SCM_COMMIT_CONTINUE=1' 16 | attr_reader :git 17 | 18 | def initialize(git) 19 | @git = git 20 | @base = git.path 21 | end 22 | 23 | def ok_to_proceed_with_partial_commit? 24 | git.rebase_in_progress? || (! git.branch.current_name.nil?) || git.initial_commit_pending? 25 | end 26 | 27 | def target_paths 28 | @target_paths ||= git.paths 29 | end 30 | 31 | def split_file_statuses 32 | [file_candidates.map{ |fc| fc[0] }, file_candidates.map{ |fc| fc[1] }] 33 | end 34 | 35 | def status_helper_tool 36 | ENV['TM_BUNDLE_SUPPORT'] + '/gateway/commit_dialog_helper.rb' 37 | end 38 | 39 | def tm_scm_commit_window 40 | files, statuses = split_file_statuses 41 | 42 | res = "" 43 | res << "cd \"#{git.path}\" && \"$TM_SCM_COMMIT_WINDOW\"" 44 | res << " --log #{Shellwords.escape(git.log(:limit => 1).first[:msg])}" if amend? 45 | res << " --diff-cmd '#{git.git},diff,HEAD,--'" 46 | res << " --action-cmd 'M,D:${TM_DISPLAYNAME:?Revert “${TM_DISPLAYNAME}”:Revert},#{status_helper_tool},revert'" 47 | res << " --action-cmd '?:${TM_DISPLAYNAME:?Delete “${TM_DISPLAYNAME}”:Delete},#{status_helper_tool},delete'" 48 | res << " --status #{statuses.join(':')}" if !amend? || (amend? && !file_candidates.empty?) 49 | res << " --show-continue-button" if git.rebase_in_progress? 50 | res << " --commit-button-title Amend" if amend? 51 | res << " #{files.map{ |f| e_sh(f) }.join(' ')} 2>/dev/console" 52 | 53 | res 54 | end 55 | 56 | def exec_commit_dialog 57 | res = %x{#{tm_scm_commit_window}} 58 | res = Shellwords.shellwords(res) 59 | 60 | continue = res.last == COMMIT_CONTINUE 61 | res = res[0 ... -1] if continue 62 | 63 | canceled = ($? != 0) 64 | msg = res[1] 65 | files = res[2..-1] 66 | return canceled, msg, files, continue 67 | end 68 | 69 | def show_commit_dialog 70 | canceled, msg, files, continue = exec_commit_dialog 71 | raise CommitCanceledException if canceled 72 | [msg, files, continue] 73 | end 74 | 75 | def file_candidates 76 | @file_candidates ||= 77 | git.status(target_paths).map do |e| 78 | [shorten(e[:path], @base), e[:status][:short]] 79 | end 80 | end 81 | 82 | def run 83 | raise NotOnBranchException unless ok_to_proceed_with_partial_commit? 84 | raise NothingToCommitException if nothing_to_commit? 85 | 86 | if amend? 87 | raise NothingToAmendException if nothing_to_amend? 88 | end 89 | 90 | msg, files, continue = show_commit_dialog 91 | git.auto_add_rm(files) 92 | res = git.commit(msg, files, :amend => amend?) 93 | git.command('rebase', '--continue') if continue 94 | { :files => files, :message => msg, :result => res} 95 | end 96 | 97 | def title 98 | "#{title_prefix} in #{target_paths.map { |e| htmlize("‘" + shorten(e, ENV['TM_PROJECT_DIRECTORY'] || @base) + "’") } * ', '} on branch ‘#{htmlize(git.branch.current_name)}’" 99 | end 100 | 101 | def nothing_to_commit? 102 | amend? ? false : file_candidates.empty? 103 | end 104 | 105 | def nothing_to_amend? 106 | git.initial_commit_pending? 107 | end 108 | end 109 | 110 | class Normal < Base 111 | def title_prefix 112 | "Committing Files" 113 | end 114 | 115 | def amend? 116 | false 117 | end 118 | end 119 | 120 | class Amend < Base 121 | 122 | def title_prefix 123 | "Amending the commit" 124 | end 125 | 126 | def amend? 127 | true 128 | end 129 | 130 | def show_commit_dialog(*args) 131 | msg, files, continue = super(*args) 132 | [msg, files, continue] 133 | end 134 | 135 | def file_candidates 136 | return @file_candidates if @file_candidates 137 | super 138 | @file_candidates 139 | end 140 | end 141 | end 142 | -------------------------------------------------------------------------------- /Support/lib/stream_progress_methods.rb: -------------------------------------------------------------------------------- 1 | 2 | module StreamProgressMethods 3 | extend self 4 | 5 | def each_line_from_stream(stream, &block) 6 | line = "" 7 | f = File.open("#{ENV['TMPDIR']}/output", "wb") 8 | stream.each_byte do |char| 9 | f.putc(char) 10 | char = [char].pack('c') 11 | line << char 12 | next unless char=="\n" || char=="\r" 13 | yield line 14 | line = "" 15 | end 16 | yield line 17 | stream 18 | end 19 | protected 20 | 21 | def process_with_progress(stream, options = {}, &block) 22 | options[:start_regexp] ||= /(?-:remote: )?([a-z]+) ([0-9]+) objects/i 23 | options[:progress_regexp] ||= /(?-:(?-:remote: )?([a-z]+) objects: +)?([0-9]+)% \(([0-9]+)\/([0-9]+)\)/i 24 | callbacks = options[:callbacks] 25 | state = nil 26 | each_line_from_stream(stream) do |line| 27 | case line 28 | when options[:start_regexp] 29 | state = $1 30 | callbacks[:start] && callbacks[:start].call(state, $2.to_i) 31 | percentage, index, count = 0, 0, $2.to_i 32 | when options[:progress_regexp] 33 | percentage, index, count = $2.to_i, $3.to_i, $4.to_i 34 | if $1 && state != $1 && percentage != 100 35 | state = $1 36 | callbacks[:start] && callbacks[:start].call(state, count) 37 | end 38 | else 39 | yield line 40 | end 41 | 42 | if state && index 43 | callbacks[:progress] && callbacks[:progress].call(state, percentage, index, count) 44 | if percentage == 100 45 | callbacks[:end] && callbacks[:end].call(state, count) 46 | state = nil 47 | end 48 | end 49 | end 50 | end 51 | 52 | def get_rev_range(input) 53 | revs = input.split("..").compact 54 | revs = ["#{revs[0]}^", revs[0]] if revs.length == 1 55 | revs 56 | end 57 | end 58 | 59 | 60 | module EnhancedStream 61 | def each_line_from_stream(&block) 62 | StreamProgressMethods.each_line_from_stream(self, &block) 63 | end 64 | 65 | def pipe_to(dest) 66 | each_line_from_stream do |line| 67 | dest << line 68 | dest.flush 69 | end 70 | end 71 | end 72 | 73 | IO.send :include, EnhancedStream 74 | StringIO.send :include, EnhancedStream 75 | -------------------------------------------------------------------------------- /Support/lib/ui.rb: -------------------------------------------------------------------------------- 1 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb' 2 | 3 | class << TextMate::UI 4 | def request_item_with_force_pick(options = {}, &block) 5 | if options[:force_pick] 6 | options[:items] << "" if options[:items].length == 1 7 | end 8 | 9 | request_item_without_force_pick(options, &block) 10 | end 11 | alias_method_chain :request_item, :force_pick 12 | 13 | def request_directory(title = "Select a directory", options = {}) 14 | options[:initial_directory] ||= ENV['TM_PROJECT_DIRECTORY'] || ENV['TM_FILEPATH'] 15 | result = `CocoaDialog fileselect --select-only-directories --with-directory "#{options[:initial_directory]}" --title "#{title}"` 16 | result.empty? ? nil : result.strip 17 | end 18 | end -------------------------------------------------------------------------------- /Support/nibs/CompareBranches.nib/keyedobjects.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/git.tmbundle/50e22e79ab3c8874f38fefef8cc6e7da0d0b3bcd/Support/nibs/CompareBranches.nib/keyedobjects.nib -------------------------------------------------------------------------------- /Support/nibs/RevisionSelector.nib/keyedobjects.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/git.tmbundle/50e22e79ab3c8874f38fefef8cc6e7da0d0b3bcd/Support/nibs/RevisionSelector.nib/keyedobjects.nib -------------------------------------------------------------------------------- /Support/resource/git-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textmate/git.tmbundle/50e22e79ab3c8874f38fefef8cc6e7da0d0b3bcd/Support/resource/git-logo.png -------------------------------------------------------------------------------- /Support/resource/rb_gateway.js: -------------------------------------------------------------------------------- 1 | /* Git JS gateway */ 2 | /* Tim Harper (tim.harper at leadmediapartners.org) */ 3 | function e_sh(str) { 4 | return '"' + (str.toString().gsub('"', '\\"').gsub('\\$', '\\$')) + '"'; 5 | } 6 | 7 | function exec(command, params) { 8 | params = params.map(function(a) { return e_sh(a) }).join(" ") 9 | return TextMate.system(command + " " + params, null) 10 | } 11 | 12 | function ENV(var_name) { 13 | return TextMate.system("echo $" + var_name, null).outputString.strip(); 14 | } 15 | 16 | function gateway_command(command, params) { 17 | // var cmd = arguments.shift 18 | // var params = arguments 19 | try { 20 | command = "ruby18 " + e_sh(TM_BUNDLE_SUPPORT) + "/gateway/" + command 21 | return exec(command, params).outputString 22 | } 23 | catch(err) { 24 | return "ERROR!" + err; 25 | } 26 | } 27 | 28 | 29 | function dispatch(params) { 30 | try { 31 | params = $H(params).map(function(pair) { return(pair.key + "=" + pair.value.toString())}) 32 | command = "ruby18 " + e_sh(TM_BUNDLE_SUPPORT) + "/dispatch.rb"; 33 | // return params.map(function(a) { return e_sh(a) }).join(" ") 34 | return exec(command, params).outputString 35 | } 36 | catch(err) { 37 | return "ERROR!" + err; 38 | } 39 | } 40 | 41 | function dispatch_streaming(iframe_target, options) { 42 | new StreamingDispatchExecuter(iframe_target, options); 43 | return false; 44 | } 45 | 46 | StreamingDispatchExecuter = Class.create(); 47 | StreamingDispatchExecuter.prototype = { 48 | initialize: function(iframe_target, options) { 49 | this.options = options; 50 | this.on_complete = options["on_complete"] 51 | params = options['params'] 52 | params['streaming']="true" 53 | var parts = dispatch(options['params']).split(",") 54 | this.port = parts[0]; 55 | this.pid = parts[1]; 56 | $(iframe_target).src = "http://127.0.0.1:" + this.port + "/" 57 | try { 58 | new PeriodicalExecuter(function(pe) { 59 | if (TextMate.system("kill -0 " + this.pid, null).status == 1) { 60 | pe.stop() 61 | if (this.on_complete) this.on_complete(); 62 | } 63 | }.bindAsEventListener(this), 0.5) 64 | } catch(e) {$('debug').update(e)} 65 | 66 | }, 67 | 68 | } 69 | 70 | TM_BUNDLE_SUPPORT = ENV('TM_BUNDLE_SUPPORT') -------------------------------------------------------------------------------- /Support/resource/toggle.js: -------------------------------------------------------------------------------- 1 | function set_togglable_visibility(dom_id, state) { 2 | link = $("toggle_link_" + dom_id); 3 | detail_div = $(dom_id) 4 | if (state) { 5 | link.update("-"); 6 | detail_div.show(); 7 | } 8 | else 9 | { 10 | link.update("+"); 11 | detail_div.hide() 12 | } 13 | } 14 | 15 | function toggle_diff(dom_id) { 16 | e = $(dom_id) 17 | if (! e.readAttribute("loaded")) { 18 | e.update(dispatch({controller: 'diff', action: 'diff', revision: e.readAttribute("rev"), git_path: e.readAttribute("git_path"), path: (e.readAttribute("path") || ""), layout: false})) 19 | e.setAttribute("loaded", ""); 20 | } 21 | 22 | set_togglable_visibility( dom_id, ! e.visible() ); 23 | } 24 | 25 | function toggle_log(dom_id) { 26 | e = $(dom_id) 27 | if (! e.readAttribute("loaded")) { 28 | e.update(dispatch({controller: 'log', action: 'log', revisions: e.readAttribute("revisions"), git_path: e.readAttribute("git_path"), path: (e.readAttribute("path") || ""), layout: false})) 29 | // e.setAttribute("loaded"); 30 | } 31 | 32 | set_togglable_visibility( dom_id, ! e.visible() ); 33 | } 34 | -------------------------------------------------------------------------------- /Support/spec/controllers/annotate_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | describe AnnotateController do 3 | include SpecHelpers 4 | 5 | before(:each) do 6 | Git.reset_mock! 7 | end 8 | 9 | describe "when annotating" do 10 | before(:all) do 11 | ENV["TM_SELECTION"] = "1" 12 | Git.command_response["blame", "--abbrev=7", "file.rb"] = fixture_file("blame.txt") 13 | Git.command_response["log", "--date=default", "--format=medium", "--follow", "--name-only", "file.rb"] = fixture_file("log_with_diffs.txt") 14 | @output = capture_output do 15 | dispatch(:controller => "annotate", :file_path => "file.rb") 16 | end 17 | @h = Hpricot(@output) 18 | @log_options = (@h / "select[@name='rev'] / option") 19 | end 20 | 21 | it "should output the log" do 22 | @log_options.first.inner_text.should == "current" 23 | @log_options.length.should == 3 24 | end 25 | 26 | it "should output the annotation" do 27 | @output.should include("Author: Tim Harper") 28 | end 29 | end 30 | end -------------------------------------------------------------------------------- /Support/spec/controllers/config_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe ConfigController do 4 | include SpecHelpers 5 | include Parsers 6 | 7 | before(:each) do 8 | @controller = ConfigController.singleton_new 9 | @git = Git.singleton_new 10 | end 11 | 12 | describe "when setting values" do 13 | it "should default to local" do 14 | @git.config.should_receive(:[]=).with("local", "user.name", "My Name") 15 | capture_output { dispatch(:controller => "config", :action => "set", :key => "user.name", :value => "My Name" )} 16 | end 17 | 18 | it "should allow setting of global variables" do 19 | @git.config.should_receive(:[]=).with("global", "user.name", "My Name") 20 | capture_output { dispatch(:controller => "config", :action => "set", :scope => "global", :key => "user.name", :value => "My Name" )} 21 | end 22 | end 23 | 24 | end -------------------------------------------------------------------------------- /Support/spec/controllers/diff_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe DiffController do 4 | include SpecHelpers 5 | include Parsers 6 | before(:each) do 7 | Git.reset_mock! 8 | @git = Git.singleton_new 9 | end 10 | 11 | describe "uncommitted changes" do 12 | before(:each) do 13 | @git.should_receive(:diff). 14 | with(:path => @git.path, :since => "HEAD" ). 15 | and_return( 16 | parse_diff(fixture_file("changed_files.diff")) 17 | ) 18 | 19 | @git.submodule.stub!(:all).and_return [] 20 | 21 | @output = capture_output do 22 | dispatch(:controller => "diff", :action => "uncommitted_changes") 23 | end 24 | end 25 | 26 | it "should output the diff" do 27 | # puts Git.commands_ran.inspect 28 | # puts @output 29 | @output.should include("Support/lib/formatters/diff.rb") 30 | end 31 | 32 | it "should show a link to open the diff in textmate" do 33 | @output.should include("Open diff in TextMate") 34 | end 35 | 36 | it "should include a javascript include tag for prototype.js" do 37 | @output.should include("prototype.js") 38 | end 39 | end 40 | 41 | describe "diffing submodules" do 42 | before(:each) do 43 | @git.should_receive(:diff). 44 | and_return( 45 | parse_diff(fixture_file("submodules.diff")) 46 | ) 47 | @output = capture_output do 48 | dispatch(:controller => "diff", :action => "diff") 49 | end 50 | end 51 | 52 | it "should report the added submodule" do 53 | @output.should include("Submodule added") 54 | end 55 | 56 | it "should report the deleted submodule" do 57 | @output.should include("Submodule deleted") 58 | end 59 | 60 | it "should report the modified submodule" do 61 | @output.should include("Submodule modified") 62 | end 63 | end 64 | end -------------------------------------------------------------------------------- /Support/spec/controllers/log_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | require CONTROLLERS_ROOT + "/log_controller.rb" 3 | describe LogController do 4 | include SpecHelpers 5 | 6 | before(:each) do 7 | Git.reset_mock! 8 | @git = Git.singleton_new 9 | end 10 | 11 | describe "showing a log" do 12 | before(:each) do 13 | Git.command_response["log", "--date=default", "--format=medium", "-n", Git::Config::DEFAULT_LOG_LIMIT, "."] = fixture_file("log.txt") 14 | @git.branch.stub!(:current).and_return branch_stub(:name => "refs/heads/master") 15 | @output = capture_output do 16 | dispatch :controller => "log", :action => "index", :path => "." 17 | end 18 | end 19 | 20 | it "should include render with a layout" do 21 | @output.should include("") 22 | end 23 | 24 | it "should show a log" do 25 | @output.should include("198fc930") 26 | end 27 | end 28 | 29 | describe "showing outgoing changes" do 30 | before(:each) do 31 | @controller = LogController.singleton_new 32 | @git = Git.singleton_new 33 | 34 | @master = branch_stub(:name => "refs/heads/master", :tracking_status => :behind, :tracking_branch_name => "refs/remotes/origin/master") 35 | @release = branch_stub(:name => "refs/heads/release", :tracking_status => :ahead, :tracking_branch_name => "refs/remotes/origin/release") 36 | @task = branch_stub(:name => "refs/heads/task", :tracking_status => :diverged, :tracking_branch_name => "refs/remotes/origin/task") 37 | end 38 | 39 | it "should show an outgoing log for all diverged or ahead branches" do 40 | @git.branch.stub!(:all).and_return([@master, @release, @task]) 41 | @git.submodule.stub!(:all).and_return([]) 42 | 43 | @controller.should_receive(:render_component).with(:action => "log", :git_path => @git.path, :branches => "refs/remotes/origin/release..refs/heads/release") 44 | @controller.should_receive(:render_component).with(:action => "log", :git_path => @git.path, :branches => "refs/remotes/origin/task..refs/heads/task") 45 | 46 | capture_output do 47 | dispatch :controller => "log", :action => "outgoing" 48 | end 49 | end 50 | 51 | it "should show an outgoing branch log for all submodules" do 52 | @git.branch.stub!(:all).and_return([]) 53 | @submodule = stub("submodule", 54 | :git => stub("git", 55 | :path => "submodule_path", 56 | :branch => stub("branch_command", 57 | :all => [@master, @release, @task] 58 | ) 59 | ) 60 | ) 61 | 62 | @git.submodule.stub!(:all).and_return([@submodule]) 63 | 64 | @controller.should_receive(:render_component).with(:action => "log", :git_path => @submodule.git.path, :branches => "refs/remotes/origin/release..refs/heads/release") 65 | @controller.should_receive(:render_component).with(:action => "log", :git_path => @submodule.git.path, :branches => "refs/remotes/origin/task..refs/heads/task") 66 | 67 | capture_output do 68 | dispatch :controller => "log", :action => "outgoing" 69 | end 70 | end 71 | end 72 | end -------------------------------------------------------------------------------- /Support/spec/controllers/misc_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe MiscController do 4 | include SpecHelpers 5 | 6 | before(:each) do 7 | @git = Git.singleton_new 8 | end 9 | 10 | it "should initialize a repository" do 11 | @git.should_receive(:init) 12 | output = capture_output do 13 | dispatch(:controller => "misc", :action => "init"); 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /Support/spec/controllers/stash_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe Git::Stash do 4 | before(:each) do 5 | Git.reset_mock! 6 | @stash_controller = StashController.new 7 | StashController.stub!(:new).and_return(@stash_controller) 8 | end 9 | 10 | include SpecHelpers 11 | 12 | it "should ask you if you want to add unstashed files" do 13 | flush 14 | TextMate::UI.should_receive(:alert).with(:warning, "Untracked files in working copy", "Would you like to include the following untracked files in your stash?:\nuntracked_file.txt\nother_untracked_file.txt\n", "Add them", "Leave them out", "Cancel").and_return("Add them") 15 | TextMate::UI.should_receive(:request_string).with({:prompt=>"Describe stash:", :default=>"WIP: ", :title=>"Stash"}).and_return("WIP") 16 | 17 | Git.command_response["ls-files", "-o", "--exclude-per-directory=.gitignore"] = "untracked_file.txt\nother_untracked_file.txt\n" 18 | Git.command_response["stash", "save", "WIP"] = <<-EOF 19 | Saved "mybranch: WIP... msg" 20 | HEAD is now at 7bba918... msg 21 | EOF 22 | output = capture_output do 23 | dispatch(:controller => "stash", :action => "save") 24 | end 25 | 26 | output.should include("Saved \"mybranch: WIP") 27 | Git.commands_ran.should include(["add", "."]) 28 | end 29 | 30 | 31 | describe "when applying a stash" do 32 | before(:each) do 33 | @stash_controller.stub!(:select_stash).and_return({:description=>" On master: boogy", :name=>"stash@{0}", :id=>0}) 34 | Git.command_response["stash", "list"] = fixture_file("stash_list_response_many_stashes.txt") 35 | Git.command_response["stash", "pop", "stash@{0}"] = fixture_file("status_output.txt") 36 | Git.command_response["stash", "show", "-p", "stash@{0}"] = fixture_file("changed_files.diff") 37 | @output = capture_output do 38 | dispatch(:controller => "stash", :action => "pop") 39 | end 40 | 41 | @h = Hpricot(@output) 42 | end 43 | 44 | it "should show the project status" do 45 | (@h / "table#status_output / tr").length.should == 6 46 | @output.should include("app/views/layouts/application.html.erb") 47 | end 48 | 49 | it "should show a diff of the stash applied" do 50 | (@h / "table.codediff").length.should == 2 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /Support/spec/controllers/submodule_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe SubmoduleController do 4 | include SpecHelpers 5 | include Parsers 6 | 7 | before(:each) do 8 | @git = Git.singleton_new 9 | @controller = SubmoduleController.singleton_new 10 | 11 | @module_repo_path = "git@server:/path/to/my-module.git" 12 | @module_name = "my-module" 13 | end 14 | 15 | # TextMate::UI.should_receive(:request_string).with( 16 | # :title => "Add submodule", :prompt => "Enter the submodule clone URL" 17 | # ).and_return(@module_repo_path) 18 | 19 | # TextMate::UI.should_receive(:request_directory).with( 20 | # "Select the parent folder for the submodule:", :initial_directory => @git.path 21 | # ).and_return("/base/") 22 | 23 | it "should extract an intelligent default" do 24 | TextMate::UI.should_receive(:request_string).with( 25 | :title => "What do you want to call the module (will be the folder name)?", :default => "my-module" 26 | ).and_return(@module_name) 27 | @controller.send(:prompt_module_name, @module_repo_path) 28 | end 29 | 30 | it "should add a repository and output the results of the add / initialize" do 31 | @controller.should_receive(:prompt_repository_path).and_return(@module_repo_path) 32 | @controller.should_receive(:prompt_parent_folder).and_return(@git.path) 33 | @controller.should_receive(:prompt_module_name).and_return(@module_name) 34 | 35 | @git.submodule.should_receive(:add).with(@module_repo_path, File.join("/base/", @module_name)).and_return(StringIO.new("Added!")) 36 | @git.submodule.should_receive(:init_and_update).and_return("Initialized!") 37 | 38 | output = capture_output do 39 | dispatch(:controller => "submodule", :action => "add") 40 | end 41 | 42 | output.should include("Added!") 43 | output.should include("Initialized!") 44 | # puts "
#{output}
" 45 | end 46 | end -------------------------------------------------------------------------------- /Support/spec/controllers/tag_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe TagController do 4 | include SpecHelpers 5 | include Parsers 6 | 7 | before(:each) do 8 | @controller = TagController.singleton_new 9 | @git = Git.singleton_new 10 | end 11 | 12 | it "should allow you to abort" do 13 | @controller.should_receive(:prompt_tag_name).and_return(false) 14 | capture_output { dispatch :controller => "tag", :action => "create" }.should include("Aborted") 15 | end 16 | 17 | it "should not push the tag if prompt_want_to_push_remote returns false" do 18 | @controller.should_receive(:prompt_tag_name).and_return("mytab") 19 | @git.should_receive(:create_tag).and_return(true) 20 | @controller.should_receive(:prompt_want_to_push_remote).and_return(false) 21 | @controller.should_not_receive(:render_component) 22 | 23 | capture_output { dispatch :controller => "tag", :action => "create" } 24 | end 25 | end -------------------------------------------------------------------------------- /Support/spec/fixtures/changed_files.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Support/lib/commands/diff.rb b/Support/lib/commands/diff.rb 2 | index 2e44996..3820608 100644 3 | --- a/Support/lib/commands/diff.rb 4 | +++ b/Support/lib/commands/diff.rb 5 | @@ -5,6 +5,25 @@ class SCM::Git::Diff 6 | base = File.expand_path("..", git_dir(file)) if base.nil? 7 | Dir.chdir(base) 8 | file = '.' if file == base 9 | - command("diff", file.sub(/^#{Regexp.escape base}\//, '')) 10 | + parse_diff(command("diff", file.sub(/^#{Regexp.escape base}\//, ''))) 11 | + end 12 | + 13 | + def parse_diff(output) 14 | + output.split("\n").each do |line| 15 | + css_class = case line 16 | + when /^(diff |index |@@|\+\+\+|\-\-\-)/ 17 | + "info" 18 | + when /^\+/ 19 | + "addition" 20 | + when /^\-/ 21 | + "deletion" 22 | + when /^diff / 23 | + "diff_cmd" 24 | + else 25 | + "" 26 | + end 27 | + puts "
#{htmlize(line)}
" 28 | + end 29 | + 30 | end 31 | end 32 | \ No newline at end of file 33 | diff --git a/Support/lib/formatters/diff.rb b/Support/lib/formatters/diff.rb 34 | index b0faae6..2ac2101 100644 35 | --- a/Support/lib/formatters/diff.rb 36 | +++ b/Support/lib/formatters/diff.rb 37 | @@ -30,21 +30,6 @@ class Formatters::Diff 38 | 39 | def content(diff_result) 40 | puts '' 41 | - diff_result.split("\n").each do |line| 42 | - css_class = case line 43 | - when /^(diff |index |@@|\+\+\+|\-\-\-)/ 44 | - "info" 45 | - when /^\+/ 46 | - "addition" 47 | - when /^\-/ 48 | - "deletion" 49 | - when /^diff / 50 | - "diff_cmd" 51 | - else 52 | - "" 53 | - end 54 | - puts "
#{htmlize(line)}
" 55 | - end 56 | 57 | puts '
' 58 | end -------------------------------------------------------------------------------- /Support/spec/fixtures/commit_result.txt: -------------------------------------------------------------------------------- 1 | Created commit 24ff719: work done 2 | 1 files changed, 1 insertions(+), 0 deletions(-) 3 | -------------------------------------------------------------------------------- /Support/spec/fixtures/config_listing.txt: -------------------------------------------------------------------------------- 1 | alias.co=checkout 2 | alias.b=branch 3 | branch.autosetupmerge=true 4 | user.email=timcharper@email.com 5 | user.name=Tim Harper 6 | gui.matchtrackingbranch=true 7 | core.repositoryformatversion=0 8 | core.filemode=true 9 | core.bare=false 10 | core.logallrefupdates=true 11 | remote.origin.url=../origin/ 12 | remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* 13 | branch.master.merge=refs/heads/master 14 | remote.satellite.url=../satellite 15 | remote.satellite.fetch=+refs/heads/*:refs/remotes/satellite/* 16 | branch.satellite.remote=satellite 17 | branch.satellite.merge=refs/heads/satellite 18 | branch.mybranch.remote=satellite 19 | branch.mybranch.merge=refs/heads/mybranch 20 | -------------------------------------------------------------------------------- /Support/spec/fixtures/conflict.txt: -------------------------------------------------------------------------------- 1 | class Coso 2 | include Something 3 | 4 | <<<<<<< HEAD:app/models/conflicted.rb 5 | def self.method 6 | @value ||= "boogy" 7 | end 8 | 9 | ======= 10 | cattr_accessor :method 11 | >>>>>>> master:app/models/conflicted.rb 12 | 13 | end -------------------------------------------------------------------------------- /Support/spec/fixtures/fetch_1_5_4_3_output.txt: -------------------------------------------------------------------------------- 1 | remote: Counting objects: 5, done. 2 | remote: Compressing objects: 33% (1/3)  remote: Compressing objects: 66% (2/3)  remote: Compressing objects: 100% (3/3)  remote: Compressing objects: 100% (3/3), done. 3 | remote: Total 3 (delta 2), reused 0 (delta 0) 4 | From ../satellite 5 | 74c0fdf..d1c6bdd asdf -> satellite/asdf 6 | -------------------------------------------------------------------------------- /Support/spec/fixtures/log.txt: -------------------------------------------------------------------------------- 1 | commit 2762e1264c439dced7f05eacd33fc56499b8b779 2 | Author: Tim Harper 3 | Date: Mon Feb 4 07:51:25 2008 -0700 4 | 5 | bugfix - diff was not parsing the index line sometimes because it varies on deleted files 6 | 7 | made more failproof 8 | 9 | commit d31fffa9df961f057019d9845c5984a264d3d574 10 | Author: Tim Harper 11 | Date: Mon Feb 4 07:44:08 2008 -0700 12 | 13 | diff-rendering of if there is a new-line at the end of a file or not. 14 | 15 | commit bd481e454a9639e8fe554aacdff91154709e11cd 16 | Author: Tim Harper 17 | Date: Mon Feb 4 07:31:18 2008 -0700 18 | 19 | Diff mode: 20 | now with "cut" visuals, links to files. Compare branches now uses the sexy diff mode. 21 | 22 | commit 198fc930b5b1aaa93ba29a9535a768b5c120ea49 23 | Author: Tim Harper 24 | Date: Mon Feb 4 06:45:47 2008 -0700 25 | 26 | new style for diff implemented. diff returns parsed data, which is then passed to the formatter. 27 | 28 | commit 2aedd4e30f077a6712ede1f1bd328e812839913f 29 | Author: Tim Harper 30 | Date: Mon Feb 4 04:51:39 2008 -0700 31 | 32 | Broke out diff command into it's own class, and seperated the view code into a new Formatters::Diff object 33 | 34 | -------------------------------------------------------------------------------- /Support/spec/fixtures/new_line_at_end.diff: -------------------------------------------------------------------------------- 1 | diff --git a/hey hey.rb b/hey hey.rb 2 | index 477c371..19dbd58 100644 3 | --- a/hey hey.rb 4 | +++ b/hey hey.rb 5 | @@ -10,5 +10,4 @@ asdf 6 | 7 | asdf 8 | 9 | - 10 | -asdf 11 | \ No newline at end of file 12 | +boogy! 13 | -------------------------------------------------------------------------------- /Support/spec/fixtures/pull_1_5_4_3_output.txt: -------------------------------------------------------------------------------- 1 | remote: Counting objects: 8, done. 2 | remote: Compressing objects: 16% (1/6) 3 | remote: Compressing objects: 33% (2/6) 4 | remote: Compressing objects: 50% (3/6) 5 | remote: Compressing objects: 66% (4/6) 6 | remote: Compressing objects: 83% (5/6) 7 | remote: Compressing objects: 100% (6/6) 8 | remote: Compressing objects: 1 0remote: 0% (6/6), done. 9 | remote: Total 6 (delta 4), reused 0 (delta 0) 10 | From ../satellite 11 | dc29d3d..05f9ad9 asdf -> satellite/asdf 12 | 791a587..4bfc230 master -> satellite/master 13 | Updating 791a587..4bfc230 14 | Fast forward 15 | project.txt | 12 ++++++++++++ 16 | 1 files changed, 12 insertions(+), 0 deletions(-) 17 | -------------------------------------------------------------------------------- /Support/spec/fixtures/push_1_5_4_3_output.txt: -------------------------------------------------------------------------------- 1 | Counting objects: 5, done. 2 | Compressing objects: 50% (1/2) Compressing objects: 100% (2/2) Compressing objects: 100% (2/2), done. 3 | Writing objects: 33% (1/3) Writing objects: 66% (2/3) Writing objects: 100% (3/3) Writing objects: 100% (3/3), 268 bytes, done. 4 | Total 3 (delta 1), reused 0 (delta 0) 5 | To ../satellite/ 6 | 865f920..f9ca10d asdf -> asdf 7 | ! [rejected] master -> master (non-fast forward) 8 | error: failed to push some refs to '../satellite/' 9 | -------------------------------------------------------------------------------- /Support/spec/fixtures/small.diff: -------------------------------------------------------------------------------- 1 | diff --git a/project.txt b/project.txt 2 | index ea4f9ca..b1b35ce 100644 3 | --- a/project.txt 4 | +++ b/project.txt 5 | @@ -1 +1,3 @@ 6 | -\\ 7 | \ No newline at end of file 8 | +\\ 9 | + 10 | +asdf 11 | \ No newline at end of file 12 | -------------------------------------------------------------------------------- /Support/spec/fixtures/stash_list_response_many_stashes.txt: -------------------------------------------------------------------------------- 1 | stash@{0}: On master: boogy 2 | stash@{1}: On master: oogity 3 | -------------------------------------------------------------------------------- /Support/spec/fixtures/status_output.txt: -------------------------------------------------------------------------------- 1 | A new_file_and_added.txt 2 | R lib/formatters/commit/layout.html.erb -> app/views/layouts/application.html.erb 3 | M project.txt 4 | D small.diff 5 | ?? dir/ 6 | ?? directory.txt 7 | -------------------------------------------------------------------------------- /Support/spec/fixtures/submodules.diff: -------------------------------------------------------------------------------- 1 | diff --git a/vendor/plugins/module1 b/vendor/plugins/module1 2 | new file mode 160000 3 | index 0000000..db01d91 4 | --- /dev/null 5 | +++ b/vendor/plugins/module1 6 | @@ -0,0 +1 @@ 7 | +Subproject commit db01d91c2039ca271c7df9bcc4cacf7e949d74c2 8 | diff --git a/vendor/plugins/railswhere b/vendor/plugins/railswhere 9 | deleted file mode 160000 10 | index b9276ab..0000000 11 | --- a/vendor/plugins/railswhere 12 | +++ /dev/null 13 | @@ -1 +0,0 @@ 14 | -Subproject commit b9276ab1ad9aee7c3688b365072fe0a616b68b71 15 | diff --git a/vendor/plugins/manage_fixtures b/vendor/plugins/manage_fixtures 16 | index 8379713..30f3d85 160000 17 | --- a/vendor/plugins/manage_fixtures 18 | +++ b/vendor/plugins/manage_fixtures 19 | @@ -1 +1 @@ 20 | -Subproject commit 837971332a4e914a1ae3e5defd0f1d00883232df 21 | +Subproject commit 30f3d850901500b52fa70ba1aa31a8f9b9a3d3f6 22 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/annotate_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe SCM::Git do 4 | before(:each) do 5 | @annotate = Git.new 6 | end 7 | include SpecHelpers 8 | 9 | describe "when parsing a annotate" do 10 | before(:each) do 11 | @lines = @annotate.parse_annotation(File.read("#{FIXTURES_DIR}/annotate.txt")) 12 | end 13 | 14 | it "should parse out all items" do 15 | @lines.should have(428).entries 16 | end 17 | 18 | it "should parse out the author, msg, and revision" do 19 | line = @lines.first 20 | line[:rev].should == "26e2d189" 21 | line[:filepath].should be_nil 22 | line[:author].should == "Tim Harper" 23 | line[:date].should == Time.parse("2008-03-02 00:24:40 -0700") 24 | line[:text].should == 'require LIB_ROOT + "/parsers.rb"' 25 | end 26 | end 27 | 28 | describe "when parsing a annotate with a RENAMED file" do 29 | before(:each) do 30 | @lines = @annotate.parse_annotation(File.read("#{FIXTURES_DIR}/annotate_renamed.txt")) 31 | end 32 | 33 | it "should parse out all items" do 34 | @lines.should have(428).entries 35 | end 36 | 37 | it "should parse out the author, msg, and revision" do 38 | line = @lines.first 39 | line[:rev].should == "26e2d189" 40 | line[:filepath].should == "Support/lib/git.rb" 41 | line[:author].should == "Tim Harper" 42 | line[:date].should == Time.parse("2008-03-02 00:24:40 -0700") 43 | line[:text].should == 'require LIB_ROOT + "/parsers.rb"' 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/commit_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe Git do 4 | before(:each) do 5 | @commit = Git.new 6 | Git.reset_mock! 7 | end 8 | include SpecHelpers 9 | 10 | it "should parse a commit" do 11 | Git.command_output << <<-EOF 12 | Created commit ff4ba93: some message 13 | 1 files changed, 2 insertions(+), 0 deletions(-) 14 | Unrecognized line 15 | EOF 16 | # @commit.should_receive(:command).and_return(commit_output) 17 | 18 | result = @commit.commit("some message") 19 | result[:rev].should == "ff4ba93" 20 | result[:message].should == "some message" 21 | result[:insertions].should == 2 22 | result[:deletions].should == 0 23 | result[:files_changed].should == 1 24 | result[:output].should == "Unrecognized line\n" 25 | end 26 | end -------------------------------------------------------------------------------- /Support/spec/lib/commands/config_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe SCM::Git do 4 | before(:each) do 5 | @git = SCM::Git.new 6 | Git.reset_mock! 7 | end 8 | 9 | it "should let git decide when local/global not specified" do 10 | Git.command_response["config", "remote.origin.url"] = "../origin" 11 | value = @git.config["remote.origin.url"] 12 | Git.commands_ran.first.should == ["config", "remote.origin.url"] 13 | value.should == "../origin" 14 | end 15 | 16 | it "should default to local when writing" do 17 | Git.command_response["config", "remote.origin.url", "../origin"] = "" 18 | @git.config["remote.origin.url"] = "../origin" 19 | Git.commands_ran.first.should == ["config", "remote.origin.url", "../origin"] 20 | end 21 | 22 | it "should allow reading of local values" do 23 | Git.command_response["config", "--file", "/base/.git/config", "remote.origin.url"] = "../origin" 24 | value = @git.config[:local, "remote.origin.url"] 25 | Git.commands_ran.first.should == ["config", "--file", "/base/.git/config", "remote.origin.url"] 26 | value.should == "../origin" 27 | end 28 | 29 | it "should allow writing of local values" do 30 | Git.command_response["config", "--file", "/base/.git/config", "remote.origin.url", "../origin"] = "" 31 | @git.config[:local, "remote.origin.url"] = "../origin" 32 | Git.commands_ran.first.should == ["config", "--file", "/base/.git/config", "remote.origin.url", "../origin"] 33 | end 34 | 35 | it "should delete local values when assigning nil" do 36 | @git.config[:local, "git-tmbundle.log.limit"] = nil 37 | Git.commands_ran.first.should == ["config", "--file", "/base/.git/config", "--unset", "git-tmbundle.log.limit"] 38 | end 39 | 40 | it "should allow reading global values" do 41 | Git.command_response["config", "--global", "remote.origin.url"] = "../origin" 42 | value = @git.config[:global, "remote.origin.url"] 43 | Git.commands_ran.first.should == ["config", "--global", "remote.origin.url"] 44 | value.should == "../origin" 45 | end 46 | 47 | it "should raise when given a scope it doesn't understand" do 48 | lambda { @git.config[:boogy, "remote.origin.url"] }.should raise_error("I don't understand the scope :boogy") 49 | end 50 | 51 | it "should respond to the string version of global as well as the symbol" do 52 | Git.command_response["config", "--global", "remote.origin.url"] = "../origin" 53 | @git.config[:global, "remote.origin.url"].should == "../origin" 54 | @git.config["global", "remote.origin.url"].should == "../origin" 55 | end 56 | 57 | it "should allow writing global values" do 58 | Git.command_response["config", "--global", "remote.origin.url", "../origin"] = "" 59 | @git.config[:global, "remote.origin.url"] = "../origin" 60 | Git.commands_ran.first.should == ["config", "--global", "remote.origin.url", "../origin"] 61 | end 62 | 63 | it "should return nil on blank, non-existing value" do 64 | Git.command_output << "" 65 | @git.config["remote.origin.url"].should be_nil 66 | end 67 | end -------------------------------------------------------------------------------- /Support/spec/lib/commands/diff_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe Git do 4 | before(:each) do 5 | @diff = Git.new 6 | end 7 | include SpecHelpers 8 | describe "when parsing a diff" do 9 | before(:each) do 10 | @results = @diff.parse_diff(fixture_file("changed_files.diff")) 11 | @lines = @results.first[:lines] 12 | end 13 | 14 | it "should create an entry for each file" do 15 | @results.should have(2).results 16 | @results.map{|r| r[:left][:file_path]}.should == ["Support/lib/commands/diff.rb", "Support/lib/formatters/diff.rb"] 17 | @results.map{|r| r[:right][:file_path]}.should == ["Support/lib/commands/diff.rb", "Support/lib/formatters/diff.rb"] 18 | end 19 | 20 | it "should parse the line_numbers for the files" do 21 | @lines.map{|l| l[:ln_left]}.should == 22 | (5..7).to_a + 23 | [8] + 24 | ([nil] * 20) + 25 | (9..10).to_a + 26 | ["EOF"] 27 | 28 | @lines.map{|r| r[:ln_right]}.should == 29 | (5..7).to_a + 30 | [nil] + 31 | (8..27).to_a + 32 | (28..29).to_a + 33 | ["EOF"] 34 | end 35 | 36 | it "shouldn't count the (\\ No newline at end of file) line" do 37 | @lines.last[:text].should == "No newline at end of file" 38 | @lines.last[:ln_right].should == "EOF" 39 | @lines.last[:ln_left].should == "EOF" 40 | end 41 | 42 | it "should parse the file mode" do 43 | @results.first[:mode].should == "100644" 44 | end 45 | end 46 | 47 | describe "when parse a diff with line breaks" do 48 | before(:each) do 49 | @results = @diff.parse_diff(fixture_file("changed_files_with_break.diff")) 50 | @lines = @results.first[:lines] 51 | end 52 | 53 | it "should insert a line break" do 54 | @lines.map{|t| t[:type]}.should include(:cut) 55 | end 56 | end 57 | describe "when parse a diff with line breaks" do 58 | before(:each) do 59 | @results = @diff.parse_diff(fixture_file("new_line_at_end.diff")) 60 | @lines = @results.first[:lines] 61 | end 62 | 63 | it "should show EOF as occuring for the side that previously had line-numbers" do 64 | eof_line = @lines.find{|l| l[:type]==:eof} 65 | eof_line[:ln_left].should == "EOF" 66 | eof_line[:ln_right].should == nil 67 | end 68 | end 69 | 70 | describe "when parsing small diff" do 71 | before(:each) do 72 | @results = @diff.parse_diff(fixture_file("small.diff")) 73 | @lines = @results.first[:lines] 74 | end 75 | 76 | it "should start with line-number-zero" do 77 | @lines.map{|l| l[:ln_left]}.should == [1, "EOF", nil, nil, nil, nil] 78 | @lines.map{|l| l[:ln_right]}.should == [nil, nil, 1, 2, 3, "EOF"] 79 | end 80 | end 81 | 82 | describe "parsing new and deleted files" do 83 | before(:each) do 84 | @results = @diff.parse_diff(fixture_file("submodules.diff")) 85 | end 86 | 87 | it "should be status :new for new files" do 88 | @results[0][:status].should == :new 89 | end 90 | 91 | it "should pick up the mode from the 'new file mode 160000' line" do 92 | @results[0][:mode].should == "160000" 93 | end 94 | 95 | it "should be status :deleted for deleted files" do 96 | @results[1][:status].should == :deleted 97 | end 98 | 99 | it "should pick up the mode from the 'deleted file mode 160000' line" do 100 | @results[1][:mode].should == "160000" 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/log_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe Git do 4 | before(:each) do 5 | @git = Git.new 6 | end 7 | include SpecHelpers 8 | 9 | describe "when parsing a plain log" do 10 | before(:each) do 11 | @entries = @git.parse_log( fixture_file('log.txt')) 12 | end 13 | 14 | it "should parse out all items" do 15 | @entries.should have(5).entries 16 | end 17 | 18 | it "should parse out the author, msg, and revision" do 19 | result = @entries.first 20 | result[:rev].should == "2762e1264c439dced7f05eacd33fc56499b8b779" 21 | result[:author].should == "Tim Harper " 22 | result[:date].should == Time.parse("Mon Feb 4 07:51:25 2008 -0700") 23 | result[:msg].should == %Q{bugfix - diff was not parsing the index line sometimes because it varies on deleted files 24 | 25 | made more failproof} 26 | end 27 | end 28 | 29 | describe "when parsing a log with diffs" do 30 | before(:each) do 31 | @entries = @git.parse_log( fixture_file("log_with_diffs.txt")) 32 | @entry = @entries.first 33 | end 34 | 35 | it "should extract and parse diffs" do 36 | @entry[:diff].should_not be_nil 37 | @entry_diff = @entry[:diff].first 38 | @entry_diff[:left][:file_path].should == "Commands/Browse Annotated File (blame).tmCommand" 39 | @entry_diff[:right][:file_path].should == "Commands/Browse Annotated File (blame).tmCommand" 40 | @entry_diff[:lines].length.should == 19 41 | end 42 | end 43 | 44 | end 45 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/merge_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe Git do 4 | before(:each) do 5 | @merge = Git.new 6 | end 7 | 8 | include SpecHelpers 9 | 10 | it "should extract conflicts from a merge" do 11 | result = @merge.parse_merge(<<-EOF) 12 | Auto-merged project.txt 13 | CONFLICT (content): Merge conflict in project.txt 14 | Auto-merged dude.txt 15 | CONFLICT (add/add): Merge conflict in dude.txt 16 | CONFLICT (delete/modify): lib/file.rb deleted in HEAD and modified in release. Version release of lib/file.rb left in tree. 17 | Auto-merged spec/fixtures/events.yml 18 | CONFLICT (delete/modify): coso.txt deleted in release and modified in HEAD. Version HEAD of coso.txt left in tree. 19 | Automatic merge failed; fix conflicts and then commit the result. 20 | Automatic merge failed; fix conflicts and then commit the result. 21 | EOF 22 | # puts result.inspect 23 | result[:conflicts].should == ["project.txt", "dude.txt", "lib/file.rb", "coso.txt"] 24 | end 25 | end -------------------------------------------------------------------------------- /Support/spec/lib/commands/pull_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | require 'stringio' 4 | 5 | describe Git do 6 | include SpecHelpers 7 | 8 | before(:each) do 9 | @pull = Git.new 10 | Git.reset_mock! 11 | Git.command_response["branch"] = "* master\n task" 12 | end 13 | 14 | describe "push from git 1.5.3.4" do 15 | before(:each) do 16 | @process_io = StringIO.new <<-EOF 17 | Unpacking 6 objects... 18 | 16% (1/6) done\r 33% (2/6) done\r 50% (3/6) done\r 66% (4/6) done\r 83% (5/6) done\r 100% (6/6) done\n 19 | * refs/remotes/origin/master: fast forward to branch 'master' of /Users/timcharper/projects/origin 20 | old..new: a58264f..89e8f37 21 | * refs/remotes/origin/mybranch: storing branch 'mybranch' of /Users/timcharper/projects/origin 22 | commit: d8b3683 23 | You asked me to pull without telling me which branch you 24 | want to merge with, and 'branch.asdf.merge' in 25 | your configuration file does not tell me either. Please 26 | name which branch you want to merge on the command line and 27 | try again (e.g. 'git pull '). 28 | See git-pull(1) for details on the refspec. 29 | 30 | If you often merge with the same branch, you may want to 31 | configure the following variables in your configuration 32 | file: 33 | EOF 34 | end 35 | 36 | it "should call the status proc 6 times" do 37 | started_count = {} 38 | finished = {} 39 | output = {"Unpacking" => [] } 40 | @pull.process_pull(@process_io, 41 | :start => lambda { |state, count| started_count[state] = count }, 42 | :progress => lambda {|state, percent, index, count| output[state] << [percent, index, count]}, 43 | :end => lambda { |state, count| finished[state] = true } 44 | ) 45 | 46 | for state in ["Unpacking"] 47 | started_count[state].should == 6 48 | output[state].map{|o| o[0]}.should == [0,16,33,50,66,83,100] 49 | output[state].map{|o| o[1]}.should == (0..6).to_a 50 | output[state].map{|o| o[2]}.should == [6] * 7 51 | finished[state].should == true 52 | end 53 | end 54 | 55 | it "should return a list of all revisions pulled" do 56 | output = @pull.process_pull(@process_io) 57 | output[:pulls].should == { 58 | "refs/remotes/origin/master" => ["a58264f", "89e8f37"], 59 | "refs/remotes/origin/mybranch" => ["d8b3683^", "d8b3683"] 60 | } 61 | end 62 | 63 | it "should return :nothing_to_pull if Everything up-to-date" do 64 | output = @pull.process_pull(StringIO.new("Already up-to-date.\n")) 65 | output[:nothing_to_pull].should == true 66 | end 67 | end 68 | 69 | describe "for git 1.5.4.3" do 70 | before(:each) do 71 | @process_io = StringIO.new(fixture_file("pull_1_5_4_3_output.txt")) 72 | end 73 | 74 | it "should call the progress proc 6 times for state Compressing" do 75 | output = {"Compressing" => [] } 76 | 77 | @pull.process_pull(@process_io, :progress => lambda {|state, percent, index, count| output[state] << [percent, index, count]}) 78 | output["Compressing"].map{|o| o[0]}.should == [16,33,50,66,83,100] 79 | output["Compressing"].map{|o| o[1]}.should == (1..6).to_a 80 | output["Compressing"].map{|o| o[2]}.should == [6] * 6 81 | end 82 | 83 | it "should extract the pull information for the branch and assume the current branch" do 84 | output = @pull.process_pull(@process_io) 85 | output[:pulls]['asdf'].should == ["dc29d3d", "05f9ad9"] 86 | output[:pulls]['master'].should == ["791a587", "4bfc230"] 87 | 88 | end 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/push_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | require 'stringio' 4 | 5 | describe Git do 6 | include SpecHelpers 7 | 8 | before(:each) do 9 | @push = Git.new 10 | @push.version = "1.5.3" 11 | end 12 | 13 | describe "standard push" do 14 | before(:each) do 15 | @process_io = StringIO.new <<-EOF 16 | updating 'refs/heads/mybranch' 17 | from f0f27c95b7cdf4ca3b56ecb3c54ef3364133eb6a 18 | to d8b368361ebdf2c51b78f7cfdae5c3044b23d189 19 | Also local refs/remotes/satellite/mybranch 20 | updating 'refs/heads/satellite' 21 | from 60a254470cd97af3668ed4d6405633af850139c6 22 | to 746fba2424e6b94570fc395c472805625ab2ed25 23 | Also local refs/remotes/satellite/satellite 24 | Generating pack... 25 | Done counting 6 objects. 26 | Deltifying 6 objects... 27 | 16% (1/6) done\r 33% (2/6) done\r 50% (3/6) done\r 66% (4/6) done\r 83% (5/6) def done(args) 28 | 29 | end 30 | \r 100% (6/6) done\n 31 | Writing 6 objects... 32 | 16% (1/6) done\r 33% (2/6) done\r 50% (3/6) done\r 66% (4/6) done\r 83% (5/6) done\r 100% (6/6) done\n 33 | Total 6 (delta 1), reused 0 (delta 0) 34 | refs/heads/satellite: 60a254470cd97af3668ed4d6405633af850139c6 -> 746fba2424e6b94570fc395c472805625ab2ed25 35 | refs/heads/mybranch: f0f27c95b7cdf4ca3b56ecb3c54ef3364133eb6a -> d8b368361ebdf2c51b78f7cfdae5c3044b23d189 36 | EOF 37 | end 38 | 39 | it "should call the status proc 6 times" do 40 | started_count = {} 41 | finished = {} 42 | output = {"Deltifying" => [], "Writing" => [] } 43 | @push.process_push(@process_io, 44 | :start => lambda { |state, count| started_count[state] = count }, 45 | :progress => lambda {|state, percent, index, count| state; output[state] << [percent, index, count]}, 46 | :end => lambda { |state, count| finished[state] = true } 47 | ) 48 | 49 | for state in ["Deltifying", "Writing"] 50 | started_count[state].should == 6 51 | output[state].map{|o| o[0]}.should == [0,16,33,50,66,83,100] 52 | output[state].map{|o| o[1]}.should == (0..6).to_a 53 | output[state].map{|o| o[2]}.should == [6] * 7 54 | finished[state].should == true 55 | end 56 | end 57 | 58 | it "should return a list of all revisions pushed" do 59 | output = @push.process_push(@process_io) 60 | output[:pushes].should == { 61 | "refs/heads/satellite" => ["60a254470cd97af3668ed4d6405633af850139c6", "746fba2424e6b94570fc395c472805625ab2ed25"], 62 | "refs/heads/mybranch" => ["f0f27c95b7cdf4ca3b56ecb3c54ef3364133eb6a", "d8b368361ebdf2c51b78f7cfdae5c3044b23d189"] 63 | } 64 | end 65 | 66 | it "should return :nothing_to_push if Everything up-to-date" do 67 | output = @push.process_push(StringIO.new("Everything up-to-date\n")) 68 | output[:nothing_to_push].should == true 69 | end 70 | end 71 | 72 | describe "for git 1.5.4.3" do 73 | before(:each) do 74 | @process_io = StringIO.new(fixture_file("push_1_5_4_3_output.txt")) 75 | @push.version = "1.5.4.3" 76 | end 77 | 78 | it "should call the progress proc 6 times for state Compressing" do 79 | output = {"Compressing" => [], "Writing" => [] } 80 | 81 | @push.process_push(@process_io, :progress => lambda {|state, percent, index, count| output[state] << [percent, index, count]}) 82 | output["Compressing"].map{|o| o[0]}.should == [50,100] 83 | output["Compressing"].map{|o| o[1]}.should == [1,2] 84 | output["Compressing"].map{|o| o[2]}.should == [2,2] 85 | output["Writing"].map{|o| o[0]}.should == [33,66,100] 86 | output["Writing"].map{|o| o[1]}.should == [1,2,3] 87 | output["Writing"].map{|o| o[2]}.should == [3,3,3] 88 | end 89 | 90 | it "should extract the push information for the branch and assume the current branch" do 91 | output = @push.process_push(@process_io) 92 | 93 | output[:pushes]['asdf'].should == ["865f920", "f9ca10d"] 94 | output[:pushes]['master'].should == nil 95 | 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/remote_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe SCM::Git::Remote do 4 | before(:each) do 5 | @git = Git.new 6 | Git.reset_mock! 7 | end 8 | 9 | include SpecHelpers 10 | 11 | it "should return a list of remote names" do 12 | Git.command_response["remote"] = "github\norigin" 13 | @git.remote.names.should == ["github", "origin"] 14 | end 15 | 16 | it "should return an Array of RemoteProxy objects" do 17 | Git.command_response["remote"] = "origin" 18 | remotes = @git.remote.all 19 | remotes.should have(1).item 20 | remotes.first.should be_kind_of(Git::Remote::RemoteProxy) 21 | remotes.first.name.should == "origin" 22 | end 23 | 24 | it "should retrieve a fetch refspec" do 25 | refspec = "+refs/heads/*:refs/remotes/origin/*" 26 | @git.config.should_receive(:[]).with("remote.origin.fetch").and_return("+refs/heads/*:refs/remotes/origin/*") 27 | @git.remote["origin"].fetch_refspec.should == refspec 28 | end 29 | 30 | it "should find the local name for a refspec" do 31 | remote = @git.remote["origin"] 32 | remote.stub!(:fetch_refspec).and_return("+refs/heads/*:refs/remotes/origin/*") 33 | remote.remote_branch_name_for("refs/heads/master").should == "origin/master" 34 | remote.remote_branch_name_for("master").should == "origin/master" 35 | remote.remote_branch_name_for("refs/heads/master", :full).should == "refs/remotes/origin/master" 36 | end 37 | 38 | it "should find the remote refspec prefix" do 39 | remote = @git.remote["origin"] 40 | remote.stub!(:fetch_refspec).and_return("+refs/heads/*:refs/remotes/origin/*") 41 | remote.remote_branch_prefix.should == "refs/remotes/origin/" 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /Support/spec/lib/commands/status_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../spec_helper' 2 | 3 | describe SCM::Git do 4 | before(:each) do 5 | @git = Git.new 6 | Git.command_response["status", "--porcelain"] = fixture_file("status_output.txt") 7 | end 8 | 9 | include SpecHelpers 10 | 11 | it "should return the state of an initial_commit_pending? as false" do 12 | @git.initial_commit_pending?.should == false 13 | end 14 | 15 | it "should return the state of initial_commit_pending? as true when 'git status' reports it as such" do 16 | Git.command_response["status"] = <"?", 81 | "new_file_and_added.txt"=>"A", 82 | "small.diff"=>"D", 83 | "directory.txt"=>"?", 84 | "project.txt"=>"M", 85 | "app/views/layouts/application.html.erb" => "R" 86 | 87 | } 88 | end 89 | 90 | it "should recognize conflict markers" do 91 | @git.file_has_conflict_markers("#{FIXTURES_DIR}/conflict.txt").should == true 92 | @git.file_has_conflict_markers("#{FIXTURES_DIR}/log.txt").should == false 93 | end 94 | end -------------------------------------------------------------------------------- /Support/spec/lib/git_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe SCM::Git do 4 | before(:each) do 5 | @git = SCM::Git.new 6 | Git.reset_mock! 7 | end 8 | 9 | it "should describe a revision, defaulting to use all refs" do 10 | Git.command_response["describe", "--all", "1234"] = "tag-1234\n" 11 | `ls` # set the exit status code to 0 12 | @git.describe("1234").should == "tag-1234" 13 | end 14 | 15 | it "should return the current revision" do 16 | Git.command_response["rev-parse", "HEAD"] = "1234\n" 17 | @git.current_revision.should == "1234" 18 | end 19 | 20 | it "should auto_add_rm files depending on their existence" do 21 | File.stub!(:exist?).with("/base/existing_file.txt").and_return(true) 22 | File.stub!(:exist?).with("/base/deleted_file.txt").and_return(false) 23 | @git.should_receive(:add).with(["existing_file.txt"]).and_return("") 24 | @git.should_receive(:rm).with(["deleted_file.txt"]).and_return("") 25 | @git.auto_add_rm(["existing_file.txt", "deleted_file.txt"]) 26 | end 27 | 28 | describe "using submodule git relative paths" do 29 | before(:each) do 30 | @sub_git = Git.new(:parent => @git, :path => File.join(@git.path, "subproject")); 31 | end 32 | 33 | it "should return absolute paths" do 34 | @sub_git.path_for("file.txt").should == File.join(@git.path, "subproject/file.txt") 35 | end 36 | 37 | it "should return a relative path from the root git" do 38 | @sub_git.root_relative_path_for("file.txt").should == "subproject/file.txt" 39 | end 40 | end 41 | it 42 | 43 | end 44 | -------------------------------------------------------------------------------- /Support/spec/lib/partial_commit_worker_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | require LIB_ROOT + "/partial_commit_worker" 3 | 4 | describe PartialCommitWorker do 5 | include SpecHelpers 6 | before(:each) do 7 | @git = Git.singleton_new 8 | end 9 | 10 | describe "Commit" do 11 | before(:each) do 12 | @commit_worker = PartialCommitWorker::Normal.new(@git) 13 | end 14 | 15 | it "should NOT be OK to proceed when not on a branch but performing an initial commit" do 16 | @git.branch.should_receive(:current_name).and_return(nil) 17 | @git.should_receive(:initial_commit_pending?).and_return(false) 18 | @commit_worker.ok_to_proceed_with_partial_commit?.should == false 19 | end 20 | 21 | it "should be OK to proceed when not on a branch but performing an initial commit" do 22 | @git.branch.should_receive(:current_name).and_return(nil) 23 | @git.should_receive(:initial_commit_pending?).and_return(true) 24 | @commit_worker.ok_to_proceed_with_partial_commit?.should == true 25 | end 26 | 27 | it "should be NOT be OK to process when there are no file candidates" do 28 | @commit_worker = @commit_worker 29 | @commit_worker.stub!(:file_candidates).and_return([]) 30 | @commit_worker.nothing_to_commit?.should == true 31 | end 32 | 33 | it "should NOT send the last commit message to the commit window when committing" do 34 | @git.stub!(:log).and_return([{:msg => "My Message"}]) 35 | @commit_worker.stub!(:file_candidates).and_return([]) 36 | @commit_worker.stub!(:status_helper_tool).and_return("/path/to/status_helper_tool") 37 | @output = @commit_worker.tm_scm_commit_window 38 | @output.should_not include(Shellwords.escape("My Message")) 39 | end 40 | end 41 | 42 | describe "Amend" do 43 | before(:each) do 44 | @commit_worker = PartialCommitWorker::Amend.new(@git) 45 | end 46 | 47 | it "should NOT be OK to proceed when performing an initial commit" do 48 | @git.stub!(:initial_commit_pending?).and_return(true) 49 | @commit_worker.nothing_to_amend?.should == true 50 | end 51 | 52 | it "should be OK to amend the commit if there are no files candiates" do 53 | @commit_worker.stub!(:file_candidates).and_return([]) 54 | @commit_worker.nothing_to_commit?.should == false 55 | end 56 | 57 | it "should send the last commit message to the commit window when amending" do 58 | @git.stub!(:log).and_return([{:msg => "My Message"}]) 59 | @commit_worker.stub!(:file_candidates).and_return([]) 60 | @commit_worker.stub!(:status_helper_tool).and_return("/path/to/status_helper_tool") 61 | @output = @commit_worker.tm_scm_commit_window 62 | @output.should include(Shellwords.escape("My Message")) 63 | end 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /Support/spec/run_all_spec.rb: -------------------------------------------------------------------------------- 1 | Dir.glob(File.dirname(__FILE__) + "/**/*_spec.rb").each do |file| 2 | require file 3 | end -------------------------------------------------------------------------------- /Support/spec/spec.opts: -------------------------------------------------------------------------------- 1 | --color 2 | --reverse 3 | -------------------------------------------------------------------------------- /Support/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | SPEC_ROOT = File.dirname(__FILE__) 2 | FIXTURES_DIR = "#{SPEC_ROOT}/fixtures" 3 | require SPEC_ROOT + '/../environment.rb' 4 | require 'rubygems' 5 | require 'stringio' 6 | require 'hpricot' 7 | require SPEC_ROOT + "/../tmvc/spec/spec_helpers.rb" 8 | require LIB_ROOT + "/ui.rb" 9 | SpecHelpers::PUTS_CAPTURE_CLASSES << ::Git 10 | 11 | describe "Formatter with layout", :shared => true do 12 | before(:each) do 13 | @h = Hpricot(@output) 14 | end 15 | 16 | it "should include a style.css" do 17 | (@h / "link").map{|s| File.basename(s.attributes["href"])}.should include("style.css") 18 | end 19 | 20 | it "should include a prototype.js" do 21 | (@h / "script").map{|s| File.basename(s.attributes["src"].to_s)}.should include("prototype.js") 22 | end 23 | end 24 | 25 | class ArrayKeyedHash < Hash 26 | def []=(*args) 27 | value = args.pop 28 | super(args, value) 29 | end 30 | 31 | def [](*args) 32 | super(args) 33 | end 34 | end 35 | 36 | class Git 37 | alias :initialize_without_autopath :initialize 38 | def initialize(options = {}) 39 | options = options.dup 40 | options[:path] ||= "/base" 41 | initialize_without_autopath(options) 42 | end 43 | 44 | class << self 45 | def reset_mock! 46 | command_response.clear 47 | command_output.clear 48 | commands_ran.clear 49 | end 50 | 51 | def command_response 52 | @@command_response ||= ArrayKeyedHash.new 53 | end 54 | 55 | def command_output 56 | @@command_output ||= [] 57 | end 58 | 59 | def commands_ran 60 | @@commands_ran ||= [] 61 | end 62 | 63 | def stubbed_command(*args) 64 | commands_ran << args 65 | if command_response.empty? 66 | command_output.shift 67 | else 68 | r = command_response[*args] || "" 69 | if r.is_a?(Array) 70 | r.shift 71 | else 72 | r 73 | end 74 | end 75 | end 76 | end 77 | 78 | def command(*args) 79 | Git.stubbed_command(*args) 80 | end 81 | 82 | def popen_command(*args) 83 | StringIO.new(command(*args)) 84 | end 85 | 86 | def git_dir(file_or_dir = paths.first) 87 | "/base/.git" 88 | end 89 | 90 | def paths(*args) 91 | [path] 92 | end 93 | 94 | def nca(*args) 95 | path 96 | end 97 | 98 | attr_writer :version 99 | def version; @version ||= "1.5.4.3"; end 100 | end 101 | 102 | def exit_with_output_status 103 | end 104 | 105 | [:exit_show_html, :exit_discard, :exit_show_tool_tip].each do |exit_method| 106 | Object.send :define_method, exit_method do 107 | $exit_status = Object.const_get(exit_method.to_s.upcase) 108 | end 109 | end 110 | 111 | class Object 112 | def self.singleton_new(*args) 113 | new_obj = new(*args) 114 | self.stub!(:new).and_return(new_obj) 115 | new_obj 116 | end 117 | end 118 | 119 | module TextMate::UI 120 | def self.request_item(options = {}, &block) 121 | yield options[:items].first if block_given? 122 | options[:items].first 123 | end 124 | end -------------------------------------------------------------------------------- /Support/tmvc/lib/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | include HtmlHelpers 3 | end 4 | -------------------------------------------------------------------------------- /Support/tmvc/lib/erb_stdout.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | 3 | class ERBStdout < ERB 4 | def set_eoutvar(compiler, eoutvar = 'STDOUT') 5 | compiler.put_cmd = "#{eoutvar} << " 6 | compiler.insert_cmd = "#{eoutvar} << " if compiler.respond_to?(:insert_cmd) 7 | compiler.pre_cmd = "#{eoutvar}.flush" 8 | compiler.post_cmd = "#{eoutvar}.flush; ''" 9 | 10 | if RUBY_VERSION >= "1.9" 11 | # in Ruby1.9.x, ERB wants pre_cmd/post_cmd wrapped in Array 12 | compiler.pre_cmd = [compiler.pre_cmd] 13 | compiler.post_cmd = [compiler.post_cmd] 14 | end 15 | end 16 | 17 | def run(b=TOPLEVEL_BINDING) 18 | self.result(b) 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- /Support/tmvc/lib/format_helpers/tag_helper.rb: -------------------------------------------------------------------------------- 1 | module FormatHelpers 2 | module TagHelper 3 | # Adapted from RubyOnRails 4 | BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple) 5 | SELF_CLOSABLE_TAGS = %w(img br hr) 6 | def content_tag_string(name, content = nil, options = {}, escape = true, close = true) 7 | if content || ! SELF_CLOSABLE_TAGS.include?(name.to_s) 8 | "#{content_tag_string_open(name, options)}#{content}#{content_tag_string_close(name)}" 9 | else 10 | content_tag_string_open(name, options, true, :self_closing => true) 11 | end 12 | end 13 | 14 | def content_tag_string_open(name, options, escape = true, self_closing = false) 15 | tag_option_string = tag_options(options, escape) if options 16 | "<#{name}#{tag_option_string}#{self_closing ? ' /' : ''}>" 17 | end 18 | 19 | def content_tag_string_close(name) 20 | "" 21 | end 22 | 23 | def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) 24 | if block_given? 25 | options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) 26 | STDOUT << content_tag_string_open(name, options, escape) 27 | yield 28 | STDOUT << content_tag_string_close(name) 29 | else 30 | if content_or_options_with_block.is_a?(Hash) 31 | content = nil 32 | options = content_or_options_with_block 33 | else 34 | content = content_or_options_with_block.to_s 35 | end 36 | content_tag_string(name, content, options, escape) 37 | end 38 | end 39 | 40 | def tag_options(options, escape = true) 41 | unless options.blank? 42 | attrs = [] 43 | if escape 44 | options.each do |key, value| 45 | next unless value 46 | key = key.to_s 47 | value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value) 48 | attrs << %(#{key}="#{value}") 49 | end 50 | else 51 | attrs = options.map { |key, value| %(#{key}="#{value}") } 52 | end 53 | " #{attrs.sort * ' '}" unless attrs.empty? 54 | end 55 | end 56 | 57 | def htmlize_attr(str) 58 | str.to_s.gsub(/&/, "&").gsub(/"/, """).gsub("<", "<").gsub(">", ">") 59 | end 60 | 61 | alias :escape_once :htmlize_attr 62 | 63 | end 64 | end -------------------------------------------------------------------------------- /Support/tmvc/lib/hash.rb: -------------------------------------------------------------------------------- 1 | class Hash 2 | def filter(*keys) 3 | keys.flatten.inject({}) do |new_hash, key| 4 | new_hash[key] = self[key] if self[key] 5 | new_hash 6 | end 7 | end 8 | 9 | def stringify_keys! 10 | keys.each do |k| 11 | if k.is_a?(Symbol) 12 | value = delete(k) 13 | self[k.to_s] = value 14 | end 15 | end 16 | end 17 | 18 | unless method_defined?(:reject_without_params) 19 | alias reject_without_params reject 20 | def reject(*keys, &block) 21 | return reject_without_params(&block) if keys.empty? 22 | reject_without_params { |key,value| keys.include?(key)} 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /Support/tmvc/lib/html_helpers.rb: -------------------------------------------------------------------------------- 1 | module HtmlHelpers 2 | include ERB::Util 3 | 4 | def path_for(default_path, path) 5 | if path.include?("/") 6 | path 7 | else 8 | default_path(path) 9 | end 10 | end 11 | 12 | protected 13 | def resource_url(filename) 14 | "file://" + e_url("#{ENV['TM_BUNDLE_SUPPORT']}/resource/#{filename}") 15 | end 16 | 17 | def select_box(name, select_options = [], options = {}) 18 | options[:name] ||= name 19 | options[:id] ||= name 20 | # puts select_options.inspect 21 | <<-EOF 22 | 25 | EOF 26 | end 27 | 28 | def options_for_select(select_options = [], selected_value = nil) 29 | output = "" 30 | 31 | select_options.each do |name, val, filepath| 32 | selected = (val == selected_value) ? "selected='true'" : "" 33 | output << "" 34 | end 35 | 36 | output 37 | end 38 | 39 | def make_non_breaking(output) 40 | htmlize(output.to_s.strip).gsub(" ", " ") 41 | end 42 | 43 | 44 | def e_js(str) 45 | str.to_s.gsub(/"/, '\"').gsub("\n", '\n') 46 | end 47 | 48 | def javascript_include_tag(*params) 49 | file_names = [] 50 | params = params.map {|p| p.include?(".js") ? p : "#{p}.js"} 51 | params.map do |p| 52 | content_tag :script, "", :type => "text/javascript", :src => resource_url(p) 53 | end * "" 54 | end 55 | 56 | def options_for_javascript(options = {}) 57 | output = options.map { |key, value| "#{key}: " + (value.is_a?(Hash) ? options_for_javascript(value) : "\"#{e_js(value)}\"") } 58 | "{" + (output.sort * ", ") + "}" 59 | end 60 | 61 | def remote_function(options = {}) 62 | case 63 | when options[:update] 64 | "$('#{options[:update]}').update(dispatch(#{options_for_javascript(options[:params])}))" 65 | when target = options[:update_streaming] 66 | other_options = "" 67 | other_options << ", on_complete: function() { #{options[:on_complete]} }" if options[:on_complete] 68 | 69 | "dispatch_streaming('#{target}', {params: #{options_for_javascript(options[:params])}#{other_options}})" 70 | else 71 | "dispatch(#{options_for_javascript(options[:params])})" 72 | end 73 | end 74 | 75 | def link_to_remote(name, options = {}) 76 | link_to_function(name, remote_function(options)) 77 | end 78 | 79 | def link_to_function(name, js, html_options = {}) 80 | content_tag(:a, name, {:href => "javascript:void(0)", :onclick => js}.merge(html_options)) 81 | end 82 | 83 | def button_tag(value, options = {}) 84 | content_tag(:input, {:type => "button", :name => value, :value => value }.merge(options)) 85 | end 86 | 87 | def link_to_textmate(name, file, line = nil) 88 | content_tag(:a, name, :href => "txmt://open?url=file://#{e_url file}&line=#{line}") 89 | end 90 | 91 | def button_to_remote(name, options = {}, html_options = {}) 92 | button_tag(name, {:onclick => remote_function(options)}.merge(html_options)) 93 | end 94 | 95 | def link_to_mate(name, file) 96 | link_to_function(name, "exec('mate', [\"#{e_sh(file)}\"])") 97 | end 98 | 99 | include FormatHelpers::TagHelper 100 | end 101 | 102 | -------------------------------------------------------------------------------- /Support/tmvc/lib/ruby_tm_helpers.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: UTF-8 -*0 2 | # TextMate helpers 3 | # Author: Tim Harper with Lead Media Partners. 4 | # http://code.google.com/p/productivity-bundle/ 5 | 6 | if ENV.has_key? 'TM_SUPPORT_PATH' 7 | require "#{ENV["TM_SUPPORT_PATH"]}/lib/escape" 8 | else 9 | abort(<<-PLAIN.gsub(/^\s{0,4}/, '')) 10 | 11 | \e[31mFail whale detected!\e[0m 12 | 13 | TM_SUPPORT_PATH is not set. This is probably because you are running 14 | specs from outside of TextMate. 15 | 16 | You can set TM_SUPPORT_PATH using something like... 17 | 18 | export TM_SUPPORT_PATH='/Applications/TextMate.app/Contents/SharedSupport/Support' 19 | 20 | PLAIN 21 | end 22 | 23 | public 24 | 25 | EXIT_DISCARD = 200 26 | EXIT_SHOW_HTML = 205 27 | EXIT_SHOW_TOOL_TIP = 206 28 | 29 | def exit_discard 30 | exit 200; 31 | end 32 | 33 | def exit_replace_text 34 | exit 201; 35 | end 36 | 37 | def exit_replace_document 38 | exit 202; 39 | end 40 | 41 | def exit_insert_text 42 | exit 203; 43 | end 44 | 45 | def exit_insert_snippet 46 | exit 204; 47 | end 48 | 49 | def exit_show_html 50 | exit 205 51 | end 52 | 53 | def exit_show_tool_tip 54 | exit 206; 55 | end 56 | 57 | def exit_create_new_document 58 | exit 207; 59 | end 60 | 61 | def flush; $>.flush; STDOUT.flush; end; 62 | 63 | def tm_open(file, options = {}) 64 | line = options[:line] 65 | wait = options[:wait] 66 | if line.nil? && /^(.+):(\d+)$/.match(file) 67 | file = $1 68 | line = $2 69 | end 70 | 71 | unless /^\//.match(file) 72 | file = File.join((ENV['TM_PROJECT_DIRECTORY'] || Dir.pwd), file) 73 | end 74 | 75 | args = [] 76 | args << "-w" if wait 77 | args << e_sh(file) 78 | args << "-l #{line}" if line 79 | %x{"#{ENV['TM_SUPPORT_PATH']}/bin/mate" #{args * " "}} 80 | end 81 | 82 | 83 | # this method only applies when the whole document contents are sent in 84 | def tm_expanded_selection(options = {}) 85 | text=ENV['TM_SELECTED_TEXT'].to_s 86 | return text unless text.empty? 87 | 88 | options = { 89 | :input_type => :doc, 90 | :input => nil, 91 | :forward => /\w*/i, 92 | :backward => /\w*/i, 93 | :line_number => ENV['TM_LINE_NUMBER'].to_i, 94 | :col_number => ENV['TM_COLUMN_NUMBER'].to_i 95 | }.merge(options) 96 | 97 | col_number, line_number = options[:col_number], options[:line_number] 98 | 99 | doc = options[:input] ||= $stdin.read 100 | 101 | line = 102 | case options[:input_type] 103 | when :doc then doc.split("\n")[line_number - 1] 104 | when :line then doc 105 | else 106 | raise "Can't handle input_type #{options[:input_type]} for tm_expanded_selection" 107 | end 108 | 109 | last_part = line[ (col_number - 1)..-1] 110 | first_part = line[ 0..col_number - 2] 111 | 112 | last_part.gsub!(/^(#{options[:forward]}){0,1}.*$/i) { $1 } 113 | 114 | first_part.reverse! 115 | first_part.gsub!(/^(#{options[:backward]}){0,1}.*$/i) { $1 } 116 | first_part.reverse! 117 | first_part + last_part 118 | end 119 | 120 | 121 | 122 | module Enumerable 123 | # TODO remove when 1.9 supports natively 124 | def map_with_index 125 | result = [] 126 | each_with_index do |item, idx| 127 | result << yield(item, idx) 128 | end 129 | result 130 | end 131 | end 132 | 133 | class Object 134 | def blank? 135 | nil? || empty? 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /Support/tmvc/lib/string.rb: -------------------------------------------------------------------------------- 1 | class String 2 | def constantize 3 | Object.module_eval("::" + self) 4 | end 5 | 6 | def underscore 7 | gsub(/(^|\b)[A-Z]/) { |l| l.downcase}.gsub(/[A-Z]/) { |l| "_#{l.downcase}" }.gsub("::", "/") 8 | end 9 | 10 | def classify 11 | gsub(/^[a-z]/) { |l| l.upcase}.gsub(/_[a-z]/) { |l| l[1..1].upcase}.gsub(/\b[a-z]/) {|l| l.upcase}.gsub("/", "::") 12 | end 13 | end -------------------------------------------------------------------------------- /Support/tmvc/spec/hash_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/spec_helper.rb" 2 | 3 | describe Hash do 4 | it "should stringify_keys" do 5 | h = {:author => 1, "date" => 1} 6 | h.stringify_keys! 7 | h.keys.sort.should == ["author", "date"] 8 | end 9 | 10 | it "should filter the keys" do 11 | {:a => 1, :b => 2}.filter(:a).should == {:a => 1} 12 | end 13 | 14 | it "should reject specified keys" do 15 | {:a => 1, :b => 2}.reject(:b).should == {:a => 1} 16 | end 17 | end -------------------------------------------------------------------------------- /Support/tmvc/spec/html_helpers_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/spec_helper.rb" 2 | describe HtmlHelpers do 3 | def resource_url(arg); arg; end 4 | it "should output a javascript_include_tag" do 5 | javascript_include_tag("prototype.js").should == [""] 6 | end 7 | 8 | it "should format options_for_javascript, escaping appropriately" do 9 | options_for_javascript(:controller => "log", :action => "index", :param => 'Grand "old" time').should == %q!{action: "index", controller: "log", param: "Grand \"old\" time"}! 10 | end 11 | 12 | it "should use dispatch_streaming when update_streaming is passed" do 13 | remote_function(:update_streaming => "iframe", :params => {:controller => "submodule", :action => "create"}, :on_complete => "alert('done')").should == 14 | %q(dispatch_streaming('iframe', {params: {action: "create", controller: "submodule"}, on_complete: function() { alert('done') }})) 15 | end 16 | 17 | it "should, when called without an :update parameter, render link_to_remote just using dispatch " do 18 | link_to_remote("link", :params => {:controller => "log", :action => "index", :param => 'Grand "old" time'}).should == 19 | %q(link) 20 | end 21 | 22 | it "should link to javascript" do 23 | link_to_function("click", "alert('Hi!');").should == %q(click) 24 | end 25 | 26 | it "should nest options_for_javascript" do 27 | options_for_javascript({:a => {:b => 1}}).should == "{a: {b: \"1\"}}" 28 | end 29 | 30 | it "should render a button_tag" do 31 | button_tag("Commit", :class => "commit_button").should == %q{} 32 | end 33 | 34 | it "should create a link with a url" do 35 | link_to_textmate("text", "/hello", 10).should == %q{text} 36 | end 37 | 38 | it "should create a button to a remote" do 39 | button_to_remote("Add", :params => {:controller => "log"}).should include("button") 40 | end 41 | end -------------------------------------------------------------------------------- /Support/tmvc/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | SPEC_ROOT = File.dirname(__FILE__) 2 | 3 | require SPEC_ROOT + "/../tmvc.rb" 4 | require SPEC_ROOT + "/spec_helpers.rb" -------------------------------------------------------------------------------- /Support/tmvc/spec/spec_helpers.rb: -------------------------------------------------------------------------------- 1 | module SpecHelpers 2 | PUTS_CAPTURE_CLASSES = [] 3 | def fixture_file(filename) 4 | File.read("#{FIXTURES_DIR}/#{filename}") 5 | end 6 | 7 | def set_constant_forced(klass, constant_name, constant) 8 | klass.class_eval do 9 | remove_const(constant_name) if const_defined?(constant_name) 10 | const_set(constant_name, constant) 11 | end 12 | end 13 | 14 | def capture_output(&block) 15 | old_stdout = Object::STDOUT 16 | io_stream = StringIO.new 17 | begin 18 | set_constant_forced(Object, "STDOUT", io_stream) 19 | PUTS_CAPTURE_CLASSES.each do |klass| 20 | klass.class_eval do 21 | def puts(*args) 22 | args.each{ |arg| Object::STDOUT.puts arg} 23 | end 24 | end 25 | end 26 | yield 27 | ensure 28 | set_constant_forced(Object, "STDOUT", old_stdout) 29 | end 30 | io_stream.rewind 31 | io_stream.read 32 | end 33 | 34 | 35 | def branch_stub(options = {}) 36 | branch = stub("branch", options) 37 | [:name, :tracking_branch_name].each do |key| 38 | next unless options[key] 39 | branch.stub!(key).with(:long).and_return(options[key]) 40 | branch.stub!(key).with().and_return(options[key].gsub(/refs\/(heads|remotes)\//, "")) 41 | end 42 | if options.has_key?(:remote) 43 | branch.stub!(:remote).and_return(stub("remote", :name => options[:remote])) 44 | branch.stub!(:remote_name).and_return(options[:remote]) 45 | end 46 | branch 47 | end 48 | 49 | def stub_current_branch(git, options = {}) 50 | git.branch.stub!(:current).and_return(branch_stub(options)) 51 | git.branch.stub!(:current_name).with(:long).and_return(git.branch.current.name(:long)) 52 | git.branch.stub!(:current_name).with().and_return(git.branch.current.name) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /Support/tmvc/spec/string_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/spec_helper.rb" 2 | describe String do 3 | it "should classify a string with a /" do 4 | "controllers/application_controller".classify.should == "Controllers::ApplicationController" 5 | end 6 | 7 | it "should classify a string" do 8 | "application_controller".classify.should == "ApplicationController" 9 | end 10 | 11 | it "should underscore a string" do 12 | "ApplicationController".underscore.should == "application_controller" 13 | end 14 | 15 | it "should underscore a string with a ::" do 16 | "Controllers::ApplicationController".underscore.should == "controllers/application_controller" 17 | end 18 | 19 | it "should constantize a string" do 20 | "String".constantize.should == String 21 | end 22 | end -------------------------------------------------------------------------------- /Support/tmvc/spec/tag_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/spec_helper.rb" 2 | describe FormatHelpers::TagHelper do 3 | include SpecHelpers 4 | 5 | it "should return a formatted tag in non-block notation" do 6 | content_tag(:script, "", :type => "javascript", :src => "prototype.js").should == "" 7 | end 8 | 9 | it "should output the tag with the block contents in the middle" do 10 | output = capture_output do 11 | content_tag(:p) do 12 | STDOUT << "Content" 13 | end 14 | end 15 | 16 | output.should == "

Content

" 17 | end 18 | end -------------------------------------------------------------------------------- /Support/tmvc/tmvc.rb: -------------------------------------------------------------------------------- 1 | TMVC_ROOT = File.dirname(__FILE__) 2 | 3 | ROOT = TMVC_ROOT + "/.." 4 | CONTROLLERS_ROOT = ROOT + "/app/controllers" 5 | HELPERS_ROOT = ROOT + '/app/helpers' 6 | VIEWS_ROOT = ROOT + "/app/views" 7 | 8 | 9 | %w[string hash erb_stdout ruby_tm_helpers format_helpers/tag_helper html_helpers application_helper application_controller].each do |filename| 10 | require TMVC_ROOT + "/lib/#{filename}.rb" 11 | end 12 | 13 | require(HELPERS_ROOT + "/application_helper.rb") if File.exist?(HELPERS_ROOT + "/application_helper.rb") 14 | 15 | 16 | at_exit { 17 | if $exit_status 18 | exit $exit_status 19 | end 20 | } 21 | 22 | module TMVC 23 | class << self 24 | attr_accessor :catch_exceptions 25 | def dispatch_streaming(params = {}) 26 | require 'socket' 27 | streaming = params.delete(:streaming) 28 | try_count = 0 29 | port = 0 30 | begin 31 | port = 9999 + try_count 32 | server = TCPServer.new('', port) 33 | rescue => e 34 | try_count += 1 35 | retry if try_count < 10 36 | raise "Couldn't find a port!" 37 | end 38 | 39 | pid = fork do 40 | socket = server.accept 41 | Object.send :remove_const, 'STDOUT' 42 | Object.const_set("STDOUT", socket) 43 | dispatch_normal(params) 44 | end 45 | puts "#{port},#{pid}" 46 | flush 47 | end 48 | 49 | def dispatch_normal(params = {}) 50 | # puts "hi" 51 | # return false 52 | begin 53 | raise "must supply a controller to use!" unless controller = params[:controller] 54 | params[:action] ||= "index" 55 | controller_class = "#{controller}_controller".classify.constantize 56 | controller_class.call(params[:action], params) 57 | rescue => e 58 | raise e unless $dont_catch_exceptions 59 | puts htmlize($!) 60 | puts htmlize($!.backtrace) 61 | end 62 | end 63 | 64 | def dispatch(params = {}) 65 | $dispatched = true 66 | params = parse_dispatch_args(ARGV) if params.is_a?(Array) 67 | if debug_mode 68 | require 'logger' 69 | Logger.new(ROOT + "/log/dispatch.log").warn(params.inspect) 70 | end 71 | if params[:streaming] 72 | dispatch_streaming(params) 73 | else 74 | dispatch_normal(params) 75 | end 76 | end 77 | 78 | def parse_dispatch_args(args = []) 79 | params = args.inject({}) do |hash, arg| 80 | parts = arg.scan(/(.+?)=(.+)/m).flatten 81 | next hash if parts.empty? 82 | key = parts.first.to_sym 83 | value = parts.last 84 | hash[key] = value 85 | hash 86 | end 87 | end 88 | end 89 | self.catch_exceptions = true 90 | end 91 | 92 | def debug_mode 93 | return $debug_mode unless $debug_mode.nil? 94 | $debug_mode = File.exist?(File.join(ROOT, "/DEBUG")) 95 | end 96 | def dispatch(params = {}); TMVC.dispatch(params); end -------------------------------------------------------------------------------- /Syntaxes/Git Rebase Message.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | git-rebase-todo 8 | 9 | name 10 | Git Rebase Message 11 | patterns 12 | 13 | 14 | captures 15 | 16 | 1 17 | 18 | name 19 | punctuation.definition.comment.git-rebase 20 | 21 | 22 | match 23 | ^\s*(#).*$\n? 24 | name 25 | comment.line.number-sign.git-rebase 26 | 27 | 28 | captures 29 | 30 | 1 31 | 32 | name 33 | support.function.git-rebase 34 | 35 | 2 36 | 37 | name 38 | constant.sha.git-rebase 39 | 40 | 3 41 | 42 | name 43 | meta.commit-message.git-rebase 44 | 45 | 46 | match 47 | ^\s*(pick|p|reword|r|edit|e|squash|s|fixup|f|drop|d)\s+([0-9a-f]+)\s+(.*)$ 48 | name 49 | meta.commit-command.git-rebase 50 | 51 | 52 | captures 53 | 54 | 1 55 | 56 | name 57 | support.function.git-rebase 58 | 59 | 2 60 | 61 | patterns 62 | 63 | 64 | include 65 | source.shell 66 | 67 | 68 | 69 | 70 | match 71 | ^\s*(exec|x)\s+(.*)$ 72 | name 73 | meta.commit-command.git-rebase 74 | 75 | 76 | captures 77 | 78 | 1 79 | 80 | name 81 | support.function.git-rebase 82 | 83 | 84 | match 85 | ^\s*(break|b)\s*$ 86 | name 87 | meta.commit-command.git-rebase 88 | 89 | 90 | scopeName 91 | text.git-rebase 92 | uuid 93 | 7F1CC209-5F6D-486A-8180-09FA282381A1 94 | 95 | 96 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODO 2 | 3 | This is a road map to experimental branches and what they should do once they're done. 4 | 5 | Anyone's encouraged to add to this list or take an idea and develop in their own clone of the git repository. When they are completed, notify me (timcharper - at - gmail) to get your changes pulled into the next release branch, and guarantee your name's immortality. 6 | 7 | - cherry-picking -- 8 | - pick a SHA ref and merge the commit associated with it from one branch to another 9 | - Would be nice to use the html-log view, and include checkmarks next to each entry. This way, you could browse the log, see the commit message, and check the contents of the commit, making it easier to select which changes you'd like to cherry-pick. 10 | - signing off on commits 11 | - setting up the .gitignore file for a standard rails project 12 | - Rebase command. Have a permanently dismissible dialog to warn Git-newbies about the potential problems of rebasing on a shared repository. 13 | - Centralized branch / tag management page. Have a single, interactive page in textmate where you can switch branches, rebase, merge, diff, log, tag, etc. This will help make the git-menu considerably shorter 14 | - Annotate 15 | - Find a way to clean-up the drop-down (use fixed font, make it a bit smaller, manually truncate the log message so it doesn't get chopped. 16 | - Use "porcelain" format of annotations. Support showing the commit message in the tool-tip hover. 17 | - Follow line numbers when navigating next/previous to assist in tracking a certain piece of code. Have the ability to change the "tracked" line. 18 | - Focus the line number on open dialog 19 | - Show commit message 20 | - Currently, the annotation browser doesn't follow renames (though Git knows about them). It would be nice if the annotation browser was smart enough to figure this out 21 | - It would be nice to be able to change the "current line" in the annotation browser, and have it update as history is navigated (probably would only be possible with next/previous commands). 22 | - Show unpushed changes command 23 | - Show a log of all local commits that have not been pushed to remote branches. 24 | - Make a "branch" management dialog - centralize all branch commands to it. 25 | - Spruce up the stash 26 | - Auto "clear" stash on successful apply 27 | - Central "stash" management page - browse, apply, clear, and create new stash all from one page. 28 | - Choose a stash to delete 29 | - Pull output dialog - make it show the current branch first. Show delimiters to split up sections between branches (
plus margin) 30 | - Log 31 | - ability to search 32 | - Paginate (show more) 33 | - adjust number of context lines (interactively) 34 | - Buttons on every log entry where you can create a tag, branch, or checkout any revision. 35 | --------------------------------------------------------------------------------