├── .ruby-version ├── Rakefile ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── spec ├── spec_helper.rb ├── gf_definition_spec.rb ├── gf_file_spec.rb ├── alternate_spec.rb └── runspec_spec.rb ├── doc └── angular.txt ├── README.md └── plugin └── angular.vim /.ruby-version: -------------------------------------------------------------------------------- 1 | 1.9.3-p194 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | 3 | RSpec::Core::RakeTask.new 4 | 5 | task :default => :spec 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | before_install: sudo apt-get install vim-gtk 5 | before_script: 6 | - "export DISPLAY=:99.0" 7 | - "sh -e /etc/init.d/xvfb start" 8 | 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | group :test do 4 | gem 'rake', '0.9.2.2' 5 | gem 'rspec' 6 | gem 'vimrunner' # http://mudge.name/2012/04/18/testing-vim-plugins-on-travis-ci-with-rspec-and-vimrunner.html 7 | end 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | diff-lcs (1.2.5) 5 | rake (0.9.2.2) 6 | rspec (2.14.1) 7 | rspec-core (~> 2.14.0) 8 | rspec-expectations (~> 2.14.0) 9 | rspec-mocks (~> 2.14.0) 10 | rspec-core (2.14.8) 11 | rspec-expectations (2.14.5) 12 | diff-lcs (>= 1.1.3, < 2.0) 13 | rspec-mocks (2.14.6) 14 | vimrunner (0.3.1) 15 | 16 | PLATFORMS 17 | ruby 18 | 19 | DEPENDENCIES 20 | rake (= 0.9.2.2) 21 | rspec 22 | vimrunner 23 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'vimrunner' 2 | require 'vimrunner/rspec' 3 | 4 | Vimrunner::RSpec.configure do |config| 5 | config.reuse_server = true 6 | 7 | config.start_vim do 8 | vim = Vimrunner.start#_gvim 9 | plugin_path = File.expand_path('../..', __FILE__) 10 | #vim.prepend_runtimepath(plugin_path) # so the ftplugin behavior takes effect 11 | vim.add_plugin(plugin_path, 'plugin/angular.vim') 12 | vim 13 | end 14 | 15 | # takes a filename argument like app/js/blah.js and 16 | # creates the directory structure if it doesn't already exist 17 | def safe_write_file(filename) 18 | dirname = File.dirname(filename) 19 | if !File.directory?(dirname) 20 | FileUtils.mkdir_p dirname 21 | end 22 | write_file(filename, "") 23 | end 24 | 25 | def current_file_name 26 | vim.echo 'bufname("%")' 27 | end 28 | 29 | # takes any number of filenames as arguments and creates each as an empty file 30 | def setup_filesystem(*args) 31 | args.each do |filename| 32 | safe_write_file(filename) 33 | end 34 | end 35 | 36 | def assume_vimrc(command) 37 | vim.command(command) 38 | end 39 | 40 | def assume_blank_vimrc_by_unsetting_any_global_variables 41 | vim.command('unlet g:angular_source_directory') 42 | vim.command('unlet g:angular_test_directory') 43 | vim.command('unlet g:angular_jasmine_version') 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /spec/gf_definition_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "gf definition" do 4 | 5 | before do 6 | assume_blank_vimrc_by_unsetting_any_global_variables 7 | end 8 | 9 | specify "should be found even though the identifier does not include the js suffix that is obviously in the filename" do 10 | setup_filesystem('app/js/poo.js') 11 | find_definition('poo') 12 | current_file_name.should eq "./app/js/poo.js" 13 | end 14 | 15 | specify "should be found when the identifier has a camelcasedName" do 16 | setup_filesystem('app/js/piles-of-poo.js') 17 | find_definition('pilesOfPoo') 18 | current_file_name.should eq "./app/js/piles-of-poo.js" 19 | end 20 | 21 | specify "should be found when the identifier has a TitlecasedName" do 22 | setup_filesystem('app/js/piles-of-poo.js') 23 | find_definition('PilesOfPoo') 24 | current_file_name.should eq "./app/js/piles-of-poo.js" 25 | end 26 | 27 | specify "should be found when the filename-is-dasherized" do 28 | setup_filesystem('app/js/piles-of-poo.js') 29 | find_definition('pilesOfPoo') 30 | current_file_name.should eq "./app/js/piles-of-poo.js" 31 | end 32 | 33 | specify "should be found when the filenameIsCamelcased" do 34 | setup_filesystem('app/js/pilesOfPoo.js') 35 | find_definition('pilesOfPoo') 36 | current_file_name.should eq "./app/js/pilesOfPoo.js" 37 | end 38 | 39 | specify "should be found when the FilenameIsTitlecased" do 40 | setup_filesystem('app/js/PilesOfPoo.js') 41 | find_definition('PilesOfPoo') 42 | current_file_name.should eq "./app/js/PilesOfPoo.js" 43 | end 44 | 45 | specify "should be a champ about avoiding full stops" do 46 | setup_filesystem('app/js/piles-of-poo.js') 47 | find_definition('PilesOfPoo.keepingStinking()') 48 | current_file_name.should eq "./app/js/piles-of-poo.js" 49 | end 50 | 51 | specify "should find partial matches at the end i guess" do 52 | setup_filesystem('app/js/piles-of-poo.js') 53 | find_definition('poo') 54 | current_file_name.should eq "./app/js/piles-of-poo.js" 55 | end 56 | 57 | private 58 | 59 | def find_definition(string_to_find_by) 60 | write_file('starting-file.js', <<-EOF) 61 | #{string_to_find_by} 62 | EOF 63 | 64 | vim.edit 'starting-file.js' 65 | current_file_name.should eq "starting-file.js" 66 | vim.command 'AngularGoToFile' 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /spec/gf_file_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "gf file" do 4 | 5 | specify "default behavior for directive" do 6 | html_file_at('my-customer.html') 7 | do_gf_from_directive_that_references!('my-customer.html') 8 | current_file_name.should eq "my-customer.html" 9 | end 10 | 11 | specify "default behavior for view" do 12 | html_file_at('my-customer.html') 13 | do_gf_from_view_that_references!('my-customer.html') 14 | current_file_name.should eq "my-customer.html" 15 | end 16 | 17 | specify "when html in app/templates and directive references full path" do 18 | html_file_at('app/templates/my-customer.html') 19 | do_gf_from_directive_that_references!('app/templates/my-customer.html') 20 | current_file_name.should eq "app/templates/my-customer.html" 21 | end 22 | 23 | specify "when html in app/templates and directive references path minus app" do 24 | html_file_at('app/templates/my-customer.html') 25 | do_gf_from_directive_that_references!('templates/my-customer.html') 26 | current_file_name.should eq "app/templates/my-customer.html" 27 | end 28 | 29 | specify "when html in app/templates and view references path minus app" do 30 | html_file_at('app/templates/my-customer.html') 31 | do_gf_from_view_that_references!('templates/my-customer.html') 32 | current_file_name.should eq "app/templates/my-customer.html" 33 | end 34 | 35 | specify "when html in app/views and view references path minus app" do 36 | html_file_at('app/views/my-customer.html') 37 | do_gf_from_view_that_references!('views/my-customer.html') 38 | current_file_name.should eq "app/views/my-customer.html" 39 | end 40 | 41 | specify "when html in app subdirectory and directive references path minus app" do 42 | html_file_at('app/my-customer.html') 43 | do_gf_from_directive_that_references!('my-customer.html') 44 | current_file_name.should eq "app/my-customer.html" 45 | end 46 | 47 | specify "when html in random unsupported subdirectory that directive is not referencing" do 48 | html_file_at('wut/my-customer.html') 49 | do_gf_from_directive_that_references!('my-customer.html') 50 | current_file_name.should eq "directive.js" 51 | end 52 | 53 | specify "the gelus use case from github issue #4" do 54 | html_file_at('partials/widgets/clustering-widget.html') 55 | do_gf_from_directive_that_references!('partials/widgets/clustering-widget.html', 'clustering') 56 | current_file_name.should eq "partials/widgets/clustering-widget.html" 57 | end 58 | 59 | private 60 | 61 | def html_file_at(filename) 62 | safe_write_file(filename) 63 | end 64 | 65 | def do_gf(starting_file, starting_file_contents, search_term = default_search_term) 66 | write_file(starting_file, starting_file_contents) 67 | 68 | vim.edit starting_file 69 | current_file_name.should eq starting_file 70 | vim.normal "/#{search_term}" 71 | # vim.normal 'gf' # does not pick up some aspect of setting up this mapping in the autocmd 72 | vim.command 'AngularGoToFile' 73 | end 74 | 75 | def default_search_term 76 | 'my-cust' 77 | end 78 | 79 | def do_gf_from_directive_that_references!(template_url, search_term = default_search_term) 80 | starting_file = 'directive.js' 81 | 82 | directive_file_contents = <<-EOF 83 | angular.module('docsTemplateUrlDirective', []) 84 | .controller('Controller', ['$scope', function($scope) { 85 | $scope.customer = { 86 | name: 'Naomi', 87 | address: '1600 Amphitheatre' 88 | }; 89 | }]) 90 | .directive('myCustomer', function() { 91 | return { 92 | templateUrl: '#{template_url}' 93 | }; 94 | }); 95 | EOF 96 | 97 | do_gf(starting_file, directive_file_contents, search_term) 98 | end 99 | 100 | def do_gf_from_view_that_references!(template_url) 101 | starting_file = 'hot.html' 102 | 103 | do_gf(starting_file, <<-EOF) 104 |
107 |
4 | License: Same terms as Vim itself (see |license|) 5 | 6 | This plugin is only available if 'compatible' is not set. 7 | 8 | *angular* 9 | There are separate javascript, html, and css runtime files, as well as lots of 10 | other nice plugins that you may want to consider using if you're doing angular 11 | development. See the README at https://github.com/burnettk/vim-angular for a 12 | nice list. 13 | 14 | NAVIGATING *angular-navigating* 15 | 16 | Get around efficiently in an angular project. 17 | 18 | *angular-gf* 19 | gf Bolsters the original gf by also sending you to the 20 | file under the cursor if the file has an implicit 21 | "app" subdirectory prefix (a common grunt config). If 22 | the word under the cursor is a service/directive/etc, 23 | go to the file where it is defined. For example, if 24 | your cursor is on BlahService, it will take you to 25 | blah-service.js. 26 | 27 | *angular-:A* 28 | :A In a test file, edit the implementation, and vice 29 | versa. It basically looks for a corresponding file in 30 | a directory that looks like it might include tests or 31 | app code, respectively. If this doesn't work, it is 32 | quite likely because the angular directory structure 33 | convention you're using is not conventional enough. 34 | That's ok; you can tell angular.vim where your source 35 | and test directories are located with 36 | g:angular_source_directory and 37 | g:angular_test_directory. You can disable this 38 | functionality by doing this before the plugin loads: 39 | let g:angular_skip_alternate_mappings = 1 40 | 41 | *angular-:AS* 42 | :AS Like :A, but in a split. 43 | 44 | *angular-:AV* 45 | :AV Like :A, but in a vertical split. 46 | 47 | *angular-:AT* 48 | :AT Like :A, but in a tab. 49 | 50 | RUNNING A SPEC *angular-run-spec* 51 | 52 | It doesn't actually run the spec, but it sure as hell looks like it does if you 53 | have a karma watch going. Wut, you don't use karma watch? Dude! 54 | 55 | *angular-:AngularRunSpec* 56 | :AngularRunSpec Updates the spec where your cursor is sitting from 57 | "it" to "fit" (the f stands for focus) and writes the 58 | file. Why? Jasmine notices that you have a fit spec, 59 | and, when you run your test suite, it will only run 60 | that one spec. If the spec is already "focused" (with 61 | "fit"), running this command will toggle it back to 62 | "it." All of this is much more effective if you have 63 | karma watching your files and running your tests 64 | automatically when you save files. If you are using 65 | jasmine 1, you need to specify iit instead of fit, 66 | so set g:angular_jasmine_version = 1 in your .vimrc. 67 | 68 | *angular-:AngularRunSpecBlock* 69 | :AngularRunSpecBlock Perform the same dance as :AngularRunSpec but using the 70 | describe block in which the cursor is sitting, 71 | effectively running all specs inside the describe block. 72 | 73 | ABOUT *angular-about* 74 | 75 | Grab the latest version or report a bug on GitHub: 76 | 77 | https://github.com/burnettk/vim-angular 78 | 79 | vim:tw=78:et:ft=help:norl: 80 | -------------------------------------------------------------------------------- /spec/alternate_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "alternate" do 4 | 5 | before do 6 | assume_blank_vimrc_by_unsetting_any_global_variables 7 | end 8 | 9 | # g:angular_skip_alternate_mappings is used at angular.vim load 10 | # time, so it's not as simple as this to test it. 11 | # specify "should allow user to disable alternates" do 12 | # assume_vimrc('let g:angular_skip_alternate_mappings = "true"') 13 | # file_a = 'app/src/poo.js' 14 | # file_b = 'test/unit/poo.js' 15 | # setup_filesystem(file_a, file_b) 16 | # vim.edit file_a 17 | # vim.command 'A' 18 | # current_file_name.should eq file_a 19 | # end 20 | 21 | specify "pairs that should work" do 22 | should_alternate_between('app/src/poo.js', 'test/unit/poo.js') 23 | should_alternate_between('app/src/poo.js', 'test/unit/poo.spec.js') 24 | should_alternate_between('app/src/poo.js', 'test/unit/pooSpec.js') 25 | 26 | should_alternate_between('app/src/poo.js', 'test/spec/poo.js') 27 | should_alternate_between('app/src/poo.js', 'test/spec/poo.spec.js') 28 | should_alternate_between('app/src/poo.js', 'test/spec/pooSpec.js') 29 | 30 | should_alternate_between('app/js/poo.js', 'test/unit/poo.js') 31 | should_alternate_between('app/js/poo.js', 'test/unit/poo.spec.js') 32 | should_alternate_between('app/js/poo.js', 'test/unit/pooSpec.js') 33 | 34 | should_alternate_between('app/js/poo.js', 'test/spec/poo.js') 35 | should_alternate_between('app/js/poo.js', 'test/spec/poo.spec.js') 36 | should_alternate_between('app/js/poo.js', 'test/spec/pooSpec.js') 37 | 38 | should_alternate_between('app/foo/foo.controller.js', 'app/foo/test/foo.controller.spec.js') 39 | should_alternate_between('app/bar/bar.service.js', 'app/bar/test/bar.service.spec.js') 40 | 41 | should_alternate_between('app/scripts/controllers/poo.js', 'test/spec/controllers/poo.js') # yoeman 42 | should_alternate_between('public/js/controllers/piles.js', 'test/karma/unit/controllers/piles.spec.js') # mean framework 43 | should_alternate_between('frontend/src/poo.js', 'tests/frontend/poo.spec.js') # Pull Request 6 supporting nkoehring's convention 44 | 45 | should_alternate_between('app/components/pane/pane-directive.js', 'app/components/pane/pane-directive_test.js') # "Best Practice Recommendations for Angular App Structure" convention 46 | end 47 | 48 | specify "pairs that should work when src directory is configured by user" do 49 | assume_vimrc 'let g:angular_source_directory = "WebContent/js"' 50 | 51 | should_alternate_between('WebContent/js/poo.js', 'test/unit/poo.js') 52 | should_alternate_between('WebContent/js/poo.js', 'test/unit/poo.spec.js') 53 | should_alternate_between('WebContent/js/poo.js', 'test/unit/pooSpec.js') 54 | 55 | should_alternate_between('WebContent/js/poo.js', 'test/spec/poo.js') 56 | should_alternate_between('WebContent/js/poo.js', 'test/spec/poo.spec.js') 57 | should_alternate_between('WebContent/js/poo.js', 'test/spec/pooSpec.js') 58 | end 59 | 60 | specify "with multiple src directories configured by user" do 61 | assume_vimrc 'let g:angular_source_directory = ["WebContent/js", "app/src"]' 62 | 63 | should_alternate_between('WebContent/js/poo.js', 'test/unit/poo.js') 64 | should_alternate_between('app/src/poo.js', 'test/unit/pooSpec.js') 65 | end 66 | 67 | specify "pairs that should work when one test directory is configured by user" do 68 | assume_vimrc 'let g:angular_test_directory = "test/units"' 69 | 70 | should_alternate_between('app/js/poo.js', 'test/units/poo.js') 71 | should_alternate_between('app/js/poo.js', 'test/units/poo.spec.js') 72 | should_alternate_between('app/js/poo.js', 'test/units/pooSpec.js') 73 | 74 | should_alternate_between('app/src/poo.js', 'test/units/poo.js') 75 | should_alternate_between('app/src/poo.js', 'test/units/poo.spec.js') 76 | should_alternate_between('app/src/poo.js', 'test/units/pooSpec.js') 77 | end 78 | 79 | specify "with multiple test directories configured by user" do 80 | assume_vimrc 'let g:angular_test_directory = ["test/unit", "test/spec"]' 81 | 82 | should_alternate_between('app/js/poo.js', 'test/unit/poo.js') 83 | should_alternate_between('app/src/poo.js', 'test/spec/pooSpec.js') 84 | end 85 | 86 | # https://github.com/burnettk/vim-angular/issues/22 87 | specify "pairs that should work when source and test directories configured by user" do 88 | assume_vimrc 'let g:angular_source_directory = "app/assets/javascripts/angular"' 89 | assume_vimrc 'let g:angular_test_directory = "spec/javascripts/angular"' 90 | 91 | should_alternate_between('app/assets/javascripts/angular/foos/index.controller.js', 'spec/javascripts/angular/foos/index.controller.spec.js') 92 | 93 | # coffee currently not supported. pull requests welcome. 94 | # should_alternate_between('app/assets/javascripts/angular/foos/index.controller.js.coffee', 'spec/javascripts/angular/foos/index.controller.spec.js.coffee') 95 | end 96 | 97 | specify "pairs should not all work" do 98 | file_a = 'app/junk/poo.js' 99 | file_b = 'test/unit/poo.js' 100 | setup_filesystem(file_a, file_b) 101 | vim.edit file_a 102 | vim.command 'A' 103 | current_file_name.should eq file_a 104 | end 105 | 106 | private 107 | 108 | def should_alternate_from_a_to_b(file_a, file_b) 109 | vim.edit file_a 110 | current_file_name.should eq file_a 111 | vim.command 'A' 112 | current_file_name.should eq file_b 113 | end 114 | 115 | def should_alternate_between(file_a, file_b) 116 | code_path = file_a 117 | test_path = file_b 118 | setup_filesystem(code_path, test_path) 119 | should_alternate_from_a_to_b(code_path, test_path) 120 | should_alternate_from_a_to_b(test_path, code_path) 121 | FileUtils.rm(file_a) 122 | FileUtils.rm(file_b) 123 | end 124 | 125 | end 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular.vim 2 | 3 | [![Build Status](https://travis-ci.org/burnettk/vim-angular.svg)](https://travis-ci.org/burnettk/vim-angular) 4 | 5 | Some niceties for using Vim with the AngularJS framework. See the [screencast][screencast]. 6 | 7 | The [canonical "what editor should I use for Angular?" post][editorchoice] 8 | pretty squarely lands on Webstorm/IntelliJ as the peoples' choice 9 | (12 people), but Vim is right there tied for second place along with 10 | NetBeans and Sublime (four people each as of April, 2014) in this 11 | super-scientific analysis. And don't make me quote [Tim Pope][tpope] on 12 | which editor is forever. 13 | 14 | ## Shoulders of giants 15 | 16 | [The reddit "how do I make vim do angular?" post][reddit] is largely 17 | summarized in the documentation that follows, but as folks pointed out, 18 | Angular is just javascript and html, and vim 19 | does really nicely with these already. These other plugins will 20 | also make your life easier when working with angular projects: 21 | 22 | * [pangloss/vim-javascript][vim-javascript] - "Vastly improved Javascript indentation and syntax support in Vim." 23 | * [othree/javascript-libraries-syntax.vim][javascript-libraries-syntax.vim] - "Syntax for JavaScript libraries," including Angular. This is the hotness you want to autocomplete ng-repeat et al. in your html. 24 | * [matthewsimo/angular-vim-snippets][angular-vim-snippets] - "repo for UltiSnips & Snipmate for angular to be included as a submodule for use in your .vim directory." `ngfor` ftw. The [honza/vim-snippets][vim-snippets] plugin is one library you can use to make this and other library-specific snippets work. 25 | * [claco/jasmine.vim][jasmine.vim] - "Jasmine Plugin for Vim," making your unit testing experience more excellent 26 | * [scrooloose/syntastic.git][syntastic] - "Syntax checking hacks for vim": excellent syntax checking for everything, including javascript and html. Install jshint globally (`npm install -g jshint`) and syntastic will get to work checking your javascript the right way (if your project already has a .jshintrc for use with grunt, it will even use that). 27 | 28 | So why was this plugin written at all? I'm glad you asked! 29 | 30 | ## Features 31 | 32 | ### Switch to test file and vice versa 33 | 34 | :A 35 | 36 | A, the "alternate" file, has been mapped to take you from your code to the 37 | corresponding test file, or from your test file to the corresponding 38 | implementation file. For example, if you're in app/js/rock-socks.js, and 39 | you hammer :A, you will be taken to test/spec/rock-socks.js, if such a file 40 | exists. Some other common directory structure conventions in the angular 41 | community, such as app/src and test/unit, are also supported. 42 | 43 | If the convention you use doesn't work out of the box, you can specify your 44 | source and/or test directory in your .vimrc like this: 45 | 46 | ``` 47 | let g:angular_source_directory = 'app/source' 48 | let g:angular_test_directory = 'test/units' 49 | ``` 50 | 51 | If there is a common convention that you feel should really work out of 52 | the box, feel free to file a pull request to make it work (please 53 | include a test to prove that it works). 54 | 55 | If you don't want to use the alternate functionality, set this before the 56 | plugin loads: 57 | 58 | ``` 59 | let g:angular_skip_alternate_mappings = 1 60 | ``` 61 | 62 | ### Jump to definition of service/directive/controller/etc 63 | 64 | gf 65 | 66 | "Go to file" has been slightly overriden to take you to the definition of 67 | the file under your cursor. If you're reading some code like this... 68 | 69 | ```javascript 70 | if (true) { 71 | AwesomeService.changeStateBecauseMutationIsAwesome(); 72 | } 73 | ``` 74 | 75 | ...and your cursor is on AwesomeService, and you hammer gf, if there is a 76 | file called awesome-service.js somewhere in a subdirectory of your path, 77 | you will be taken there. The default behavior of gf can also be quite 78 | useful in the context of an angular app, since file paths appear in views 79 | (with ng-include src="full/path.html) and directives (with templateUrl: 80 | 'src/myapp/modules/main/views//prompt-list.html', so an 81 | attempt has been made to allow this to work as well. If all that is missing 82 | from a template path is the "app" directory (which is a common value for 83 | "cwd" in `Gruntfile.js`, the plugin will add this for you as well. If either 84 | of these two things don't work for your use case, file a ticket, figure 85 | out why and file a pull request, or [use ctags][ctags]. 86 | 87 | Results can be filtered by specifying exclusions in your .vimrc like this: 88 | 89 | ``` 90 | let g:angular_find_ignore = ['build/', 'dist/'] 91 | ``` 92 | 93 | It does work in at least some cases regardless of whether your filenames are 94 | dasherized (likeABoss or LikeABoss goes to like-a-boss.js), camelcased 95 | (likeABoss.js), or titlecased (LikeABoss.js). 96 | 97 | ### Run the current spec 98 | 99 | If you're writing jasmine unit tests for your angular app, they look like 100 | this: 101 | 102 | ```javascript 103 | it('should work', function() { 104 | var actualThing = 'cow'; 105 | expect(actualThing).toEqual('cow'); 106 | }); 107 | 108 | ``` 109 | 110 | Now, if you take that "it" prefix, and replace it with "fit", instead of 111 | running your entire suite, it will run JUST THAT ONE SPEC. There are 112 | probably bad reasons to want to do this, like if your build is broken 113 | and you want to ignore the failures, but it can be pretty handy to 114 | focus in on just one spec at a time (and one spec generally runs way fast). 115 | 116 | So, if you're anywhere inside a spec: 117 | 118 | :AngularRunSpec 119 | 120 | or the "run spec" mapping: 121 | 122 | rs 123 | 124 | will toggle the spec between "it" and "fit." This works especially well if 125 | you have a karma watch going, as shown in the [screencast][screencast]. 126 | 127 | You are able to do the same with a describe block using the run block command: 128 | 129 | :AngularRunSpecBlock 130 | 131 | or the corresponding mapping: 132 | 133 | rb 134 | 135 | If you're running jasmine 1 instead of jasmine 2, you will need to use iit and 136 | ddescribe instead of fit and fdescribe. To make that happen, tell vim-angular 137 | that you are using jasmine 1 in your .vimrc like this: 138 | 139 | ``` 140 | let g:angular_jasmine_version = 1 141 | ``` 142 | 143 | ### Syntastic syntax checker customization 144 | 145 | You know how you use syntastic to check your syntax as you edit, because 146 | it works for pretty much any language and is awesome? When you use angular 147 | directives (like ng-app, ng-repeat, and even library directives like 148 | ui-view), the html tidy check will complain. This is fixed out of the box. 149 | 150 | Use the same mechanism to make syntastic aware of your own directives by 151 | specifying exclusions in your .vimrc like this: 152 | 153 | ``` 154 | let g:syntastic_html_tidy_ignore_errors = ['proprietary attribute "myhotcompany-'] 155 | ``` 156 | 157 | Some angular directives can also be used as custom elements (i.e. ng-include, 158 | ng-form). These are added to the list of allowed tags by default. In order 159 | to make syntastic recognize your additional blocklevel tags define them in your 160 | .vimrc before the plugin is loaded: 161 | 162 | ``` 163 | let g:syntastic_html_tidy_blocklevel_tags = ['myCustomTag'] 164 | ``` 165 | 166 | 167 | ## Installation 168 | 169 | * Using [Pathogen][pathogen], run the following commands: 170 | 171 | % cd ~/.vim/bundle 172 | % git clone git://github.com/burnettk/vim-angular.git 173 | 174 | * Using [Vundle][vundle], add the following to your `vimrc` and then run 175 | `:PluginInstall` 176 | 177 | Plugin 'burnettk/vim-angular' 178 | 179 | Once help tags have been generated, you can view the manual with 180 | `:help angular`. 181 | 182 | ## Self-Promotion 183 | 184 | Like vim-angular.vim? Follow the repository on [GitHub][project] and vote 185 | for it on [vim.org][vimorgscript]. And if you're feeling especially 186 | charitable, follow [me][mysite] on [Twitter][mytwitter] and 187 | [GitHub][mygithub]. 188 | 189 | ## License 190 | 191 | Copyright (c) Kevin Burnett. Distributed under the same terms as Vim itself. 192 | See `:help license`. 193 | 194 | [editorchoice]: https://groups.google.com/forum/#!topic/angular/MvPSE0Gy1rs 195 | [tpope]: https://github.com/tpope 196 | [reddit]: http://www.reddit.com/r/vim/comments/1q10an/recommended_vim_pluginssetup_for_angular/ 197 | [vim-javascript]: https://github.com/pangloss/vim-javascript 198 | [javascript-libraries-syntax.vim]: https://github.com/othree/javascript-libraries-syntax.vim 199 | [angular-vim-snippets]: https://github.com/matthewsimo/angular-vim-snippets 200 | [vim-snippets]: https://github.com/honza/vim-snippets 201 | [jasmine.vim]: https://github.com/claco/jasmine.vim 202 | [syntastic]: https://github.com/scrooloose/syntastic 203 | [ctags]: http://tbaggery.com/2011/08/08/effortless-ctags-with-git.html 204 | [screencast]: http://youtu.be/-tEaY7HsTn8 205 | [pathogen]: https://github.com/tpope/vim-pathogen 206 | [vundle]: https://github.com/gmarik/vundle 207 | [project]: https://github.com/burnettk/vim-angular 208 | [vimorgscript]: http://www.vim.org/scripts/script.php?script_id=4907 209 | [mysite]: http://notkeepingitreal.com 210 | [mytwitter]: http://twitter.com/kbbkkbbk 211 | [mygithub]: https://github.com/burnettk 212 | -------------------------------------------------------------------------------- /spec/runspec_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "runspec" do 4 | 5 | specify "html tidy syntastic ignores" do 6 | value_of_variable = vim.echo('g:syntastic_html_tidy_ignore_errors') 7 | value_of_variable.should include( 8 | '> proprietary attribute "', 9 | 'trimming empty <' 10 | ) 11 | end 12 | 13 | specify "html tidy syntastic tags" do 14 | value_of_variable = vim.echo('g:syntastic_html_tidy_blocklevel_tags') 15 | value_of_variable.should include( 16 | 'ng-include', 17 | 'ng-form' 18 | ) 19 | end 20 | 21 | describe 'jasmine 1' do 22 | before do 23 | assume_vimrc 'let g:angular_jasmine_version = 1' 24 | end 25 | 26 | specify "command with one spec" do 27 | write_file('test.js', <<-EOF) 28 | it('should work', function() { 29 | var actualThing = 'cow'; 30 | expect(actualThing).toEqual('cow'); 31 | }); 32 | EOF 33 | 34 | vim.edit 'test.js' 35 | vim.command 'AngularRunSpec' 36 | #vim.write # the AngularRunSpec writes the file 37 | 38 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 39 | iit('should work', function() { 40 | var actualThing = 'cow'; 41 | expect(actualThing).toEqual('cow'); 42 | }); 43 | EOF 44 | end 45 | 46 | specify "command with two specs" do 47 | write_file('test.js', <<-EOF) 48 | it('should work', function() { 49 | var actualThing = 'cow'; 50 | expect(actualThing).toEqual('cow'); 51 | }); 52 | 53 | it('should also work', function() { 54 | var actualThing = 'cow'; 55 | expect(actualThing).toEqual('cow'); 56 | }); 57 | EOF 58 | 59 | vim.edit 'test.js' 60 | vim.normal '5j' 61 | vim.command 'AngularRunSpec' 62 | 63 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 64 | it('should work', function() { 65 | var actualThing = 'cow'; 66 | expect(actualThing).toEqual('cow'); 67 | }); 68 | 69 | iit('should also work', function() { 70 | var actualThing = 'cow'; 71 | expect(actualThing).toEqual('cow'); 72 | }); 73 | EOF 74 | end 75 | 76 | specify "command untoggles spec" do 77 | write_file('test.js', <<-EOF) 78 | iit('should work', function() { 79 | var actualThing = 'cow'; 80 | expect(actualThing).toEqual('cow'); 81 | }); 82 | 83 | it('should also work', function() { 84 | var actualThing = 'cow'; 85 | expect(actualThing).toEqual('cow'); 86 | }); 87 | EOF 88 | 89 | vim.edit 'test.js' 90 | vim.command 'AngularRunSpec' 91 | 92 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 93 | it('should work', function() { 94 | var actualThing = 'cow'; 95 | expect(actualThing).toEqual('cow'); 96 | }); 97 | 98 | it('should also work', function() { 99 | var actualThing = 'cow'; 100 | expect(actualThing).toEqual('cow'); 101 | }); 102 | EOF 103 | end 104 | 105 | specify "command grabs focus away from another spec" do 106 | write_file('test.js', <<-EOF) 107 | iit('should work', function() { 108 | var actualThing = 'cow'; 109 | expect(actualThing).toEqual('cow'); 110 | }); 111 | 112 | it('should also work', function() { 113 | var actualThing = 'cow'; 114 | expect(actualThing).toEqual('cow'); 115 | }); 116 | EOF 117 | 118 | vim.edit 'test.js' 119 | vim.normal '5j' 120 | vim.command 'AngularRunSpec' 121 | 122 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 123 | it('should work', function() { 124 | var actualThing = 'cow'; 125 | expect(actualThing).toEqual('cow'); 126 | }); 127 | 128 | iit('should also work', function() { 129 | var actualThing = 'cow'; 130 | expect(actualThing).toEqual('cow'); 131 | }); 132 | EOF 133 | end 134 | 135 | specify "command runs describe block" do 136 | write_file('test.js', <<-EOF) 137 | describe('aThing', function() { 138 | it('should work', function() { 139 | var actualThing = 'cow'; 140 | expect(actualThing).toEqual('cow'); 141 | }); 142 | }); 143 | EOF 144 | 145 | vim.edit 'test.js' 146 | vim.command 'AngularRunSpecBlock' 147 | 148 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 149 | ddescribe('aThing', function() { 150 | it('should work', function() { 151 | var actualThing = 'cow'; 152 | expect(actualThing).toEqual('cow'); 153 | }); 154 | }); 155 | EOF 156 | end 157 | 158 | specify "command to run describe block clears out any focused specs marked iit" do 159 | write_file('test.js', <<-EOF) 160 | describe('aThing', function() { 161 | iit('should work', function() { 162 | var actualThing = 'cow'; 163 | expect(actualThing).toEqual('cow'); 164 | }); 165 | }); 166 | EOF 167 | 168 | vim.edit 'test.js' 169 | vim.command 'AngularRunSpecBlock' 170 | 171 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 172 | ddescribe('aThing', function() { 173 | it('should work', function() { 174 | var actualThing = 'cow'; 175 | expect(actualThing).toEqual('cow'); 176 | }); 177 | }); 178 | EOF 179 | end 180 | 181 | specify "command toggles describe blocks and it specs" do 182 | write_file('test.js', <<-EOF) 183 | ddescribe('aThing', function() { 184 | it('should work', function() { 185 | var actualThing = 'cow'; 186 | expect(actualThing).toEqual('cow'); 187 | }); 188 | }); 189 | EOF 190 | 191 | vim.edit 'test.js' 192 | vim.command 'AngularRunSpecBlock' 193 | 194 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 195 | describe('aThing', function() { 196 | it('should work', function() { 197 | var actualThing = 'cow'; 198 | expect(actualThing).toEqual('cow'); 199 | }); 200 | }); 201 | EOF 202 | end 203 | end 204 | 205 | describe 'jasmine 2' do 206 | before do 207 | assume_blank_vimrc_by_unsetting_any_global_variables 208 | end 209 | 210 | specify "command with one spec" do 211 | write_file('test.js', <<-EOF) 212 | it('should work', function() { 213 | var actualThing = 'cow'; 214 | expect(actualThing).toEqual('cow'); 215 | }); 216 | EOF 217 | 218 | vim.edit 'test.js' 219 | vim.command 'AngularRunSpec' 220 | 221 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 222 | fit('should work', function() { 223 | var actualThing = 'cow'; 224 | expect(actualThing).toEqual('cow'); 225 | }); 226 | EOF 227 | end 228 | 229 | specify "command with two specs" do 230 | write_file('test.js', <<-EOF) 231 | it('should work', function() { 232 | var actualThing = 'cow'; 233 | expect(actualThing).toEqual('cow'); 234 | }); 235 | 236 | it('should also work', function() { 237 | var actualThing = 'cow'; 238 | expect(actualThing).toEqual('cow'); 239 | }); 240 | EOF 241 | 242 | vim.edit 'test.js' 243 | vim.normal '5j' 244 | vim.command 'AngularRunSpec' 245 | 246 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 247 | it('should work', function() { 248 | var actualThing = 'cow'; 249 | expect(actualThing).toEqual('cow'); 250 | }); 251 | 252 | fit('should also work', function() { 253 | var actualThing = 'cow'; 254 | expect(actualThing).toEqual('cow'); 255 | }); 256 | EOF 257 | end 258 | 259 | specify "command untoggles spec" do 260 | write_file('test.js', <<-EOF) 261 | fit('should work', function() { 262 | var actualThing = 'cow'; 263 | expect(actualThing).toEqual('cow'); 264 | }); 265 | 266 | it('should also work', function() { 267 | var actualThing = 'cow'; 268 | expect(actualThing).toEqual('cow'); 269 | }); 270 | EOF 271 | 272 | vim.edit 'test.js' 273 | vim.command 'AngularRunSpec' 274 | 275 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 276 | it('should work', function() { 277 | var actualThing = 'cow'; 278 | expect(actualThing).toEqual('cow'); 279 | }); 280 | 281 | it('should also work', function() { 282 | var actualThing = 'cow'; 283 | expect(actualThing).toEqual('cow'); 284 | }); 285 | EOF 286 | end 287 | 288 | specify "command grabs focus away from another spec" do 289 | write_file('test.js', <<-EOF) 290 | fit('should work', function() { 291 | var actualThing = 'cow'; 292 | expect(actualThing).toEqual('cow'); 293 | }); 294 | 295 | it('should also work', function() { 296 | var actualThing = 'cow'; 297 | expect(actualThing).toEqual('cow'); 298 | }); 299 | EOF 300 | 301 | vim.edit 'test.js' 302 | vim.normal '5j' 303 | vim.command 'AngularRunSpec' 304 | 305 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 306 | it('should work', function() { 307 | var actualThing = 'cow'; 308 | expect(actualThing).toEqual('cow'); 309 | }); 310 | 311 | fit('should also work', function() { 312 | var actualThing = 'cow'; 313 | expect(actualThing).toEqual('cow'); 314 | }); 315 | EOF 316 | end 317 | 318 | specify "command runs describe block" do 319 | write_file('test.js', <<-EOF) 320 | describe('aThing', function() { 321 | it('should work', function() { 322 | var actualThing = 'cow'; 323 | expect(actualThing).toEqual('cow'); 324 | }); 325 | }); 326 | EOF 327 | 328 | vim.edit 'test.js' 329 | vim.command 'AngularRunSpecBlock' 330 | 331 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 332 | fdescribe('aThing', function() { 333 | it('should work', function() { 334 | var actualThing = 'cow'; 335 | expect(actualThing).toEqual('cow'); 336 | }); 337 | }); 338 | EOF 339 | end 340 | 341 | specify "command to run describe block clears out any focused specs marked fit" do 342 | write_file('test.js', <<-EOF) 343 | describe('aThing', function() { 344 | fit('should work', function() { 345 | var actualThing = 'cow'; 346 | expect(actualThing).toEqual('cow'); 347 | }); 348 | }); 349 | EOF 350 | 351 | vim.edit 'test.js' 352 | vim.command 'AngularRunSpecBlock' 353 | 354 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 355 | fdescribe('aThing', function() { 356 | it('should work', function() { 357 | var actualThing = 'cow'; 358 | expect(actualThing).toEqual('cow'); 359 | }); 360 | }); 361 | EOF 362 | end 363 | 364 | specify "command toggles describe blocks and it specs" do 365 | write_file('test.js', <<-EOF) 366 | fdescribe('aThing', function() { 367 | it('should work', function() { 368 | var actualThing = 'cow'; 369 | expect(actualThing).toEqual('cow'); 370 | }); 371 | }); 372 | EOF 373 | 374 | vim.edit 'test.js' 375 | vim.command 'AngularRunSpecBlock' 376 | 377 | IO.read('test.js').strip.should eq normalize_string_indent(<<-EOF) 378 | describe('aThing', function() { 379 | it('should work', function() { 380 | var actualThing = 'cow'; 381 | expect(actualThing).toEqual('cow'); 382 | }); 383 | }); 384 | EOF 385 | end 386 | end 387 | 388 | end 389 | -------------------------------------------------------------------------------- /plugin/angular.vim: -------------------------------------------------------------------------------- 1 | " angular.vim 2 | " Maintainer: Kevin Burnett 3 | " Last Change: 2014 April 6 4 | 5 | 6 | " https://github.com/scrooloose/syntastic/issues/612#issuecomment-19456342 7 | " 8 | " define your own proprietary attributes before this plugin loads, in your 9 | " .vimrc, like so: 10 | " let g:syntastic_html_tidy_ignore_errors = [' proprietary attribute "myhotcompany-'] 11 | " let g:syntastic_html_tidy_blocklevel_tags = ['myCustomTag'] 12 | " 13 | " or copy the mechanism used here to ensure you get both your settings and 14 | " the ones defined by the plugin. 15 | if !exists('g:syntastic_html_tidy_ignore_errors') 16 | let g:syntastic_html_tidy_ignore_errors = [] 17 | endif 18 | 19 | let g:syntastic_html_tidy_ignore_errors += [ 20 | \ '> proprietary attribute "', 21 | \ 'trimming empty <' 22 | \ ] 23 | 24 | if !exists('g:syntastic_html_tidy_blocklevel_tags') 25 | let g:syntastic_html_tidy_blocklevel_tags = [] 26 | endif 27 | 28 | let g:syntastic_html_tidy_blocklevel_tags += [ 29 | \ 'ng-include', 30 | \ 'ng-form' 31 | \ ] 32 | 33 | if !exists('g:angular_find_ignore') 34 | let g:angular_find_ignore = [] 35 | endif 36 | 37 | let g:angular_find_ignore += [ 38 | \ 'coverage/', 39 | \ 'build/', 40 | \ 'dist/', 41 | \ 'test/', 42 | \ '.git/' 43 | \ ] 44 | 45 | " Helper 46 | " Find file in or below current directory and edit it. 47 | function! s:Find(...) abort 48 | let path="." 49 | let query=a:1 50 | 51 | if a:0 == 2 52 | let cmd=a:2 53 | else 54 | let cmd="open" 55 | endif 56 | 57 | 58 | if !exists("g:angular_find_ignore") 59 | let ignore = "" 60 | else 61 | let ignore = " | egrep -v '".join(g:angular_find_ignore, "|")."'" 62 | endif 63 | 64 | let l:command="find ".path." -type f -iname '*".query."*'".ignore 65 | let l:list=system(l:command) 66 | let l:num=strlen(substitute(l:list, "[^\n]", "", "g")) 67 | 68 | if l:num < 1 69 | throw "AngularQueryNotFound" 70 | return 71 | endif 72 | 73 | if l:num == 1 74 | exe cmd . " " . substitute(l:list, "\n", "", "g") 75 | else 76 | let tmpfile = tempname() 77 | exe "redir! > " . tmpfile 78 | silent echon l:list 79 | redir END 80 | let old_efm = &efm 81 | set efm=%f 82 | 83 | if exists(":cgetfile") 84 | execute "silent! cgetfile " . tmpfile 85 | else 86 | execute "silent! cfile " . tmpfile 87 | endif 88 | 89 | let &efm = old_efm 90 | 91 | " Open the quickfix window below the current window 92 | botright copen 93 | 94 | call delete(tmpfile) 95 | endif 96 | endfunction 97 | 98 | 99 | " Helper 100 | " jacked from abolish.vim (was s:snakecase there). thank you, tim pope. 101 | function! s:dashcase(word) abort 102 | let word = substitute(a:word,'::','/','g') 103 | let word = substitute(word,'\(\u\+\)\(\u\l\)','\1_\2','g') 104 | let word = substitute(word,'\(\l\|\d\)\(\u\)','\1_\2','g') 105 | let word = substitute(word,'_','-','g') 106 | let word = tolower(word) 107 | return word 108 | endfunction 109 | 110 | function! s:dashcasewithngtype(word) abort 111 | let word = substitute(a:word,'::','/','g') 112 | let word = substitute(word,'\(\u\+\)\(\u\l\)','\1_\2','g') 113 | let word = substitute(word,'\(\l\|\d\)\(\u\)','\1_\2','g') 114 | let word = substitute(word,'_\([a-zA-Z]\+\)$','.\1','g') 115 | let word = substitute(word,'_','-','g') 116 | let word = tolower(word) 117 | return word 118 | endfunction 119 | 120 | function! s:FindFileBasedOnAngularServiceUnderCursor(cmd) abort 121 | let l:fileundercursor = expand('') 122 | 123 | " Maybe the person actually has the cursor over a file path. 124 | " do more standard gf stuff in that case 125 | if filereadable(l:fileundercursor) 126 | execute "e " . l:fileundercursor 127 | return 128 | endif 129 | 130 | " app is the angular 'public root' conventionally. 131 | " this will help us find things like the template here: 132 | " $routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'}); 133 | if filereadable("app/" . l:fileundercursor) 134 | execute "e " . "app/" . l:fileundercursor 135 | return 136 | endif 137 | 138 | let l:wordundercursor = expand('') 139 | let l:dashcased = s:dashcase(l:wordundercursor) 140 | let l:ngdotcased = s:dashcasewithngtype(l:wordundercursor) 141 | let l:filethatmayexistverbatim = l:wordundercursor . '.js' 142 | let l:filethatmayexistdashcase = l:dashcased . '.js' 143 | let l:filethatmayexistngdotcase = l:ngdotcased . '.js' 144 | 145 | let l:queries = [ 146 | \ l:filethatmayexistverbatim, 147 | \ l:filethatmayexistdashcase, 148 | \ l:filethatmayexistngdotcase 149 | \ ] 150 | 151 | for query in l:queries 152 | try 153 | call Find(query, a:cmd) 154 | break 155 | catch 'AngularQueryNotFound' 156 | if (query == l:filethatmayexistngdotcase) 157 | echo "angular.vim says: '".join(l:queries, ', ')."' not found" 158 | endif 159 | endtry 160 | endfor 161 | endfunction 162 | 163 | function! s:SubStr(originalstring, pattern, replacement) abort 164 | return substitute(a:originalstring, a:pattern, a:replacement, "") 165 | endfunction 166 | 167 | function! s:GenerateTestPaths(currentpath, appbasepath, testbasepath) abort 168 | let l:samefilename = s:SubStr(a:currentpath, a:appbasepath, a:testbasepath) 169 | let l:withcamelcasedspecsuffix = s:SubStr(s:SubStr(a:currentpath, a:appbasepath, a:testbasepath), ".js", "Spec.js") 170 | let l:withdotspecsuffix = s:SubStr(s:SubStr(a:currentpath, a:appbasepath, a:testbasepath), ".js", ".spec.js") 171 | return [l:withdotspecsuffix, l:withcamelcasedspecsuffix, l:samefilename] 172 | endfunction 173 | 174 | function! s:GenerateSrcPaths(currentpath, appbasepath, testbasepath) abort 175 | return [s:SubStr(s:SubStr(a:currentpath, a:testbasepath, a:appbasepath), "Spec.js", ".js"), 176 | \ s:SubStr(s:SubStr(a:currentpath, a:testbasepath, a:appbasepath), ".spec.js", ".js")] 177 | endfunction 178 | 179 | function! s:Alternate(cmd) abort 180 | let l:currentpath = expand('%') 181 | let l:possiblepathsforalternatefile = [] 182 | 183 | for possiblenewpath in [s:SubStr(l:currentpath, ".js", "_test.js"), s:SubStr(l:currentpath, "_test.js", ".js")] 184 | if possiblenewpath != l:currentpath 185 | let l:possiblepathsforalternatefile = l:possiblepathsforalternatefile + [possiblenewpath] 186 | endif 187 | endfor 188 | 189 | " handle a test subdirectory just above the leaf node 190 | let l:possiblenewpath = s:SubStr(l:currentpath, "/test/", "/") 191 | if possiblenewpath != l:currentpath 192 | let l:possiblepathsforalternatefile = l:possiblepathsforalternatefile + [s:SubStr(possiblenewpath, '.spec.js', '.js')] 193 | else 194 | let l:lastslashindex = strridx(l:currentpath, '/') 195 | let l:possibletestpath = strpart(l:currentpath, 0, l:lastslashindex) . '/test' . s:SubStr(strpart(l:currentpath, l:lastslashindex), '.js', '.spec.js') 196 | let l:possiblepathsforalternatefile = l:possiblepathsforalternatefile + [l:possibletestpath] 197 | endif 198 | 199 | if exists('g:angular_source_directory') 200 | if type(g:angular_source_directory) == type([]) 201 | let l:possiblesrcpaths = g:angular_source_directory 202 | else 203 | let l:possiblesrcpaths = [g:angular_source_directory] 204 | endif 205 | else 206 | let l:possiblesrcpaths = ['app/src', 'app/js', 'app/scripts', 'public/js', 'frontend/src'] 207 | endif 208 | 209 | if exists('g:angular_test_directory') 210 | if type(g:angular_test_directory) == type([]) 211 | let l:possibletestpaths = g:angular_test_directory 212 | else 213 | let l:possibletestpaths = [g:angular_test_directory] 214 | endif 215 | else 216 | let l:possibletestpaths = ['test/unit', 'test/spec', 'test/karma/unit', 'tests/frontend'] 217 | endif 218 | 219 | for srcpath in l:possiblesrcpaths 220 | if l:currentpath =~ srcpath 221 | for testpath in l:possibletestpaths 222 | let l:possiblepathsforalternatefile = l:possiblepathsforalternatefile + s:GenerateTestPaths(l:currentpath, srcpath, testpath) 223 | endfor 224 | endif 225 | endfor 226 | 227 | for testpath in l:possibletestpaths 228 | if l:currentpath =~ testpath 229 | for srcpath in l:possiblesrcpaths 230 | let l:possiblepathsforalternatefile = l:possiblepathsforalternatefile + s:GenerateSrcPaths(l:currentpath, srcpath, testpath) 231 | endfor 232 | endif 233 | endfor 234 | 235 | for path in l:possiblepathsforalternatefile 236 | if filereadable(path) 237 | return a:cmd . ' ' . fnameescape(path) 238 | endif 239 | endfor 240 | 241 | return 'echoerr '.string("angular.vim says: Couldn't find alternate file") 242 | endfunction 243 | 244 | 245 | " Helper 246 | " goes to end of line first ($) so it doesn't go the previous 247 | " function if your cursor is sitting right on top of the pattern 248 | function! s:SearchUpForPattern(pattern) abort 249 | execute 'silent normal! ' . '$?' . a:pattern . "\r" 250 | endfunction 251 | 252 | function! s:FirstLetterOf(sourcestring) abort 253 | return strpart(a:sourcestring, 0, 1) 254 | endfunction 255 | 256 | function! s:AngularRunSpecOrBlock(jasminekeyword) abort 257 | " save cursor position so we can go back 258 | let b:angular_pos = getpos('.') 259 | 260 | cal s:SearchUpForPattern(a:jasminekeyword . '(') 261 | 262 | let l:wordundercursor = expand('') 263 | let l:jasmine1 = exists('g:angular_jasmine_version') && g:angular_jasmine_version == 1 264 | if l:jasmine1 265 | let l:additionalletter = s:FirstLetterOf(a:jasminekeyword) 266 | else 267 | let l:additionalletter = 'f' 268 | end 269 | 270 | if l:wordundercursor == a:jasminekeyword 271 | " if there was a spec (anywhere in the file) highlighted with "iit" before, revert it to "it" 272 | let l:positionofspectorun = getpos('.') 273 | 274 | " this can move the cursor, hence setting the cursor back 275 | if l:jasmine1 276 | %s/ddescribe(/describe(/ge 277 | %s/iit(/it(/ge 278 | else 279 | %s/fdescribe(/describe(/ge 280 | %s/fit(/it(/ge 281 | end 282 | 283 | " move cursor back to the spec we want to run 284 | call setpos('.', l:positionofspectorun) 285 | 286 | " either change the current spec to "iit" or 287 | " the current block to "ddescribe" 288 | execute 'silent normal! cw' . l:additionalletter . a:jasminekeyword 289 | elseif l:wordundercursor == l:additionalletter . a:jasminekeyword 290 | " either delete the first i in "iit" or 291 | " the first d in "ddescribe" 292 | execute 'silent normal! hx' 293 | endif 294 | 295 | update " write the file if modified 296 | 297 | " Reset cursor to previous position. 298 | call setpos('.', b:angular_pos) 299 | endfunction 300 | 301 | function! s:AngularRunSpecBlock() abort 302 | cal s:AngularRunSpecOrBlock('describe') 303 | endfunction 304 | 305 | function! s:AngularRunSpec() abort 306 | cal s:AngularRunSpecOrBlock('it') 307 | endfunction 308 | 309 | 310 | nnoremap AngularGfJump :exe FindFileBasedOnAngularServiceUnderCursor('open') 311 | nnoremap AngularGfSplit :exe FindFileBasedOnAngularServiceUnderCursor('split') 312 | nnoremap AngularGfTabjump :exe FindFileBasedOnAngularServiceUnderCursor('tabedit') 313 | 314 | augroup angular_gf 315 | autocmd! 316 | autocmd FileType javascript,html command! -buffer AngularGoToFile :call s:FindFileBasedOnAngularServiceUnderCursor('open') 317 | autocmd FileType javascript,html nmap gf AngularGfJump 318 | autocmd FileType javascript,html nmap f AngularGfSplit 319 | autocmd FileType javascript,html nmap AngularGfSplit 320 | autocmd FileType javascript,html nmap gf AngularGfTabjump 321 | augroup END 322 | 323 | if !exists('g:angular_skip_alternate_mappings') 324 | augroup angular_alternate 325 | autocmd! 326 | autocmd FileType javascript command! -buffer -bar -bang A :exe s:Alternate('edit') 327 | autocmd FileType javascript command! -buffer -bar AS :exe s:Alternate('split') 328 | autocmd FileType javascript command! -buffer -bar AV :exe s:Alternate('vsplit') 329 | autocmd FileType javascript command! -buffer -bar AT :exe s:Alternate('tabedit') 330 | augroup END 331 | endif 332 | 333 | augroup angular_run_spec 334 | autocmd! 335 | autocmd FileType javascript command! -buffer AngularRunSpec :call s:AngularRunSpec() 336 | autocmd FileType javascript command! -buffer AngularRunSpecBlock :call s:AngularRunSpecBlock() 337 | autocmd FileType javascript nnoremap rs :AngularRunSpec 338 | autocmd FileType javascript nnoremap rb :AngularRunSpecBlock 339 | augroup END 340 | --------------------------------------------------------------------------------