├── .eslintignore ├── .eslintrc.js ├── .github └── no-response.yml ├── .gitignore ├── .pairs ├── .travis.yml ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── appveyor.yml ├── keymaps └── symbols-view.cson ├── lib ├── ctags-config ├── file-view.js ├── get-tags-file.js ├── go-back-view.js ├── go-to-view.js ├── load-tags-handler.js ├── main.js ├── project-view.js ├── symbols-view.js ├── tag-generator.js └── tag-reader.js ├── menus └── symbols-view.cson ├── package-lock.json ├── package.json ├── spec ├── async-spec-helpers.js ├── fixtures │ ├── c │ │ ├── sample.c │ │ └── tags │ ├── js │ │ ├── sample.js │ │ ├── tagged-duplicate.js │ │ ├── tagged.js │ │ └── tags │ └── ruby │ │ ├── file1.rb │ │ └── tags └── symbols-view-spec.js ├── styles └── symbols-view.less └── vendor ├── ctags-darwin ├── ctags-linux └── ctags-win32.exe /.eslintignore: -------------------------------------------------------------------------------- 1 | **/fixtures/**/*.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | extends: 'fbjs', 4 | globals: { 5 | atom: true 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an issue is closed for lack of response 4 | daysUntilClose: 28 5 | 6 | # Label requiring a response 7 | responseRequiredLabel: more-information-needed 8 | 9 | # Comment to post when closing an issue for lack of response. Set to `false` to disable. 10 | closeComment: > 11 | This issue has been automatically closed because there has been no response 12 | to our request for more information from the original author. With only the 13 | information that is currently in the issue, we don't have enough information 14 | to take action. Please reach out if you have or find the answers we need so 15 | that we can investigate further. 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.pairs: -------------------------------------------------------------------------------- 1 | pairs: 2 | ns: Nathan Sobo; nathan 3 | cj: Corey Johnson; cj 4 | dg: David Graham; dgraham 5 | ks: Kevin Sawicki; kevin 6 | jc: Jerry Cheung; jerry 7 | bl: Brian Lopez; brian 8 | jp: Justin Palmer; justin 9 | gt: Garen Torikian; garen 10 | mc: Matt Colyer; mcolyer 11 | bo: Ben Ogle; benogle 12 | jr: Jason Rudolph; jasonrudolph 13 | jl: Jessica Lord; jlord 14 | email: 15 | domain: github.com 16 | #global: true 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | notifications: 4 | email: 5 | on_success: never 6 | on_failure: change 7 | 8 | script: 'curl -s https://raw.githubusercontent.com/atom/ci/master/build-package.sh | sh' 9 | 10 | git: 11 | depth: 10 12 | 13 | branches: 14 | only: 15 | - master 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | See the [Atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md) 2 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Prerequisites 10 | 11 | * [ ] Put an X between the brackets on this line if you have done all of the following: 12 | * Reproduced the problem in Safe Mode: http://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode 13 | * Followed all applicable steps in the debugging guide: http://flight-manual.atom.io/hacking-atom/sections/debugging/ 14 | * Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq 15 | * Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom 16 | * Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages 17 | 18 | ### Description 19 | 20 | [Description of the issue] 21 | 22 | ### Steps to Reproduce 23 | 24 | 1. [First Step] 25 | 2. [Second Step] 26 | 3. [and so on...] 27 | 28 | **Expected behavior:** [What you expect to happen] 29 | 30 | **Actual behavior:** [What actually happens] 31 | 32 | **Reproduces how often:** [What percentage of the time does it reproduce?] 33 | 34 | ### Versions 35 | 36 | You can get this information from copy and pasting the output of `atom --version` and `apm --version` from the command line. Also, please include the OS and what version of the OS you're running. 37 | 38 | ### Additional Information 39 | 40 | Any additional information, configuration or data that might be necessary to reproduce the issue. 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 GitHub Inc. 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 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Requirements 2 | 3 | * Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion. 4 | * All new code requires tests to ensure against regressions 5 | 6 | ### Description of the Change 7 | 8 | 13 | 14 | ### Alternate Designs 15 | 16 | 17 | 18 | ### Benefits 19 | 20 | 21 | 22 | ### Possible Drawbacks 23 | 24 | 25 | 26 | ### Applicable Issues 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##### Atom and all repositories under Atom will be archived on December 15, 2022. Learn more in our [official announcement](https://github.blog/2022-06-08-sunsetting-atom/) 2 | # Symbols View package 3 | [![macOS Build Status](https://travis-ci.org/atom/symbols-view.svg?branch=master)](https://travis-ci.org/atom/symbols-view) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/al68vtv83x49eu5d/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/symbols-view/branch/master) [![Dependency Status](https://david-dm.org/atom/symbols-view.svg)](https://david-dm.org/atom/symbols-view) 4 | 5 | Display the list of functions/methods in the editor. 6 | 7 | If your project has a `tags`/`.tags`/`TAGS`/`.TAGS` file at the root then following are supported: 8 | 9 | |Command|Description|Keybinding (Linux)|Keybinding (macOS)|Keybinding (Windows)| 10 | |-------|-----------|------------------|-----------------|--------------------| 11 | |`symbols-view:toggle-file-symbols`|Show all symbols in current file|ctrl-r|cmd-r|ctrl-r| 12 | |`symbols-view:toggle-project-symbols`|Show all symbols in the project|ctrl-shift-r|cmd-shift-r|ctrl-shift-r| 13 | |`symbols-view:go-to-declaration`|Jump to the symbol under the cursor|ctrl-alt-down|cmd-alt-down|| 14 | |`symbols-view:return-from-declaration`|Return from the jump|ctrl-alt-up|cmd-alt-up|| 15 | 16 | This package uses [ctags](http://ctags.sourceforge.net). 17 | 18 | ![](https://f.cloud.github.com/assets/671378/2241860/30ef0b2e-9ce8-11e3-86e2-2c17c0885fa4.png) 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2015 2 | 3 | version: "{build}" 4 | 5 | platform: x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | clone_depth: 10 12 | 13 | skip_tags: true 14 | 15 | environment: 16 | APM_TEST_PACKAGES: 17 | 18 | matrix: 19 | - ATOM_CHANNEL: stable 20 | - ATOM_CHANNEL: beta 21 | 22 | install: 23 | - ps: Install-Product node 4 24 | 25 | build_script: 26 | - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/atom/ci/master/build-package.ps1')) 27 | 28 | test: off 29 | deploy: off 30 | -------------------------------------------------------------------------------- /keymaps/symbols-view.cson: -------------------------------------------------------------------------------- 1 | '.platform-darwin atom-text-editor': 2 | 'cmd-r': 'symbols-view:toggle-file-symbols' 3 | 'cmd-alt-down': 'symbols-view:go-to-declaration' 4 | 'cmd-alt-up': 'symbols-view:return-from-declaration' 5 | 6 | '.platform-win32 atom-text-editor': 7 | 'ctrl-r': 'symbols-view:toggle-file-symbols' 8 | 9 | '.platform-linux atom-text-editor': 10 | 'ctrl-r': 'symbols-view:toggle-file-symbols' 11 | 'ctrl-alt-down': 'symbols-view:go-to-declaration' 12 | 'ctrl-alt-up': 'symbols-view:return-from-declaration' 13 | 14 | '.platform-darwin': 15 | 'cmd-shift-r': 'symbols-view:toggle-project-symbols' 16 | 17 | '.platform-win32, .platform-linux': 18 | 'ctrl-shift-r': 'symbols-view:toggle-project-symbols' 19 | -------------------------------------------------------------------------------- /lib/ctags-config: -------------------------------------------------------------------------------- 1 | --langdef=CoffeeScript 2 | --langmap=CoffeeScript:.coffee 3 | --regex-CoffeeScript=/^[ \t]*(@?[a-zA-Z$_\.0-9]+)[ \t]*(=|\:)[ \t]*(\(.*\))?[ \t]*(-|=)>/\1/f,function/ 4 | --regex-CoffeeScript=/^[ \t]*([a-zA-Z$_0-9]+\:\:[a-zA-Z$_\.0-9]+)[ \t]*(=|\:)[ \t]*(\(.*\))?[ \t]*(-|=)>/\1/f,function/ 5 | --regex-CoffeeScript=/^[ \t]*describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 6 | --regex-CoffeeScript=/^[ \t]*describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 7 | --regex-CoffeeScript=/^[ \t]*it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 8 | --regex-CoffeeScript=/^[ \t]*it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 9 | --regex-CoffeeScript=/^[ \t]*f+describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/focused\: \1/f,function/ 10 | --regex-CoffeeScript=/^[ \t]*f+describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ 11 | --regex-CoffeeScript=/^[ \t]*f+it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ 12 | --regex-CoffeeScript=/^[ \t]*f+it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ 13 | --regex-CoffeeScript=/^[ \t]*xdescribe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/disabled\: \1/f,function/ 14 | --regex-CoffeeScript=/^[ \t]*xdescribe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 15 | --regex-CoffeeScript=/^[ \t]*xit[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 16 | --regex-CoffeeScript=/^[ \t]*xit[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 17 | --regex-CoffeeScript=/^[ \t]*class[ \t]*([a-zA-Z$_\.0-9]+)[ \t]*/\1/f,function/ 18 | 19 | --langdef=ColdFusion 20 | --langmap=ColdFusion:.cfc 21 | --langmap=ColdFusion:+.cfm 22 | --langmap=ColdFusion:+.cfml 23 | --regex-ColdFusion=/(,|(;|^)[ \t]*(var|([A-Za-z_$][A-Za-z0-9_$.]*\.)*))[ \t]*([A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\5/,function/ 24 | --regex-ColdFusion=/function[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,function/ 25 | --regex-ColdFusion=/cffunction[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,cffunction/ 26 | --regex-ColdFusion=/(,|^|\*\/)[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*:[ \t]*function[ \t]*\(/\2/,function/ 27 | --regex-ColdFusion=/(,|^|\*\/)[ \t]*(static[ \t]+)?(while|if|for|function|switch|with|([A-Za-z_$][A-Za-z0-9_$]+))[ \t]*\(.*\)[ \t]*\{/\2\4/,function/ 28 | --regex-ColdFusion=/(,|^|\*\/)[ \t]*get[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*\)[ \t]*\{/get \2/,function/ 29 | --regex-ColdFusion=/(,|^|\*\/)[ \t]*set[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$][A-Za-z0-9_$]+)?[ \t]*\)[ \t]*\{/set \2/,function/ 30 | --regex-ColdFusion=/(,|^|\*\/)[ \t]*async[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$].+)?[ \t]*\)[ \t]*\{/\2/,function/ 31 | --regex-ColdFusion=/component[ \t]+([A-Za-z0-9._$]+)[ \t]*/\1/c,component/ 32 | --regex-ColdFusion=/^[ \t]*given[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 33 | --regex-ColdFusion=/^[ \t]*given[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 34 | --regex-ColdFusion=/^[ \t]*story[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 35 | --regex-ColdFusion=/^[ \t]*story[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 36 | --regex-ColdFusion=/^[ \t]*feature[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 37 | --regex-ColdFusion=/^[ \t]*feature[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 38 | --regex-ColdFusion=/^[ \t]*when[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 39 | --regex-ColdFusion=/^[ \t]*when[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 40 | --regex-ColdFusion=/^[ \t]*then[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 41 | --regex-ColdFusion=/^[ \t]*then[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 42 | --regex-ColdFusion=/^[ \t]*describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 43 | --regex-ColdFusion=/^[ \t]*describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 44 | --regex-ColdFusion=/^[ \t]*it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ 45 | --regex-ColdFusion=/^[ \t]*it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ 46 | --regex-ColdFusion=/^[ \t]*xdescribe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/disabled\: \1/f,function/ 47 | --regex-ColdFusion=/^[ \t]*xdescribe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 48 | --regex-ColdFusion=/^[ \t]*xit[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 49 | --regex-ColdFusion=/^[ \t]*xit[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ 50 | 51 | --langdef=Css 52 | --langmap=Css:.css 53 | --langmap=Css:+.less 54 | --langmap=Css:+.scss 55 | --regex-Css=/^[ \t]*(.+)[ \t]*\{/\1/f,function/ 56 | --regex-Css=/^[ \t]*(.+)[ \t]*,[ \t]*$/\1/f,function/ 57 | --regex-Css=/^[ \t]*[@$]([a-zA-Z$_][-a-zA-Z$_0-9]*)[ \t]*:/\1/f,function/ 58 | 59 | --langdef=Sass 60 | --langmap=Sass:.sass 61 | --regex-Sass=/^[ \t]*([#.]*[a-zA-Z_0-9]+)[ \t]*$/\1/f,function/ 62 | 63 | --langdef=Yaml 64 | --langmap=Yaml:.yaml 65 | --langmap=Yaml:+.yml 66 | --regex-Yaml=/^[ \t]*([a-zA-Z_0-9 ]+)[ \t]*\:[ \t]*/\1/f,function/ 67 | 68 | --regex-Html=/^[ \t]*<([a-zA-Z]+)[ \t]*.*>/\1/f,function/ 69 | 70 | --langdef=Markdown 71 | --langmap=Markdown:.md 72 | --langmap=Markdown:+.markdown 73 | --langmap=Markdown:+.mdown 74 | --langmap=Markdown:+.mkd 75 | --langmap=Markdown:+.mkdown 76 | --langmap=Markdown:+.ron 77 | --regex-Markdown=/^#+[ \t]*([^#]+)/\1/f,function/ 78 | 79 | --langdef=Json 80 | --langmap=Json:.json 81 | --regex-Json=/^[ \t]*"([^"]+)"[ \t]*\:/\1/f,function/ 82 | 83 | --langdef=Cson 84 | --langmap=Cson:.cson 85 | --langmap=Cson:+.gyp 86 | --regex-Cson=/^[ \t]*'([^']+)'[ \t]*\:/\1/f,function/ 87 | --regex-Cson=/^[ \t]*"([^"]+)"[ \t]*\:/\1/f,function/ 88 | --regex-Cson=/^[ \t]*([^'"]+)[ \t]*\:/\1/f,function/ 89 | 90 | --langmap=C++:+.mm 91 | 92 | --langmap=Ruby:+(Rakefile) 93 | 94 | --langmap=Php:+.module 95 | 96 | --langdef=Go 97 | --langmap=Go:.go 98 | --regex-Go=/func([ \t]+\([^)]+\))?[ \t]+([a-zA-Z0-9_]+)/\2/f,func/ 99 | --regex-Go=/var[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)/\1/v,var/ 100 | --regex-Go=/type[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)/\1/t,type/ 101 | 102 | --langdef=Capnp 103 | --langmap=Capnp:.capnp 104 | --regex-Capnp=/struct[ \t]+([A-Za-z]+)/\1/s,struct/ 105 | --regex-Capnp=/enum[ \t]+([A-Za-z]+)/\1/e,enum/ 106 | --regex-Capnp=/using[ \t]+([A-Za-z]+)[ \t]+=[ \t]+import/\1/u,using/ 107 | --regex-Capnp=/const[ \t]+([A-Za-z]+)/\1/c,const/ 108 | 109 | --langmap=perl:+.pod 110 | --regex-perl=/with[ \t]+([^;]+)[ \t]*?;/\1/w,role,roles/ 111 | --regex-perl=/extends[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ 112 | --regex-perl=/use[ \t]+base[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ 113 | --regex-perl=/use[ \t]+parent[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ 114 | --regex-perl=/Mojo::Base[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ 115 | --regex-perl=/^[ \t]*?use[ \t]+([^;]+)[ \t]*?;/\1/u,use,uses/ 116 | --regex-perl=/^[ \t]*?require[ \t]+((\w|\:)+)/\1/r,require,requires/ 117 | --regex-perl=/^[ \t]*?has[ \t]+['"]?(\w+)['"]?/\1/a,attribute,attributes/ 118 | --regex-perl=/^[ \t]*?\*(\w+)[ \t]*?=/\1/a,alias,aliases/ 119 | --regex-perl=/->helper\([ \t]?['"]?(\w+)['"]?/\1/h,helper,helpers/ 120 | --regex-perl=/^[ \t]*?our[ \t]*?[\$@%](\w+)/\1/o,our,ours/ 121 | --regex-perl=/^\=head1[ \t]+(.+)/\1/p,pod,Plain Old Documentation/ 122 | --regex-perl=/^\=head2[ \t]+(.+)/-- \1/p,pod,Plain Old Documentation/ 123 | --regex-perl=/^\=head[3-5][ \t]+(.+)/---- \1/p,pod,Plain Old Documentation/ 124 | 125 | --regex-JavaScript=/(,|(;|^)[ \t]*(var|let|([A-Za-z_$][A-Za-z0-9_$.]*\.)*))[ \t]*([A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\5/,function/ 126 | --regex-JavaScript=/function[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,function/ 127 | --regex-JavaScript=/(,|^|\*\/)[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*:[ \t]*function[ \t]*\(/\2/,function/ 128 | --regex-JavaScript=/(,|^|\*\/)[ \t]*(static[ \t]+)?(while|if|for|function|switch|with|([A-Za-z_$][A-Za-z0-9_$]+))[ \t]*\(.*\)[ \t]*\{/\2\4/,function/ 129 | --regex-JavaScript=/(,|^|\*\/)[ \t]*get[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*\)[ \t]*\{/get \2/,function/ 130 | --regex-JavaScript=/(,|^|\*\/)[ \t]*set[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$][A-Za-z0-9_$]+)?[ \t]*\)[ \t]*\{/set \2/,function/ 131 | --regex-JavaScript=/(,|^|\*\/)[ \t]*async[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$].+)?[ \t]*\)[ \t]*\{/\2/,function/ 132 | --regex-JavaScript=/class[ \t]+([A-Za-z0-9._$]+)[ \t]*/\1/c,class/ 133 | --regex-JavaScript=/^[ \t]*describe\("([^"]+)"[ \t]*,/\1/f,function/ 134 | --regex-JavaScript=/^[ \t]*describe\('([^']+)'[ \t]*,/\1/f,function/ 135 | --regex-JavaScript=/^[ \t]*it\("([^"]+)"[ \t]*,/\1/f,function/ 136 | --regex-JavaScript=/^[ \t]*it\('([^']+)'[ \t]*,/\1/f,function/ 137 | --regex-JavaScript=/^[ \t]*f+describe\('([^']+)'[ \t]*,/focused: \1/f,function/ 138 | --regex-JavaScript=/^[ \t]*f+describe\("([^"]+)"[ \t]*,/focused: \1/f,function/ 139 | --regex-JavaScript=/^[ \t]*f+it\('([^']+)'[ \t]*,/focused: \1/f,function/ 140 | --regex-JavaScript=/^[ \t]*f+it\("([^"]+)"[ \t]*,/focused: \1/f,function/ 141 | --regex-JavaScript=/^[ \t]*xdescribe\('([^']+)'[ \t]*,/disabled: \1/f,function/ 142 | --regex-JavaScript=/^[ \t]*xdescribe\("([^"]+)"[ \t]*,/disabled: \1/f,function/ 143 | --regex-JavaScript=/^[ \t]*xit\('([^']+)'[ \t]*,/disabled: \1/f,function/ 144 | --regex-JavaScript=/^[ \t]*xit\("([^"]+)"[ \t]*,/disabled: \1/f,function/ 145 | 146 | --langdef=haxe 147 | --langmap=haxe:.hx 148 | --regex-haxe=/^package[ \t]+([A-Za-z0-9_.]+)/\1/p,package/ 149 | --regex-haxe=/^[ \t]*[(@:macro|private|public|static|override|inline|dynamic)( \t)]*function[ \t]+([A-Za-z0-9_]+)/\1/f,function/ 150 | --regex-haxe=/^[ \t]*([private|public|static|protected|inline][ \t]*)+var[ \t]+([A-Za-z0-9_]+)/\2/v,variable/ 151 | --regex-haxe=/^[ \t]*package[ \t]*([A-Za-z0-9_]+)/\1/p,package/ 152 | --regex-haxe=/^[ \t]*(extern[ \t]*|@:native\([^)]*\)[ \t]*)*class[ \t]+([A-Za-z0-9_]+)[ \t]*[^\{]*/\2/c,class/ 153 | --regex-haxe=/^[ \t]*(extern[ \t]+)?interface[ \t]+([A-Za-z0-9_]+)/\2/i,interface/ 154 | --regex-haxe=/^[ \t]*typedef[ \t]+([A-Za-z0-9_]+)/\1/t,typedef/ 155 | --regex-haxe=/^[ \t]*enum[ \t]+([A-Za-z0-9_]+)/\1/t,typedef/ 156 | --regex-haxe=/^[ \t]*+([A-Za-z0-9_]+)(;|\([^)]*:[^)]*\))/\1/t,enum_field/ 157 | 158 | --langdef=Elixir 159 | --langmap=Elixir:.ex.exs 160 | --regex-Elixir=/^[ \t]*def(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\2/f,functions,functions (def ...)/ 161 | --regex-Elixir=/^[ \t]*defcallback[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/c,callbacks,callbacks (defcallback ...)/ 162 | --regex-Elixir=/^[ \t]*defdelegate[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/d,delegates,delegates (defdelegate ...)/ 163 | --regex-Elixir=/^[ \t]*defexception[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/e,exceptions,exceptions (defexception ...)/ 164 | --regex-Elixir=/^[ \t]*defimpl[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/i,implementations,implementations (defimpl ...)/ 165 | --regex-Elixir=/^[ \t]*defmacro(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)\(/\2/a,macros,macros (defmacro ...)/ 166 | --regex-Elixir=/^[ \t]*defmacro(p?)[ \t]+([a-zA-Z0-9_?!]+)?[ \t]+([^ \tA-Za-z0-9_]+)[ \t]*[a-zA-Z0-9_!?!]/\3/o,operators,operators (e.g. "defmacro a <<< b")/ 167 | --regex-Elixir=/^[ \t]*defmodule[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/m,modules,modules (defmodule ...)/ 168 | --regex-Elixir=/^[ \t]*defprotocol[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/p,protocols,protocols (defprotocol...)/ 169 | --regex-Elixir=/^[ \t]*Record\.defrecord[ \t]+:([a-zA-Z0-9_]+)/\1/r,records,records (defrecord...)/ 170 | 171 | --langdef=Nim 172 | --langmap=Nim:.nim 173 | --regex-Nim=/^[\t\s]*proc\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/f,function/ 174 | --regex-Nim=/^[\t\s]*iterator\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/i,iterator/ 175 | --regex-Nim=/^[\t\s]*macro\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/m,macro/ 176 | --regex-Nim=/^[\t\s]*method\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/h,method/ 177 | --regex-Nim=/^[\t\s]*template\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/t,generics/ 178 | --regex-Nim=/^[\t\s]*converter\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/c,converter/ 179 | 180 | --langdef=Fountain 181 | --langmap=Fountain:.fountain 182 | --langmap=Fountain:+.ftn 183 | --regex-Fountain=/^(([iI][nN][tT]|[eE][xX][tT]|[^\w][eE][sS][tT]|\.|[iI]\.?\/[eE]\.?)([^\n]+))/\1/f,function/ 184 | 185 | --langdef=Julia 186 | --langmap=Julia:.jl 187 | --regex-Julia=/^[ \t]*(function|macro|abstract|type|typealias|immutable)[ \t]+([^ \t({[]+).*$/\2/f,function/ 188 | --regex-Julia=/^[ \t]*(([^@#$ \t({[]+)|\(([^@#$ \t({[]+)\)|\((\$)\))[ \t]*(\{.*\})?[ \t]*\([^#]*\)[ \t]*=([^=].*$|$)/\2\3\4/f,function/ 189 | 190 | --langdef=Latex 191 | --langmap=latex:.tex 192 | --regex-latex=/\\label\{([^}]*)\}/\1/l,label/ 193 | --regex-latex=/\\section\{([^}]*)\}/\1/s,section/ 194 | --regex-latex=/\\subsection\{([^}]*)\}/\1/t,subsection/ 195 | --regex-latex=/\\subsubsection\{([^}]*)\}/\1/u,subsubsection/ 196 | --regex-latex=/\\section\*\{([^}]*)\}/\1/s,section/ 197 | --regex-latex=/\\subsection\*\{([^}]*)\}/\1/t,subsection/ 198 | --regex-latex=/\\subsubsection\*\{([^}]*)\}/\1/u,subsubsection/ 199 | -------------------------------------------------------------------------------- /lib/file-view.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import { CompositeDisposable } from 'atom'; 4 | import SymbolsView from './symbols-view'; 5 | import TagGenerator from './tag-generator'; 6 | import { match } from 'fuzzaldrin'; 7 | 8 | export default class FileView extends SymbolsView { 9 | constructor(stack) { 10 | super(stack); 11 | this.cachedTags = {}; 12 | this.watchedEditors = new WeakSet(); 13 | 14 | this.editorsSubscription = atom.workspace.observeTextEditors(editor => { 15 | if (this.watchedEditors.has(editor)) return; 16 | 17 | const removeFromCache = () => { 18 | delete this.cachedTags[editor.getPath()]; 19 | }; 20 | const editorSubscriptions = new CompositeDisposable(); 21 | editorSubscriptions.add(editor.onDidChangeGrammar(removeFromCache)); 22 | editorSubscriptions.add(editor.onDidSave(removeFromCache)); 23 | editorSubscriptions.add(editor.onDidChangePath(removeFromCache)); 24 | editorSubscriptions.add(editor.getBuffer().onDidReload(removeFromCache)); 25 | editorSubscriptions.add(editor.getBuffer().onDidDestroy(removeFromCache)); 26 | editor.onDidDestroy(() => { 27 | this.watchedEditors.delete(editor); 28 | editorSubscriptions.dispose(); 29 | }); 30 | 31 | this.watchedEditors.add(editor); 32 | }); 33 | } 34 | 35 | destroy() { 36 | this.editorsSubscription.dispose(); 37 | return super.destroy(); 38 | } 39 | 40 | elementForItem({position, name}) { 41 | // Style matched characters in search results 42 | const matches = match(name, this.selectListView.getFilterQuery()); 43 | 44 | const li = document.createElement('li'); 45 | li.classList.add('two-lines'); 46 | 47 | const primaryLine = document.createElement('div'); 48 | primaryLine.classList.add('primary-line'); 49 | primaryLine.appendChild(SymbolsView.highlightMatches(this, name, matches)); 50 | li.appendChild(primaryLine); 51 | 52 | const secondaryLine = document.createElement('div'); 53 | secondaryLine.classList.add('secondary-line'); 54 | secondaryLine.textContent = `Line ${position.row + 1}`; 55 | li.appendChild(secondaryLine); 56 | 57 | return li; 58 | } 59 | 60 | didChangeSelection(item) { 61 | if (atom.config.get('symbols-view.quickJumpToFileSymbol') && item) { 62 | this.openTag(item); 63 | } 64 | } 65 | 66 | async didCancelSelection() { 67 | await this.cancel(); 68 | const editor = this.getEditor(); 69 | if (this.initialState && editor) { 70 | this.deserializeEditorState(editor, this.initialState); 71 | } 72 | this.initialState = null; 73 | } 74 | 75 | async toggle() { 76 | if (this.panel.isVisible()) { 77 | await this.cancel(); 78 | } 79 | const filePath = this.getPath(); 80 | if (filePath) { 81 | const editor = this.getEditor(); 82 | if (atom.config.get('symbols-view.quickJumpToFileSymbol') && editor) { 83 | this.initialState = this.serializeEditorState(editor); 84 | } 85 | this.populate(filePath); 86 | this.attach(); 87 | } 88 | } 89 | 90 | serializeEditorState(editor) { 91 | const editorElement = atom.views.getView(editor); 92 | const scrollTop = editorElement.getScrollTop(); 93 | 94 | return { 95 | bufferRanges: editor.getSelectedBufferRanges(), 96 | scrollTop, 97 | }; 98 | } 99 | 100 | deserializeEditorState(editor, {bufferRanges, scrollTop}) { 101 | const editorElement = atom.views.getView(editor); 102 | 103 | editor.setSelectedBufferRanges(bufferRanges); 104 | editorElement.setScrollTop(scrollTop); 105 | } 106 | 107 | getEditor() { 108 | return atom.workspace.getActiveTextEditor(); 109 | } 110 | 111 | getPath() { 112 | if (this.getEditor()) { 113 | return this.getEditor().getPath(); 114 | } 115 | return undefined; 116 | } 117 | 118 | getScopeName() { 119 | if (this.getEditor() && this.getEditor().getGrammar()) { 120 | return this.getEditor().getGrammar().scopeName; 121 | } 122 | return undefined; 123 | } 124 | 125 | async populate(filePath) { 126 | const tags = this.cachedTags[filePath]; 127 | if (tags) { 128 | await this.selectListView.update({items: tags}); 129 | } else { 130 | await this.selectListView.update({ 131 | items: [], 132 | loadingMessage: 'Generating symbols\u2026', 133 | }); 134 | await this.selectListView.update({ 135 | items: await this.generateTags(filePath), 136 | loadingMessage: null, 137 | }); 138 | } 139 | } 140 | 141 | async generateTags(filePath) { 142 | const generator = new TagGenerator(filePath, this.getScopeName()); 143 | this.cachedTags[filePath] = await generator.generate(); 144 | return this.cachedTags[filePath]; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/get-tags-file.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import path from 'path'; 4 | import fs from 'fs-plus'; 5 | 6 | const files = ['tags', 'TAGS', '.tags', '.TAGS', path.join('.git', 'tags'), path.join('.git', 'TAGS')]; 7 | export default function(directoryPath) { 8 | if (!directoryPath) { 9 | return undefined; 10 | } 11 | 12 | for (const file of files) { 13 | const tagsFile = path.join(directoryPath, file); 14 | if (fs.isFileSync(tagsFile)) { 15 | return tagsFile; 16 | } 17 | } 18 | 19 | return undefined; 20 | } 21 | -------------------------------------------------------------------------------- /lib/go-back-view.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import SymbolsView from './symbols-view'; 4 | 5 | export default class GoBackView extends SymbolsView { 6 | toggle() { 7 | const previousTag = this.stack.pop(); 8 | if (!previousTag) { 9 | return; 10 | } 11 | 12 | const restorePosition = () => { 13 | if (previousTag.position) { 14 | this.moveToPosition(previousTag.position, false); 15 | } 16 | }; 17 | 18 | const previousEditor = atom.workspace.getTextEditors().find(e => e.id === previousTag.editorId); 19 | 20 | if (previousEditor) { 21 | const pane = atom.workspace.paneForItem(previousEditor); 22 | pane.setActiveItem(previousEditor); 23 | restorePosition(); 24 | } else if (previousTag.file) { 25 | atom.workspace.open(previousTag.file).then(restorePosition); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/go-to-view.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import path from 'path'; 4 | import SymbolsView from './symbols-view'; 5 | import TagReader from './tag-reader'; 6 | 7 | export default class GoToView extends SymbolsView { 8 | toggle() { 9 | if (this.panel.isVisible()) { 10 | this.cancel(); 11 | } else { 12 | this.populate(); 13 | } 14 | } 15 | 16 | detached() { 17 | if (this.resolveFindTagPromise) { 18 | this.resolveFindTagPromise([]); 19 | } 20 | } 21 | 22 | findTag(editor) { 23 | if (this.resolveFindTagPromise) { 24 | this.resolveFindTagPromise([]); 25 | } 26 | 27 | return new Promise((resolve, reject) => { 28 | this.resolveFindTagPromise = resolve; 29 | TagReader.find(editor, (error, matches) => { 30 | if (!matches) { 31 | matches = []; 32 | } 33 | if (error) { 34 | return reject(error); 35 | } else { 36 | return resolve(matches); 37 | } 38 | }); 39 | }); 40 | } 41 | 42 | async populate() { 43 | let editor = atom.workspace.getActiveTextEditor(); 44 | if (!editor) { 45 | return; 46 | } 47 | 48 | this.findTag(editor).then(async matches => { 49 | let tags = []; 50 | for (let match of Array.from(matches)) { 51 | let position = this.getTagLine(match); 52 | if (!position) { continue; } 53 | match.name = path.basename(match.file); 54 | tags.push(match); 55 | } 56 | 57 | if (tags.length === 1) { 58 | this.openTag(tags[0]); 59 | } else if (tags.length > 0) { 60 | await this.selectListView.update({items: tags}); 61 | this.attach(); 62 | } 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/load-tags-handler.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | /* global emit*/ 3 | 4 | import async from 'async'; 5 | import ctags from 'ctags'; 6 | import getTagsFile from './get-tags-file'; 7 | 8 | export default function(directoryPaths) { 9 | return async.each( 10 | directoryPaths, 11 | (directoryPath, done) => { 12 | let tagsFilePath = getTagsFile(directoryPath); 13 | if (!tagsFilePath) { return done(); } 14 | 15 | let stream = ctags.createReadStream(tagsFilePath); 16 | stream.on('data', function(tags) { 17 | for (const tag of Array.from(tags)) { tag.directory = directoryPath; } 18 | return emit('tags', tags); 19 | }); 20 | stream.on('end', done); 21 | return stream.on('error', done); 22 | } 23 | , this.async() 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | export default { 4 | activate() { 5 | this.stack = []; 6 | 7 | this.workspaceSubscription = atom.commands.add('atom-workspace', { 8 | 'symbols-view:toggle-project-symbols': () => { 9 | this.createProjectView().toggle(); 10 | }, 11 | }); 12 | 13 | this.editorSubscription = atom.commands.add('atom-text-editor', { 14 | 'symbols-view:toggle-file-symbols': () => { 15 | this.createFileView().toggle(); 16 | }, 17 | 'symbols-view:go-to-declaration': () => { 18 | this.createGoToView().toggle(); 19 | }, 20 | 'symbols-view:return-from-declaration': () => { 21 | this.createGoBackView().toggle(); 22 | }, 23 | }); 24 | }, 25 | 26 | deactivate() { 27 | if (this.fileView != null) { 28 | this.fileView.destroy(); 29 | this.fileView = null; 30 | } 31 | 32 | if (this.projectView != null) { 33 | this.projectView.destroy(); 34 | this.projectView = null; 35 | } 36 | 37 | if (this.goToView != null) { 38 | this.goToView.destroy(); 39 | this.goToView = null; 40 | } 41 | 42 | if (this.goBackView != null) { 43 | this.goBackView.destroy(); 44 | this.goBackView = null; 45 | } 46 | 47 | if (this.workspaceSubscription != null) { 48 | this.workspaceSubscription.dispose(); 49 | this.workspaceSubscription = null; 50 | } 51 | 52 | if (this.editorSubscription != null) { 53 | this.editorSubscription.dispose(); 54 | this.editorSubscription = null; 55 | } 56 | }, 57 | 58 | createFileView() { 59 | if (this.fileView) { 60 | return this.fileView; 61 | } 62 | const FileView = require('./file-view'); 63 | this.fileView = new FileView(this.stack); 64 | return this.fileView; 65 | }, 66 | 67 | createProjectView() { 68 | if (this.projectView) { 69 | return this.projectView; 70 | } 71 | const ProjectView = require('./project-view'); 72 | this.projectView = new ProjectView(this.stack); 73 | return this.projectView; 74 | }, 75 | 76 | createGoToView() { 77 | if (this.goToView) { 78 | return this.goToView; 79 | } 80 | const GoToView = require('./go-to-view'); 81 | this.goToView = new GoToView(this.stack); 82 | return this.goToView; 83 | }, 84 | 85 | createGoBackView() { 86 | if (this.goBackView) { 87 | return this.goBackView; 88 | } 89 | const GoBackView = require('./go-back-view'); 90 | this.goBackView = new GoBackView(this.stack); 91 | return this.goBackView; 92 | }, 93 | }; 94 | -------------------------------------------------------------------------------- /lib/project-view.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import { CompositeDisposable, File } from 'atom'; 4 | import humanize from 'humanize-plus'; 5 | import SymbolsView from './symbols-view'; 6 | import TagReader from './tag-reader'; 7 | import getTagsFile from './get-tags-file'; 8 | 9 | export default class ProjectView extends SymbolsView { 10 | constructor(stack) { 11 | super(stack, 'Project has no tags file or it is empty', 10); 12 | this.reloadTags = true; 13 | } 14 | 15 | destroy() { 16 | this.stopTask(); 17 | this.unwatchTagsFiles(); 18 | return super.destroy(); 19 | } 20 | 21 | toggle() { 22 | if (this.panel.isVisible()) { 23 | this.cancel(); 24 | } else { 25 | this.populate(); 26 | this.attach(); 27 | } 28 | } 29 | 30 | async populate() { 31 | if (this.tags) { 32 | await this.selectListView.update({items: this.tags}); 33 | } 34 | 35 | if (this.reloadTags) { 36 | this.reloadTags = false; 37 | this.startTask(); 38 | 39 | if (this.tags) { 40 | await this.selectListView.update({ 41 | loadingMessage: 'Reloading project symbols\u2026', 42 | }); 43 | } else { 44 | await this.selectListView.update({ 45 | loadingMessage: 'Loading project symbols\u2026', 46 | loadingBadge: 0, 47 | }); 48 | let tagsRead = 0; 49 | this.loadTagsTask.on('tags', tags => { 50 | tagsRead += tags.length; 51 | this.selectListView.update({loadingBadge: humanize.intComma(tagsRead)}); 52 | }); 53 | } 54 | } 55 | } 56 | 57 | stopTask() { 58 | if (this.loadTagsTask) { 59 | this.loadTagsTask.terminate(); 60 | } 61 | } 62 | 63 | startTask() { 64 | this.stopTask(); 65 | 66 | this.loadTagsTask = TagReader.getAllTags(tags => { 67 | this.tags = tags; 68 | this.reloadTags = this.tags.length === 0; 69 | this.selectListView.update({ 70 | loadingMessage: null, 71 | loadingBadge: null, 72 | items: this.tags, 73 | }); 74 | }); 75 | 76 | this.watchTagsFiles(); 77 | } 78 | 79 | watchTagsFiles() { 80 | this.unwatchTagsFiles(); 81 | 82 | this.tagsFileSubscriptions = new CompositeDisposable(); 83 | let reloadTags = () => { 84 | this.reloadTags = true; 85 | this.watchTagsFiles(); 86 | }; 87 | 88 | for (const projectPath of Array.from(atom.project.getPaths())) { 89 | const tagsFilePath = getTagsFile(projectPath); 90 | if (tagsFilePath) { 91 | const tagsFile = new File(tagsFilePath); 92 | this.tagsFileSubscriptions.add(tagsFile.onDidChange(reloadTags)); 93 | this.tagsFileSubscriptions.add(tagsFile.onDidDelete(reloadTags)); 94 | this.tagsFileSubscriptions.add(tagsFile.onDidRename(reloadTags)); 95 | } 96 | } 97 | } 98 | 99 | unwatchTagsFiles() { 100 | if (this.tagsFileSubscriptions) { 101 | this.tagsFileSubscriptions.dispose(); 102 | } 103 | this.tagsFileSubscriptions = null; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/symbols-view.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import path from 'path'; 4 | import { Point } from 'atom'; 5 | import SelectListView from 'atom-select-list'; 6 | import fs from 'fs-plus'; 7 | import { match } from 'fuzzaldrin'; 8 | 9 | export default class SymbolsView { 10 | static highlightMatches(context, name, matches, offsetIndex) { 11 | if (!offsetIndex) { 12 | offsetIndex = 0; 13 | } 14 | let lastIndex = 0; 15 | let matchedChars = []; // Build up a set of matched chars to be more semantic 16 | const fragment = document.createDocumentFragment(); 17 | 18 | for (let matchIndex of Array.from(matches)) { 19 | matchIndex -= offsetIndex; 20 | if (matchIndex < 0) { 21 | continue; // If marking up the basename, omit name matches 22 | } 23 | const unmatched = name.substring(lastIndex, matchIndex); 24 | if (unmatched) { 25 | if (matchedChars.length) { 26 | const span = document.createElement('span'); 27 | span.classList.add('character-match'); 28 | span.textContent = matchedChars.join(''); 29 | fragment.appendChild(span); 30 | } 31 | matchedChars = []; 32 | fragment.appendChild(document.createTextNode(unmatched)); 33 | } 34 | matchedChars.push(name[matchIndex]); 35 | lastIndex = matchIndex + 1; 36 | } 37 | 38 | if (matchedChars.length) { 39 | const span = document.createElement('span'); 40 | span.classList.add('character-match'); 41 | span.textContent = matchedChars.join(''); 42 | fragment.appendChild(span); 43 | } 44 | 45 | // Remaining characters are plain text 46 | fragment.appendChild(document.createTextNode(name.substring(lastIndex))); 47 | 48 | return fragment; 49 | } 50 | 51 | constructor(stack, emptyMessage = 'No symbols found', maxResults = null) { 52 | this.stack = stack; 53 | this.selectListView = new SelectListView({ 54 | maxResults, 55 | emptyMessage, 56 | items: [], 57 | filterKeyForItem: (item) => item.name, 58 | elementForItem: this.elementForItem.bind(this), 59 | didChangeSelection: this.didChangeSelection.bind(this), 60 | didConfirmSelection: this.didConfirmSelection.bind(this), 61 | didConfirmEmptySelection: this.didConfirmEmptySelection.bind(this), 62 | didCancelSelection: this.didCancelSelection.bind(this), 63 | }); 64 | this.element = this.selectListView.element; 65 | this.element.classList.add('symbols-view'); 66 | this.panel = atom.workspace.addModalPanel({item: this, visible: false}); 67 | } 68 | 69 | async destroy() { 70 | await this.cancel(); 71 | this.panel.destroy(); 72 | return this.selectListView.destroy(); 73 | } 74 | 75 | getFilterKey() { 76 | return 'name'; 77 | } 78 | 79 | elementForItem({position, name, file, directory}) { 80 | // Style matched characters in search results 81 | const matches = match(name, this.selectListView.getFilterQuery()); 82 | 83 | if (atom.project.getPaths().length > 1) { 84 | file = path.join(path.basename(directory), file); 85 | } 86 | 87 | const li = document.createElement('li'); 88 | li.classList.add('two-lines'); 89 | 90 | const primaryLine = document.createElement('div'); 91 | primaryLine.classList.add('primary-line'); 92 | if (position) { 93 | primaryLine.textContent = `${name}:${position.row + 1}`; 94 | } else { 95 | primaryLine.appendChild(SymbolsView.highlightMatches(this, name, matches)); 96 | } 97 | li.appendChild(primaryLine); 98 | 99 | const secondaryLine = document.createElement('div'); 100 | secondaryLine.classList.add('secondary-line'); 101 | secondaryLine.textContent = file; 102 | li.appendChild(secondaryLine); 103 | 104 | return li; 105 | } 106 | 107 | async cancel() { 108 | if (!this.isCanceling) { 109 | this.isCanceling = true; 110 | await this.selectListView.update({items: []}); 111 | this.panel.hide(); 112 | if (this.previouslyFocusedElement) { 113 | this.previouslyFocusedElement.focus(); 114 | this.previouslyFocusedElement = null; 115 | } 116 | this.isCanceling = false; 117 | } 118 | } 119 | 120 | didCancelSelection() { 121 | this.cancel(); 122 | } 123 | 124 | didConfirmEmptySelection() { 125 | this.cancel(); 126 | } 127 | 128 | async didConfirmSelection(tag) { 129 | if (tag.file && !fs.isFileSync(path.join(tag.directory, tag.file))) { 130 | await this.selectListView.update({errorMessage: 'Selected file does not exist'}); 131 | setTimeout(() => { 132 | this.selectListView.update({errorMessage: null}); 133 | }, 2000); 134 | } else { 135 | await this.cancel(); 136 | this.openTag(tag); 137 | } 138 | } 139 | 140 | didChangeSelection(tag) { 141 | // no-op 142 | } 143 | 144 | openTag(tag) { 145 | const editor = atom.workspace.getActiveTextEditor(); 146 | let previous; 147 | if (editor) { 148 | previous = { 149 | editorId: editor.id, 150 | position: editor.getCursorBufferPosition(), 151 | file: editor.getURI(), 152 | }; 153 | } 154 | 155 | let {position} = tag; 156 | if (!position) { position = this.getTagLine(tag); } 157 | if (tag.file) { 158 | atom.workspace.open(path.join(tag.directory, tag.file)).then(() => { 159 | if (position) { 160 | return this.moveToPosition(position); 161 | } 162 | return undefined; 163 | }); 164 | } else if (position && previous && !previous.position.isEqual(position)) { 165 | this.moveToPosition(position); 166 | } 167 | 168 | this.stack.push(previous); 169 | } 170 | 171 | moveToPosition(position, beginningOfLine) { 172 | const editor = atom.workspace.getActiveTextEditor(); 173 | if (beginningOfLine == null) { 174 | beginningOfLine = true; 175 | } 176 | if (editor) { 177 | editor.setCursorBufferPosition(position, {autoscroll: false}); 178 | if (beginningOfLine) { 179 | editor.moveToFirstCharacterOfLine(); 180 | } 181 | editor.scrollToCursorPosition({center: true}); 182 | } 183 | } 184 | 185 | attach() { 186 | this.previouslyFocusedElement = document.activeElement; 187 | this.panel.show(); 188 | this.selectListView.reset(); 189 | this.selectListView.focus(); 190 | } 191 | 192 | getTagLine(tag) { 193 | if (!tag) { 194 | return undefined; 195 | } 196 | 197 | if (tag.lineNumber) { 198 | return new Point(tag.lineNumber - 1, 0); 199 | } 200 | 201 | // Remove leading /^ and trailing $/ 202 | if (!tag.pattern) { 203 | return undefined; 204 | } 205 | const pattern = tag.pattern.replace(/(^\/\^)|(\$\/$)/g, '').trim(); 206 | 207 | if (!pattern) { 208 | return undefined; 209 | } 210 | const file = path.join(tag.directory, tag.file); 211 | if (!fs.isFileSync(file)) { 212 | return undefined; 213 | } 214 | const iterable = fs.readFileSync(file, 'utf8').split('\n'); 215 | for (let index = 0; index < iterable.length; index++) { 216 | let line = iterable[index]; 217 | if (pattern === line.trim()) { 218 | return new Point(index, 0); 219 | } 220 | } 221 | 222 | return undefined; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /lib/tag-generator.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import { BufferedProcess, Point } from 'atom'; 4 | import path from 'path'; 5 | import fs from 'fs-plus'; 6 | 7 | export default class TagGenerator { 8 | constructor(path1, scopeName) { 9 | this.path = path1; 10 | this.scopeName = scopeName; 11 | } 12 | 13 | getPackageRoot() { 14 | const {resourcePath} = atom.getLoadSettings(); 15 | const currentFileWasRequiredFromSnapshot = !fs.isAbsolute(__dirname); 16 | const packageRoot = currentFileWasRequiredFromSnapshot 17 | ? path.join(resourcePath, 'node_modules', 'symbols-view') 18 | : path.resolve(__dirname, '..'); 19 | 20 | if (path.extname(resourcePath) === '.asar' && packageRoot.indexOf(resourcePath) === 0) { 21 | return path.join(`${resourcePath}.unpacked`, 'node_modules', 'symbols-view'); 22 | } else { 23 | return packageRoot; 24 | } 25 | } 26 | 27 | parseTagLine(line) { 28 | let sections = line.split('\t'); 29 | if (sections.length > 3) { 30 | return { 31 | position: new Point(parseInt(sections[2], 10) - 1), 32 | name: sections[0], 33 | }; 34 | } 35 | return null; 36 | } 37 | 38 | getLanguage() { 39 | if (['.cson', '.gyp'].includes(path.extname(this.path))) { 40 | return 'Cson'; 41 | } 42 | 43 | switch (this.scopeName) { 44 | case 'source.c': return 'C'; 45 | case 'source.cpp': return 'C++'; 46 | case 'source.clojure': return 'Lisp'; 47 | case 'source.capnp': return 'Capnp'; 48 | case 'source.cfscript': return 'ColdFusion'; 49 | case 'source.cfscript.embedded': return 'ColdFusion'; 50 | case 'source.coffee': return 'CoffeeScript'; 51 | case 'source.css': return 'Css'; 52 | case 'source.css.less': return 'Css'; 53 | case 'source.css.scss': return 'Css'; 54 | case 'source.elixir': return 'Elixir'; 55 | case 'source.fountain': return 'Fountain'; 56 | case 'source.gfm': return 'Markdown'; 57 | case 'source.go': return 'Go'; 58 | case 'source.java': return 'Java'; 59 | case 'source.js': return 'JavaScript'; 60 | case 'source.js.jsx': return 'JavaScript'; 61 | case 'source.jsx': return 'JavaScript'; 62 | case 'source.json': return 'Json'; 63 | case 'source.julia': return 'Julia'; 64 | case 'source.makefile': return 'Make'; 65 | case 'source.objc': return 'C'; 66 | case 'source.objcpp': return 'C++'; 67 | case 'source.python': return 'Python'; 68 | case 'source.ruby': return 'Ruby'; 69 | case 'source.sass': return 'Sass'; 70 | case 'source.yaml': return 'Yaml'; 71 | case 'text.html': return 'Html'; 72 | case 'text.html.php': return 'Php'; 73 | case 'text.tex.latex': return 'Latex'; 74 | case 'text.html.cfml': return 'ColdFusion'; 75 | } 76 | return undefined; 77 | } 78 | 79 | generate() { 80 | let tags = {}; 81 | const packageRoot = this.getPackageRoot(); 82 | const command = path.join(packageRoot, 'vendor', `ctags-${process.platform}`); 83 | const defaultCtagsFile = path.join(packageRoot, 'lib', 'ctags-config'); 84 | const args = [`--options=${defaultCtagsFile}`, '--fields=+KS']; 85 | 86 | if (atom.config.get('symbols-view.useEditorGrammarAsCtagsLanguage')) { 87 | const language = this.getLanguage(); 88 | if (language) { 89 | args.push(`--language-force=${language}`); 90 | } 91 | } 92 | 93 | args.push('-nf', '-', this.path); 94 | 95 | return new Promise((resolve) => { 96 | let result, tag; 97 | return new BufferedProcess({ 98 | command: command, 99 | args: args, 100 | stdout: (lines) => { 101 | return (() => { 102 | result = []; 103 | for (const line of Array.from(lines.split('\n'))) { 104 | let item; 105 | if (tag = this.parseTagLine(line)) { 106 | item = tags[tag.position.row] ? tags[tag.position.row] : (tags[tag.position.row] = tag); 107 | } 108 | result.push(item); 109 | } 110 | return result; 111 | })(); 112 | }, 113 | stderr() {}, 114 | exit() { 115 | tags = ((() => { 116 | result = []; 117 | for (const row in tags) { 118 | tag = tags[row]; 119 | result.push(tag); 120 | } 121 | return result; 122 | })()); 123 | return resolve(tags); 124 | }, 125 | }); 126 | }); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/tag-reader.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | import { Task } from 'atom'; 4 | import ctags from 'ctags'; 5 | import async from 'async'; 6 | import getTagsFile from './get-tags-file'; 7 | import _ from 'underscore-plus'; 8 | 9 | let handlerPath = require.resolve('./load-tags-handler'); 10 | 11 | let wordAtCursor = (text, cursorIndex, wordSeparator, noStripBefore) => { 12 | const beforeCursor = text.slice(0, cursorIndex); 13 | const afterCursor = text.slice(cursorIndex); 14 | const beforeCursorWordBegins = noStripBefore ? 0 : beforeCursor.lastIndexOf(wordSeparator) + 1; 15 | let afterCursorWordEnds = afterCursor.indexOf(wordSeparator); 16 | if (afterCursorWordEnds === -1) { 17 | afterCursorWordEnds = afterCursor.length; 18 | } 19 | return beforeCursor.slice(beforeCursorWordBegins) + afterCursor.slice(0, afterCursorWordEnds); 20 | }; 21 | 22 | export default { 23 | find(editor, callback) { 24 | let symbol; 25 | const symbols = []; 26 | 27 | if (symbol = editor.getSelectedText()) { 28 | symbols.push(symbol); 29 | } 30 | 31 | if (!symbols.length) { 32 | let nonWordCharacters; 33 | const cursor = editor.getLastCursor(); 34 | const cursorPosition = cursor.getBufferPosition(); 35 | const scope = cursor.getScopeDescriptor(); 36 | const rubyScopes = scope.getScopesArray().filter(s => /^source\.ruby($|\.)/.test(s)); 37 | 38 | const wordRegExp = rubyScopes.length ? 39 | (nonWordCharacters = atom.config.get('editor.nonWordCharacters', {scope}), 40 | // Allow special handling for fully-qualified ruby constants 41 | nonWordCharacters = nonWordCharacters.replace(/:/g, ''), 42 | new RegExp(`[^\\s${_.escapeRegExp(nonWordCharacters)}]+([!?]|\\s*=>?)?|[<=>]+`, 'g')) 43 | : 44 | cursor.wordRegExp(); 45 | 46 | const addSymbol = (symbol) => { 47 | if (rubyScopes.length) { 48 | // Normalize assignment syntax 49 | if (/\s+=?$/.test(symbol)) { symbols.push(symbol.replace(/\s+=$/, '=')); } 50 | // Strip away assignment & hashrocket syntax 51 | symbols.push(symbol.replace(/\s+=>?$/, '')); 52 | } else { 53 | symbols.push(symbol); 54 | } 55 | }; 56 | 57 | // Can't use `getCurrentWordBufferRange` here because we want to select 58 | // the last match of the potential 2 matches under cursor. 59 | editor.scanInBufferRange(wordRegExp, cursor.getCurrentLineBufferRange(), ({range, match}) => { 60 | if (range.containsPoint(cursorPosition)) { 61 | symbol = match[0]; 62 | if (rubyScopes.length && symbol.indexOf(':') > -1) { 63 | const cursorWithinSymbol = cursorPosition.column - range.start.column; 64 | // Add fully-qualified ruby constant up until the cursor position 65 | addSymbol(wordAtCursor(symbol, cursorWithinSymbol, ':', true)); 66 | // Additionally, also look up the bare word under cursor 67 | addSymbol(wordAtCursor(symbol, cursorWithinSymbol, ':')); 68 | } else { 69 | addSymbol(symbol); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | if (!symbols.length) { 76 | process.nextTick(() => { 77 | callback(null, []); 78 | }); 79 | } 80 | 81 | async.map(atom.project.getPaths(), (projectPath, done) => { 82 | const tagsFile = getTagsFile(projectPath); 83 | let foundTags = []; 84 | let foundErr = null; 85 | const detectCallback = () => { 86 | done(foundErr, foundTags); 87 | }; 88 | if (!tagsFile) { 89 | return detectCallback(); 90 | } 91 | // Find the first symbol in the list that matches a tag 92 | return async.detectSeries(symbols, (symbol, doneDetect) => { 93 | ctags.findTags(tagsFile, symbol, (err, tags) => { 94 | if (!tags) { 95 | tags = []; 96 | } 97 | if (err) { 98 | foundErr = err; 99 | doneDetect(false); 100 | } else if (tags.length) { 101 | for (const tag of Array.from(tags)) { 102 | tag.directory = projectPath; 103 | } 104 | foundTags = tags; 105 | doneDetect(true); 106 | } else { 107 | doneDetect(false); 108 | } 109 | }); 110 | }, detectCallback); 111 | }, (err, foundTags) => { 112 | callback(err, _.flatten(foundTags)); 113 | }); 114 | }, 115 | 116 | getAllTags(callback) { 117 | const projectTags = []; 118 | const task = Task.once(handlerPath, atom.project.getPaths(), () => callback(projectTags)); 119 | task.on('tags', (tags) => { 120 | projectTags.push(...tags); 121 | }); 122 | return task; 123 | }, 124 | }; 125 | -------------------------------------------------------------------------------- /menus/symbols-view.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 3 | 'label': 'Packages' 4 | 'submenu': [ 5 | 'label': 'Symbols' 6 | 'submenu': [ 7 | { 'label': 'File Symbols', 'command': 'symbols-view:toggle-file-symbols' } 8 | { 'label': 'Project Symbols', 'command': 'symbols-view:toggle-project-symbols' } 9 | ] 10 | ] 11 | } 12 | ] 13 | 14 | 'context-menu': 15 | 'atom-text-editor:not([mini])': [ 16 | { 'label': 'Go to Declaration', 'command': 'symbols-view:go-to-declaration' } 17 | ] 18 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symbols-view", 3 | "version": "0.118.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "acorn": { 8 | "version": "5.7.3", 9 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", 10 | "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", 11 | "dev": true 12 | }, 13 | "acorn-jsx": { 14 | "version": "3.0.1", 15 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", 16 | "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", 17 | "dev": true, 18 | "requires": { 19 | "acorn": "^3.0.4" 20 | }, 21 | "dependencies": { 22 | "acorn": { 23 | "version": "3.3.0", 24 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", 25 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", 26 | "dev": true 27 | } 28 | } 29 | }, 30 | "ajv": { 31 | "version": "4.11.8", 32 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 33 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 34 | "dev": true, 35 | "requires": { 36 | "co": "^4.6.0", 37 | "json-stable-stringify": "^1.0.1" 38 | } 39 | }, 40 | "ajv-keywords": { 41 | "version": "1.5.1", 42 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", 43 | "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", 44 | "dev": true 45 | }, 46 | "ansi-escapes": { 47 | "version": "1.4.0", 48 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", 49 | "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", 50 | "dev": true 51 | }, 52 | "ansi-regex": { 53 | "version": "2.1.1", 54 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 55 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 56 | "dev": true 57 | }, 58 | "ansi-styles": { 59 | "version": "2.2.1", 60 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 61 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 62 | "dev": true 63 | }, 64 | "argparse": { 65 | "version": "1.0.10", 66 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 67 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 68 | "dev": true, 69 | "requires": { 70 | "sprintf-js": "~1.0.2" 71 | } 72 | }, 73 | "async": { 74 | "version": "0.2.10", 75 | "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", 76 | "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" 77 | }, 78 | "atom-select-list": { 79 | "version": "0.7.2", 80 | "resolved": "https://registry.npmjs.org/atom-select-list/-/atom-select-list-0.7.2.tgz", 81 | "integrity": "sha512-a707OB1DhLGjzqtFrtMQKH7BBxFuCh8UBoUWxgFOrLrSwVh3g+/TlVPVDOz12+U0mDu3mIrnYLqQyhywQOTxhw==", 82 | "requires": { 83 | "etch": "^0.12.6", 84 | "fuzzaldrin": "^2.1.0" 85 | } 86 | }, 87 | "babel-code-frame": { 88 | "version": "6.26.0", 89 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 90 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 91 | "dev": true, 92 | "requires": { 93 | "chalk": "^1.1.3", 94 | "esutils": "^2.0.2", 95 | "js-tokens": "^3.0.2" 96 | } 97 | }, 98 | "babel-eslint": { 99 | "version": "6.1.2", 100 | "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz", 101 | "integrity": "sha1-UpNBn+NnLWZZjTJ9qWlFZ7pqXy8=", 102 | "dev": true, 103 | "requires": { 104 | "babel-traverse": "^6.0.20", 105 | "babel-types": "^6.0.19", 106 | "babylon": "^6.0.18", 107 | "lodash.assign": "^4.0.0", 108 | "lodash.pickby": "^4.0.0" 109 | } 110 | }, 111 | "babel-messages": { 112 | "version": "6.23.0", 113 | "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", 114 | "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", 115 | "dev": true, 116 | "requires": { 117 | "babel-runtime": "^6.22.0" 118 | } 119 | }, 120 | "babel-runtime": { 121 | "version": "6.26.0", 122 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 123 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 124 | "dev": true, 125 | "requires": { 126 | "core-js": "^2.4.0", 127 | "regenerator-runtime": "^0.11.0" 128 | } 129 | }, 130 | "babel-traverse": { 131 | "version": "6.26.0", 132 | "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", 133 | "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", 134 | "dev": true, 135 | "requires": { 136 | "babel-code-frame": "^6.26.0", 137 | "babel-messages": "^6.23.0", 138 | "babel-runtime": "^6.26.0", 139 | "babel-types": "^6.26.0", 140 | "babylon": "^6.18.0", 141 | "debug": "^2.6.8", 142 | "globals": "^9.18.0", 143 | "invariant": "^2.2.2", 144 | "lodash": "^4.17.4" 145 | } 146 | }, 147 | "babel-types": { 148 | "version": "6.26.0", 149 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 150 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 151 | "dev": true, 152 | "requires": { 153 | "babel-runtime": "^6.26.0", 154 | "esutils": "^2.0.2", 155 | "lodash": "^4.17.4", 156 | "to-fast-properties": "^1.0.3" 157 | } 158 | }, 159 | "babylon": { 160 | "version": "6.18.0", 161 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 162 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", 163 | "dev": true 164 | }, 165 | "balanced-match": { 166 | "version": "1.0.0", 167 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 168 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 169 | }, 170 | "brace-expansion": { 171 | "version": "1.1.11", 172 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 173 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 174 | "requires": { 175 | "balanced-match": "^1.0.0", 176 | "concat-map": "0.0.1" 177 | } 178 | }, 179 | "buffer-from": { 180 | "version": "1.1.1", 181 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 182 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 183 | "dev": true 184 | }, 185 | "caller-path": { 186 | "version": "0.1.0", 187 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", 188 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", 189 | "dev": true, 190 | "requires": { 191 | "callsites": "^0.2.0" 192 | } 193 | }, 194 | "callsites": { 195 | "version": "0.2.0", 196 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", 197 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", 198 | "dev": true 199 | }, 200 | "chalk": { 201 | "version": "1.1.3", 202 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 203 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 204 | "dev": true, 205 | "requires": { 206 | "ansi-styles": "^2.2.1", 207 | "escape-string-regexp": "^1.0.2", 208 | "has-ansi": "^2.0.0", 209 | "strip-ansi": "^3.0.0", 210 | "supports-color": "^2.0.0" 211 | } 212 | }, 213 | "circular-json": { 214 | "version": "0.3.3", 215 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", 216 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", 217 | "dev": true 218 | }, 219 | "cli-cursor": { 220 | "version": "1.0.2", 221 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", 222 | "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", 223 | "dev": true, 224 | "requires": { 225 | "restore-cursor": "^1.0.1" 226 | } 227 | }, 228 | "cli-width": { 229 | "version": "2.2.0", 230 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 231 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 232 | "dev": true 233 | }, 234 | "co": { 235 | "version": "4.6.0", 236 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 237 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 238 | "dev": true 239 | }, 240 | "code-point-at": { 241 | "version": "1.1.0", 242 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 243 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 244 | "dev": true 245 | }, 246 | "concat-map": { 247 | "version": "0.0.1", 248 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 249 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 250 | }, 251 | "concat-stream": { 252 | "version": "1.6.2", 253 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 254 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 255 | "dev": true, 256 | "requires": { 257 | "buffer-from": "^1.0.0", 258 | "inherits": "^2.0.3", 259 | "readable-stream": "^2.2.2", 260 | "typedarray": "^0.0.6" 261 | } 262 | }, 263 | "core-js": { 264 | "version": "2.6.10", 265 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", 266 | "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", 267 | "dev": true 268 | }, 269 | "core-util-is": { 270 | "version": "1.0.2", 271 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 272 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 273 | "dev": true 274 | }, 275 | "ctags": { 276 | "version": "3.1.0", 277 | "resolved": "https://registry.npmjs.org/ctags/-/ctags-3.1.0.tgz", 278 | "integrity": "sha512-7/aiGLj8Ih7Ko3bAAg8bQUwHjOGXKQ7XC+bv+vLh84BtkVodPEOpOnr65FnWjX2oFWoKSaDuxe7jFHudD2Q0uw==", 279 | "requires": { 280 | "event-stream": "~3.1.0", 281 | "nan": "^2.14.0" 282 | } 283 | }, 284 | "d": { 285 | "version": "1.0.1", 286 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", 287 | "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", 288 | "dev": true, 289 | "requires": { 290 | "es5-ext": "^0.10.50", 291 | "type": "^1.0.1" 292 | } 293 | }, 294 | "debug": { 295 | "version": "2.6.9", 296 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 297 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 298 | "dev": true, 299 | "requires": { 300 | "ms": "2.0.0" 301 | } 302 | }, 303 | "deep-is": { 304 | "version": "0.1.3", 305 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 306 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 307 | "dev": true 308 | }, 309 | "doctrine": { 310 | "version": "2.1.0", 311 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 312 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 313 | "dev": true, 314 | "requires": { 315 | "esutils": "^2.0.2" 316 | } 317 | }, 318 | "duplexer": { 319 | "version": "0.1.1", 320 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 321 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" 322 | }, 323 | "es5-ext": { 324 | "version": "0.10.53", 325 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", 326 | "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", 327 | "dev": true, 328 | "requires": { 329 | "es6-iterator": "~2.0.3", 330 | "es6-symbol": "~3.1.3", 331 | "next-tick": "~1.0.0" 332 | } 333 | }, 334 | "es6-iterator": { 335 | "version": "2.0.3", 336 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 337 | "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", 338 | "dev": true, 339 | "requires": { 340 | "d": "1", 341 | "es5-ext": "^0.10.35", 342 | "es6-symbol": "^3.1.1" 343 | } 344 | }, 345 | "es6-map": { 346 | "version": "0.1.5", 347 | "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", 348 | "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", 349 | "dev": true, 350 | "requires": { 351 | "d": "1", 352 | "es5-ext": "~0.10.14", 353 | "es6-iterator": "~2.0.1", 354 | "es6-set": "~0.1.5", 355 | "es6-symbol": "~3.1.1", 356 | "event-emitter": "~0.3.5" 357 | } 358 | }, 359 | "es6-set": { 360 | "version": "0.1.5", 361 | "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", 362 | "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", 363 | "dev": true, 364 | "requires": { 365 | "d": "1", 366 | "es5-ext": "~0.10.14", 367 | "es6-iterator": "~2.0.1", 368 | "es6-symbol": "3.1.1", 369 | "event-emitter": "~0.3.5" 370 | }, 371 | "dependencies": { 372 | "es6-symbol": { 373 | "version": "3.1.1", 374 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", 375 | "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", 376 | "dev": true, 377 | "requires": { 378 | "d": "1", 379 | "es5-ext": "~0.10.14" 380 | } 381 | } 382 | } 383 | }, 384 | "es6-symbol": { 385 | "version": "3.1.3", 386 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", 387 | "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", 388 | "dev": true, 389 | "requires": { 390 | "d": "^1.0.1", 391 | "ext": "^1.1.2" 392 | } 393 | }, 394 | "es6-weak-map": { 395 | "version": "2.0.3", 396 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", 397 | "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", 398 | "dev": true, 399 | "requires": { 400 | "d": "1", 401 | "es5-ext": "^0.10.46", 402 | "es6-iterator": "^2.0.3", 403 | "es6-symbol": "^3.1.1" 404 | } 405 | }, 406 | "escape-string-regexp": { 407 | "version": "1.0.5", 408 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 409 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 410 | "dev": true 411 | }, 412 | "escope": { 413 | "version": "3.6.0", 414 | "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", 415 | "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", 416 | "dev": true, 417 | "requires": { 418 | "es6-map": "^0.1.3", 419 | "es6-weak-map": "^2.0.1", 420 | "esrecurse": "^4.1.0", 421 | "estraverse": "^4.1.1" 422 | } 423 | }, 424 | "eslint": { 425 | "version": "3.19.0", 426 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", 427 | "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", 428 | "dev": true, 429 | "requires": { 430 | "babel-code-frame": "^6.16.0", 431 | "chalk": "^1.1.3", 432 | "concat-stream": "^1.5.2", 433 | "debug": "^2.1.1", 434 | "doctrine": "^2.0.0", 435 | "escope": "^3.6.0", 436 | "espree": "^3.4.0", 437 | "esquery": "^1.0.0", 438 | "estraverse": "^4.2.0", 439 | "esutils": "^2.0.2", 440 | "file-entry-cache": "^2.0.0", 441 | "glob": "^7.0.3", 442 | "globals": "^9.14.0", 443 | "ignore": "^3.2.0", 444 | "imurmurhash": "^0.1.4", 445 | "inquirer": "^0.12.0", 446 | "is-my-json-valid": "^2.10.0", 447 | "is-resolvable": "^1.0.0", 448 | "js-yaml": "^3.5.1", 449 | "json-stable-stringify": "^1.0.0", 450 | "levn": "^0.3.0", 451 | "lodash": "^4.0.0", 452 | "mkdirp": "^0.5.0", 453 | "natural-compare": "^1.4.0", 454 | "optionator": "^0.8.2", 455 | "path-is-inside": "^1.0.1", 456 | "pluralize": "^1.2.1", 457 | "progress": "^1.1.8", 458 | "require-uncached": "^1.0.2", 459 | "shelljs": "^0.7.5", 460 | "strip-bom": "^3.0.0", 461 | "strip-json-comments": "~2.0.1", 462 | "table": "^3.7.8", 463 | "text-table": "~0.2.0", 464 | "user-home": "^2.0.0" 465 | } 466 | }, 467 | "eslint-config-fbjs": { 468 | "version": "1.1.1", 469 | "resolved": "https://registry.npmjs.org/eslint-config-fbjs/-/eslint-config-fbjs-1.1.1.tgz", 470 | "integrity": "sha1-3Sn42RLop1Ulfp7u8AuuHM5X9zo=", 471 | "dev": true 472 | }, 473 | "eslint-plugin-babel": { 474 | "version": "3.3.0", 475 | "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz", 476 | "integrity": "sha1-L0lK7c9vSqTnW5FVmAg3vB+94ZM=", 477 | "dev": true 478 | }, 479 | "eslint-plugin-flowtype": { 480 | "version": "2.50.3", 481 | "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.3.tgz", 482 | "integrity": "sha512-X+AoKVOr7Re0ko/yEXyM5SSZ0tazc6ffdIOocp2fFUlWoDt7DV0Bz99mngOkAFLOAWjqRA5jPwqUCbrx13XoxQ==", 483 | "dev": true, 484 | "requires": { 485 | "lodash": "^4.17.10" 486 | } 487 | }, 488 | "eslint-plugin-jasmine": { 489 | "version": "2.10.1", 490 | "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz", 491 | "integrity": "sha1-VzO3CedR9LxA4x4cFpib0s377Jc=", 492 | "dev": true 493 | }, 494 | "eslint-plugin-prefer-object-spread": { 495 | "version": "1.2.1", 496 | "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz", 497 | "integrity": "sha1-J/uRhTaQzOs65hAdnIrsxqZ6QCw=", 498 | "dev": true 499 | }, 500 | "eslint-plugin-react": { 501 | "version": "5.2.2", 502 | "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-5.2.2.tgz", 503 | "integrity": "sha1-fbBo4fVIf2hx5N7vNqOBwwPqwWE=", 504 | "dev": true, 505 | "requires": { 506 | "doctrine": "^1.2.2", 507 | "jsx-ast-utils": "^1.2.1" 508 | }, 509 | "dependencies": { 510 | "doctrine": { 511 | "version": "1.5.0", 512 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 513 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 514 | "dev": true, 515 | "requires": { 516 | "esutils": "^2.0.2", 517 | "isarray": "^1.0.0" 518 | } 519 | } 520 | } 521 | }, 522 | "espree": { 523 | "version": "3.5.4", 524 | "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", 525 | "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", 526 | "dev": true, 527 | "requires": { 528 | "acorn": "^5.5.0", 529 | "acorn-jsx": "^3.0.0" 530 | } 531 | }, 532 | "esprima": { 533 | "version": "4.0.1", 534 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 535 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 536 | "dev": true 537 | }, 538 | "esquery": { 539 | "version": "1.0.1", 540 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 541 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 542 | "dev": true, 543 | "requires": { 544 | "estraverse": "^4.0.0" 545 | } 546 | }, 547 | "esrecurse": { 548 | "version": "4.2.1", 549 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 550 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 551 | "dev": true, 552 | "requires": { 553 | "estraverse": "^4.1.0" 554 | } 555 | }, 556 | "estraverse": { 557 | "version": "4.3.0", 558 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 559 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 560 | "dev": true 561 | }, 562 | "esutils": { 563 | "version": "2.0.3", 564 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 565 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 566 | "dev": true 567 | }, 568 | "etch": { 569 | "version": "0.12.8", 570 | "resolved": "https://registry.npmjs.org/etch/-/etch-0.12.8.tgz", 571 | "integrity": "sha512-dFLRe4wLroVtwzyy1vGlE3BSDZHiL0kZME5XgNGzZIULcYTvVno8vbiIleAesoKJmwWaxDTzG+4eppg2zk14JQ==" 572 | }, 573 | "event-emitter": { 574 | "version": "0.3.5", 575 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 576 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", 577 | "dev": true, 578 | "requires": { 579 | "d": "1", 580 | "es5-ext": "~0.10.14" 581 | } 582 | }, 583 | "event-stream": { 584 | "version": "3.1.7", 585 | "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.1.7.tgz", 586 | "integrity": "sha1-tMVAAS0P4UmEIPPYlGAI22OTw3o=", 587 | "requires": { 588 | "duplexer": "~0.1.1", 589 | "from": "~0", 590 | "map-stream": "~0.1.0", 591 | "pause-stream": "0.0.11", 592 | "split": "0.2", 593 | "stream-combiner": "~0.0.4", 594 | "through": "~2.3.1" 595 | } 596 | }, 597 | "exit-hook": { 598 | "version": "1.1.1", 599 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", 600 | "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", 601 | "dev": true 602 | }, 603 | "ext": { 604 | "version": "1.4.0", 605 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", 606 | "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", 607 | "dev": true, 608 | "requires": { 609 | "type": "^2.0.0" 610 | }, 611 | "dependencies": { 612 | "type": { 613 | "version": "2.0.0", 614 | "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", 615 | "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", 616 | "dev": true 617 | } 618 | } 619 | }, 620 | "fast-levenshtein": { 621 | "version": "2.0.6", 622 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 623 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 624 | "dev": true 625 | }, 626 | "figures": { 627 | "version": "1.7.0", 628 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", 629 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", 630 | "dev": true, 631 | "requires": { 632 | "escape-string-regexp": "^1.0.5", 633 | "object-assign": "^4.1.0" 634 | } 635 | }, 636 | "file-entry-cache": { 637 | "version": "2.0.0", 638 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", 639 | "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", 640 | "dev": true, 641 | "requires": { 642 | "flat-cache": "^1.2.1", 643 | "object-assign": "^4.0.1" 644 | } 645 | }, 646 | "flat-cache": { 647 | "version": "1.3.4", 648 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", 649 | "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", 650 | "dev": true, 651 | "requires": { 652 | "circular-json": "^0.3.1", 653 | "graceful-fs": "^4.1.2", 654 | "rimraf": "~2.6.2", 655 | "write": "^0.2.1" 656 | }, 657 | "dependencies": { 658 | "rimraf": { 659 | "version": "2.6.3", 660 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 661 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 662 | "dev": true, 663 | "requires": { 664 | "glob": "^7.1.3" 665 | } 666 | } 667 | } 668 | }, 669 | "from": { 670 | "version": "0.1.7", 671 | "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", 672 | "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" 673 | }, 674 | "fs-plus": { 675 | "version": "3.1.1", 676 | "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", 677 | "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", 678 | "requires": { 679 | "async": "^1.5.2", 680 | "mkdirp": "^0.5.1", 681 | "rimraf": "^2.5.2", 682 | "underscore-plus": "1.x" 683 | }, 684 | "dependencies": { 685 | "async": { 686 | "version": "1.5.2", 687 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 688 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" 689 | } 690 | } 691 | }, 692 | "fs.realpath": { 693 | "version": "1.0.0", 694 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 695 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 696 | }, 697 | "fuzzaldrin": { 698 | "version": "2.1.0", 699 | "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", 700 | "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=" 701 | }, 702 | "generate-function": { 703 | "version": "2.3.1", 704 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 705 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 706 | "dev": true, 707 | "requires": { 708 | "is-property": "^1.0.2" 709 | } 710 | }, 711 | "generate-object-property": { 712 | "version": "1.2.0", 713 | "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", 714 | "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", 715 | "dev": true, 716 | "requires": { 717 | "is-property": "^1.0.0" 718 | } 719 | }, 720 | "glob": { 721 | "version": "7.1.6", 722 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 723 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 724 | "requires": { 725 | "fs.realpath": "^1.0.0", 726 | "inflight": "^1.0.4", 727 | "inherits": "2", 728 | "minimatch": "^3.0.4", 729 | "once": "^1.3.0", 730 | "path-is-absolute": "^1.0.0" 731 | } 732 | }, 733 | "globals": { 734 | "version": "9.18.0", 735 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 736 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 737 | "dev": true 738 | }, 739 | "graceful-fs": { 740 | "version": "4.2.3", 741 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 742 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", 743 | "dev": true 744 | }, 745 | "has-ansi": { 746 | "version": "2.0.0", 747 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 748 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 749 | "dev": true, 750 | "requires": { 751 | "ansi-regex": "^2.0.0" 752 | } 753 | }, 754 | "humanize-plus": { 755 | "version": "1.8.2", 756 | "resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz", 757 | "integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=" 758 | }, 759 | "ignore": { 760 | "version": "3.3.10", 761 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", 762 | "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", 763 | "dev": true 764 | }, 765 | "imurmurhash": { 766 | "version": "0.1.4", 767 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 768 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 769 | "dev": true 770 | }, 771 | "inflight": { 772 | "version": "1.0.6", 773 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 774 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 775 | "requires": { 776 | "once": "^1.3.0", 777 | "wrappy": "1" 778 | } 779 | }, 780 | "inherits": { 781 | "version": "2.0.4", 782 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 783 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 784 | }, 785 | "inquirer": { 786 | "version": "0.12.0", 787 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", 788 | "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", 789 | "dev": true, 790 | "requires": { 791 | "ansi-escapes": "^1.1.0", 792 | "ansi-regex": "^2.0.0", 793 | "chalk": "^1.0.0", 794 | "cli-cursor": "^1.0.1", 795 | "cli-width": "^2.0.0", 796 | "figures": "^1.3.5", 797 | "lodash": "^4.3.0", 798 | "readline2": "^1.0.1", 799 | "run-async": "^0.1.0", 800 | "rx-lite": "^3.1.2", 801 | "string-width": "^1.0.1", 802 | "strip-ansi": "^3.0.0", 803 | "through": "^2.3.6" 804 | } 805 | }, 806 | "interpret": { 807 | "version": "1.2.0", 808 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", 809 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", 810 | "dev": true 811 | }, 812 | "invariant": { 813 | "version": "2.2.4", 814 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", 815 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", 816 | "dev": true, 817 | "requires": { 818 | "loose-envify": "^1.0.0" 819 | } 820 | }, 821 | "is-fullwidth-code-point": { 822 | "version": "1.0.0", 823 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 824 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 825 | "dev": true, 826 | "requires": { 827 | "number-is-nan": "^1.0.0" 828 | } 829 | }, 830 | "is-my-ip-valid": { 831 | "version": "1.0.0", 832 | "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", 833 | "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", 834 | "dev": true 835 | }, 836 | "is-my-json-valid": { 837 | "version": "2.20.0", 838 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", 839 | "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", 840 | "dev": true, 841 | "requires": { 842 | "generate-function": "^2.0.0", 843 | "generate-object-property": "^1.1.0", 844 | "is-my-ip-valid": "^1.0.0", 845 | "jsonpointer": "^4.0.0", 846 | "xtend": "^4.0.0" 847 | } 848 | }, 849 | "is-property": { 850 | "version": "1.0.2", 851 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 852 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", 853 | "dev": true 854 | }, 855 | "is-resolvable": { 856 | "version": "1.1.0", 857 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", 858 | "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", 859 | "dev": true 860 | }, 861 | "isarray": { 862 | "version": "1.0.0", 863 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 864 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 865 | "dev": true 866 | }, 867 | "js-tokens": { 868 | "version": "3.0.2", 869 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 870 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 871 | "dev": true 872 | }, 873 | "js-yaml": { 874 | "version": "3.13.1", 875 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 876 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 877 | "dev": true, 878 | "requires": { 879 | "argparse": "^1.0.7", 880 | "esprima": "^4.0.0" 881 | } 882 | }, 883 | "json-stable-stringify": { 884 | "version": "1.0.1", 885 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 886 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 887 | "dev": true, 888 | "requires": { 889 | "jsonify": "~0.0.0" 890 | } 891 | }, 892 | "jsonify": { 893 | "version": "0.0.0", 894 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 895 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 896 | "dev": true 897 | }, 898 | "jsonpointer": { 899 | "version": "4.0.1", 900 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", 901 | "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", 902 | "dev": true 903 | }, 904 | "jsx-ast-utils": { 905 | "version": "1.4.1", 906 | "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", 907 | "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", 908 | "dev": true 909 | }, 910 | "levn": { 911 | "version": "0.3.0", 912 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 913 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 914 | "dev": true, 915 | "requires": { 916 | "prelude-ls": "~1.1.2", 917 | "type-check": "~0.3.2" 918 | } 919 | }, 920 | "lodash": { 921 | "version": "4.17.15", 922 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 923 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 924 | "dev": true 925 | }, 926 | "lodash.assign": { 927 | "version": "4.2.0", 928 | "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", 929 | "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", 930 | "dev": true 931 | }, 932 | "lodash.pickby": { 933 | "version": "4.6.0", 934 | "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", 935 | "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", 936 | "dev": true 937 | }, 938 | "loose-envify": { 939 | "version": "1.4.0", 940 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 941 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 942 | "dev": true, 943 | "requires": { 944 | "js-tokens": "^3.0.0 || ^4.0.0" 945 | } 946 | }, 947 | "map-stream": { 948 | "version": "0.1.0", 949 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", 950 | "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" 951 | }, 952 | "minimatch": { 953 | "version": "3.0.4", 954 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 955 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 956 | "requires": { 957 | "brace-expansion": "^1.1.7" 958 | } 959 | }, 960 | "minimist": { 961 | "version": "0.0.8", 962 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 963 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 964 | }, 965 | "mkdirp": { 966 | "version": "0.5.1", 967 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 968 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 969 | "requires": { 970 | "minimist": "0.0.8" 971 | } 972 | }, 973 | "ms": { 974 | "version": "2.0.0", 975 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 976 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 977 | "dev": true 978 | }, 979 | "mute-stream": { 980 | "version": "0.0.5", 981 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", 982 | "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", 983 | "dev": true 984 | }, 985 | "nan": { 986 | "version": "2.14.0", 987 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 988 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 989 | }, 990 | "natural-compare": { 991 | "version": "1.4.0", 992 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 993 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 994 | "dev": true 995 | }, 996 | "next-tick": { 997 | "version": "1.0.0", 998 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", 999 | "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", 1000 | "dev": true 1001 | }, 1002 | "number-is-nan": { 1003 | "version": "1.0.1", 1004 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1005 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1006 | "dev": true 1007 | }, 1008 | "object-assign": { 1009 | "version": "4.1.1", 1010 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1011 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1012 | "dev": true 1013 | }, 1014 | "once": { 1015 | "version": "1.4.0", 1016 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1017 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1018 | "requires": { 1019 | "wrappy": "1" 1020 | } 1021 | }, 1022 | "onetime": { 1023 | "version": "1.1.0", 1024 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", 1025 | "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", 1026 | "dev": true 1027 | }, 1028 | "optionator": { 1029 | "version": "0.8.3", 1030 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 1031 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 1032 | "dev": true, 1033 | "requires": { 1034 | "deep-is": "~0.1.3", 1035 | "fast-levenshtein": "~2.0.6", 1036 | "levn": "~0.3.0", 1037 | "prelude-ls": "~1.1.2", 1038 | "type-check": "~0.3.2", 1039 | "word-wrap": "~1.2.3" 1040 | } 1041 | }, 1042 | "os-homedir": { 1043 | "version": "1.0.2", 1044 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1045 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1046 | "dev": true 1047 | }, 1048 | "path-is-absolute": { 1049 | "version": "1.0.1", 1050 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1051 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1052 | }, 1053 | "path-is-inside": { 1054 | "version": "1.0.2", 1055 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1056 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1057 | "dev": true 1058 | }, 1059 | "path-parse": { 1060 | "version": "1.0.6", 1061 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1062 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1063 | "dev": true 1064 | }, 1065 | "pause-stream": { 1066 | "version": "0.0.11", 1067 | "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", 1068 | "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", 1069 | "requires": { 1070 | "through": "~2.3" 1071 | } 1072 | }, 1073 | "pluralize": { 1074 | "version": "1.2.1", 1075 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", 1076 | "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", 1077 | "dev": true 1078 | }, 1079 | "prelude-ls": { 1080 | "version": "1.1.2", 1081 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1082 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1083 | "dev": true 1084 | }, 1085 | "process-nextick-args": { 1086 | "version": "2.0.1", 1087 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1088 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 1089 | "dev": true 1090 | }, 1091 | "progress": { 1092 | "version": "1.1.8", 1093 | "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", 1094 | "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", 1095 | "dev": true 1096 | }, 1097 | "readable-stream": { 1098 | "version": "2.3.6", 1099 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1100 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1101 | "dev": true, 1102 | "requires": { 1103 | "core-util-is": "~1.0.0", 1104 | "inherits": "~2.0.3", 1105 | "isarray": "~1.0.0", 1106 | "process-nextick-args": "~2.0.0", 1107 | "safe-buffer": "~5.1.1", 1108 | "string_decoder": "~1.1.1", 1109 | "util-deprecate": "~1.0.1" 1110 | } 1111 | }, 1112 | "readline2": { 1113 | "version": "1.0.1", 1114 | "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", 1115 | "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", 1116 | "dev": true, 1117 | "requires": { 1118 | "code-point-at": "^1.0.0", 1119 | "is-fullwidth-code-point": "^1.0.0", 1120 | "mute-stream": "0.0.5" 1121 | } 1122 | }, 1123 | "rechoir": { 1124 | "version": "0.6.2", 1125 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 1126 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 1127 | "dev": true, 1128 | "requires": { 1129 | "resolve": "^1.1.6" 1130 | } 1131 | }, 1132 | "regenerator-runtime": { 1133 | "version": "0.11.1", 1134 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 1135 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", 1136 | "dev": true 1137 | }, 1138 | "require-uncached": { 1139 | "version": "1.0.3", 1140 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", 1141 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", 1142 | "dev": true, 1143 | "requires": { 1144 | "caller-path": "^0.1.0", 1145 | "resolve-from": "^1.0.0" 1146 | } 1147 | }, 1148 | "resolve": { 1149 | "version": "1.13.1", 1150 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", 1151 | "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", 1152 | "dev": true, 1153 | "requires": { 1154 | "path-parse": "^1.0.6" 1155 | } 1156 | }, 1157 | "resolve-from": { 1158 | "version": "1.0.1", 1159 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", 1160 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", 1161 | "dev": true 1162 | }, 1163 | "restore-cursor": { 1164 | "version": "1.0.1", 1165 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", 1166 | "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", 1167 | "dev": true, 1168 | "requires": { 1169 | "exit-hook": "^1.0.0", 1170 | "onetime": "^1.0.0" 1171 | } 1172 | }, 1173 | "rimraf": { 1174 | "version": "2.7.1", 1175 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1176 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1177 | "requires": { 1178 | "glob": "^7.1.3" 1179 | } 1180 | }, 1181 | "run-async": { 1182 | "version": "0.1.0", 1183 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", 1184 | "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", 1185 | "dev": true, 1186 | "requires": { 1187 | "once": "^1.3.0" 1188 | } 1189 | }, 1190 | "rx-lite": { 1191 | "version": "3.1.2", 1192 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", 1193 | "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", 1194 | "dev": true 1195 | }, 1196 | "safe-buffer": { 1197 | "version": "5.1.2", 1198 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1199 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1200 | "dev": true 1201 | }, 1202 | "shelljs": { 1203 | "version": "0.7.8", 1204 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", 1205 | "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", 1206 | "dev": true, 1207 | "requires": { 1208 | "glob": "^7.0.0", 1209 | "interpret": "^1.0.0", 1210 | "rechoir": "^0.6.2" 1211 | } 1212 | }, 1213 | "slice-ansi": { 1214 | "version": "0.0.4", 1215 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", 1216 | "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", 1217 | "dev": true 1218 | }, 1219 | "split": { 1220 | "version": "0.2.10", 1221 | "resolved": "https://registry.npmjs.org/split/-/split-0.2.10.tgz", 1222 | "integrity": "sha1-Zwl8YB1pfOE2j0GPBs0gHPBSGlc=", 1223 | "requires": { 1224 | "through": "2" 1225 | } 1226 | }, 1227 | "sprintf-js": { 1228 | "version": "1.0.3", 1229 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1230 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1231 | "dev": true 1232 | }, 1233 | "stream-combiner": { 1234 | "version": "0.0.4", 1235 | "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", 1236 | "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", 1237 | "requires": { 1238 | "duplexer": "~0.1.1" 1239 | } 1240 | }, 1241 | "string-width": { 1242 | "version": "1.0.2", 1243 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1244 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1245 | "dev": true, 1246 | "requires": { 1247 | "code-point-at": "^1.0.0", 1248 | "is-fullwidth-code-point": "^1.0.0", 1249 | "strip-ansi": "^3.0.0" 1250 | } 1251 | }, 1252 | "string_decoder": { 1253 | "version": "1.1.1", 1254 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1255 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1256 | "dev": true, 1257 | "requires": { 1258 | "safe-buffer": "~5.1.0" 1259 | } 1260 | }, 1261 | "strip-ansi": { 1262 | "version": "3.0.1", 1263 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1264 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1265 | "dev": true, 1266 | "requires": { 1267 | "ansi-regex": "^2.0.0" 1268 | } 1269 | }, 1270 | "strip-bom": { 1271 | "version": "3.0.0", 1272 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1273 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1274 | "dev": true 1275 | }, 1276 | "strip-json-comments": { 1277 | "version": "2.0.1", 1278 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1279 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1280 | "dev": true 1281 | }, 1282 | "supports-color": { 1283 | "version": "2.0.0", 1284 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1285 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1286 | "dev": true 1287 | }, 1288 | "table": { 1289 | "version": "3.8.3", 1290 | "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", 1291 | "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", 1292 | "dev": true, 1293 | "requires": { 1294 | "ajv": "^4.7.0", 1295 | "ajv-keywords": "^1.0.0", 1296 | "chalk": "^1.1.1", 1297 | "lodash": "^4.0.0", 1298 | "slice-ansi": "0.0.4", 1299 | "string-width": "^2.0.0" 1300 | }, 1301 | "dependencies": { 1302 | "ansi-regex": { 1303 | "version": "3.0.0", 1304 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1305 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1306 | "dev": true 1307 | }, 1308 | "is-fullwidth-code-point": { 1309 | "version": "2.0.0", 1310 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1311 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1312 | "dev": true 1313 | }, 1314 | "string-width": { 1315 | "version": "2.1.1", 1316 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1317 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1318 | "dev": true, 1319 | "requires": { 1320 | "is-fullwidth-code-point": "^2.0.0", 1321 | "strip-ansi": "^4.0.0" 1322 | } 1323 | }, 1324 | "strip-ansi": { 1325 | "version": "4.0.0", 1326 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1327 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1328 | "dev": true, 1329 | "requires": { 1330 | "ansi-regex": "^3.0.0" 1331 | } 1332 | } 1333 | } 1334 | }, 1335 | "temp": { 1336 | "version": "0.8.4", 1337 | "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", 1338 | "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", 1339 | "requires": { 1340 | "rimraf": "~2.6.2" 1341 | }, 1342 | "dependencies": { 1343 | "rimraf": { 1344 | "version": "2.6.3", 1345 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1346 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1347 | "requires": { 1348 | "glob": "^7.1.3" 1349 | } 1350 | } 1351 | } 1352 | }, 1353 | "text-table": { 1354 | "version": "0.2.0", 1355 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1356 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1357 | "dev": true 1358 | }, 1359 | "through": { 1360 | "version": "2.3.8", 1361 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1362 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 1363 | }, 1364 | "to-fast-properties": { 1365 | "version": "1.0.3", 1366 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 1367 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", 1368 | "dev": true 1369 | }, 1370 | "type": { 1371 | "version": "1.2.0", 1372 | "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", 1373 | "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", 1374 | "dev": true 1375 | }, 1376 | "type-check": { 1377 | "version": "0.3.2", 1378 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1379 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1380 | "dev": true, 1381 | "requires": { 1382 | "prelude-ls": "~1.1.2" 1383 | } 1384 | }, 1385 | "typedarray": { 1386 | "version": "0.0.6", 1387 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1388 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1389 | "dev": true 1390 | }, 1391 | "underscore": { 1392 | "version": "1.9.1", 1393 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", 1394 | "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" 1395 | }, 1396 | "underscore-plus": { 1397 | "version": "1.7.0", 1398 | "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", 1399 | "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", 1400 | "requires": { 1401 | "underscore": "^1.9.1" 1402 | } 1403 | }, 1404 | "user-home": { 1405 | "version": "2.0.0", 1406 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", 1407 | "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", 1408 | "dev": true, 1409 | "requires": { 1410 | "os-homedir": "^1.0.0" 1411 | } 1412 | }, 1413 | "util-deprecate": { 1414 | "version": "1.0.2", 1415 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1416 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1417 | "dev": true 1418 | }, 1419 | "word-wrap": { 1420 | "version": "1.2.3", 1421 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1422 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1423 | "dev": true 1424 | }, 1425 | "wrappy": { 1426 | "version": "1.0.2", 1427 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1428 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1429 | }, 1430 | "write": { 1431 | "version": "0.2.1", 1432 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", 1433 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", 1434 | "dev": true, 1435 | "requires": { 1436 | "mkdirp": "^0.5.1" 1437 | } 1438 | }, 1439 | "xtend": { 1440 | "version": "4.0.2", 1441 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1442 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1443 | "dev": true 1444 | } 1445 | } 1446 | } 1447 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symbols-view", 3 | "version": "0.118.4", 4 | "main": "./lib/main", 5 | "description": "Jump to a function/method in the current editor with `cmd-r`.", 6 | "license": "MIT", 7 | "activationCommands": { 8 | "atom-workspace": [ 9 | "symbols-view:toggle-project-symbols" 10 | ], 11 | "atom-text-editor": [ 12 | "symbols-view:go-to-declaration", 13 | "symbols-view:return-from-declaration", 14 | "symbols-view:toggle-file-symbols" 15 | ] 16 | }, 17 | "dependencies": { 18 | "async": "^0.2.6", 19 | "atom-select-list": "^0.7.0", 20 | "ctags": "^3.1.0", 21 | "fs-plus": "^3.0.0", 22 | "fuzzaldrin": "^2.1.0", 23 | "humanize-plus": "^1.8.2", 24 | "temp": "^0.8.3", 25 | "underscore-plus": "^1.6.6" 26 | }, 27 | "configSchema": { 28 | "useEditorGrammarAsCtagsLanguage": { 29 | "default": true, 30 | "type": "boolean", 31 | "description": "Force ctags to use the name of the current file's language in Atom when generating tags. By default, ctags automatically selects the language of a source file, ignoring those files whose language cannot be determined. This option forces the specified language to be used instead of automatically selecting the language based upon its extension." 32 | }, 33 | "quickJumpToFileSymbol": { 34 | "default": true, 35 | "type": "boolean", 36 | "description": "Automatically visit selected file-symbols" 37 | } 38 | }, 39 | "repository": "https://github.com/atom/symbols-view", 40 | "engines": { 41 | "atom": "*" 42 | }, 43 | "devDependencies": { 44 | "babel-eslint": "^6.1.2", 45 | "eslint": "^3.12.2", 46 | "eslint-config-fbjs": "^1.1.1", 47 | "eslint-plugin-babel": "^3.3.0", 48 | "eslint-plugin-flowtype": "^2.29.1", 49 | "eslint-plugin-jasmine": "^2.2.0", 50 | "eslint-plugin-prefer-object-spread": "^1.1.0", 51 | "eslint-plugin-react": "^5.2.2" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /spec/async-spec-helpers.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | 3 | export function beforeEach(fn) { 4 | global.beforeEach(function() { 5 | const result = fn(); 6 | if (result instanceof Promise) { 7 | waitsForPromise(() => result); 8 | } 9 | }); 10 | } 11 | 12 | export function afterEach(fn) { 13 | global.afterEach(function() { 14 | const result = fn(); 15 | if (result instanceof Promise) { 16 | waitsForPromise(() => result); 17 | } 18 | }); 19 | } 20 | 21 | ['it', 'fit', 'ffit', 'fffit'].forEach(function(name) { 22 | module.exports[name] = function(description, fn) { 23 | global[name](description, function() { 24 | const result = fn(); 25 | if (result instanceof Promise) { 26 | waitsForPromise(() => result); 27 | } 28 | }); 29 | }; 30 | }); 31 | 32 | export async function conditionPromise(condition) { 33 | const startTime = Date.now(); 34 | 35 | while (true) { 36 | await timeoutPromise(100); 37 | 38 | let conditionResult = condition(); 39 | if (condition instanceof Promise) { 40 | conditionResult = await conditionResult; 41 | } 42 | 43 | if (conditionResult) { 44 | return; 45 | } 46 | 47 | if (Date.now() - startTime > 5000) { 48 | throw new Error('Timed out waiting on condition'); 49 | } 50 | } 51 | } 52 | 53 | export function timeoutPromise(timeout) { 54 | return new Promise(function(resolve) { 55 | global.setTimeout(resolve, timeout); 56 | }); 57 | } 58 | 59 | function waitsForPromise(fn) { 60 | const promise = fn(); 61 | global.waitsFor('spec promise to resolve', function(done) { 62 | promise.then(done, function(error) { 63 | jasmine.getEnv().currentSpec.fail(error); 64 | done(); 65 | }); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /spec/fixtures/c/sample.c: -------------------------------------------------------------------------------- 1 | #define UNUSED(x) (void)(x) 2 | 3 | static void f(int x) 4 | { 5 | UNUSED(x); 6 | } 7 | -------------------------------------------------------------------------------- /spec/fixtures/c/tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.9~svn20110310 // 7 | UNUSED sample.c 1;" d file: 8 | f sample.c /^static void f(int x)$/;" f file: 9 | -------------------------------------------------------------------------------- /spec/fixtures/js/sample.js: -------------------------------------------------------------------------------- 1 | var quicksort = function () { 2 | var sort = function(items) { 3 | if (items.length <= 1) return items; 4 | var pivot = items.shift(), current, left = [], right = []; 5 | while(items.length > 0) { 6 | current = items.shift(); 7 | current < pivot ? left.push(current) : right.push(current); 8 | } 9 | return sort(left).concat(pivot).concat(sort(right)); 10 | }; 11 | 12 | return sort(Array.apply(this, arguments)); 13 | }; -------------------------------------------------------------------------------- /spec/fixtures/js/tagged-duplicate.js: -------------------------------------------------------------------------------- 1 | function duplicate() { 2 | return false; 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/js/tagged.js: -------------------------------------------------------------------------------- 1 | var thisIsCrazy = true; 2 | 3 | function callMeMaybe() { 4 | return "here's my number"; 5 | } 6 | 7 | var iJustMetYou = callMeMaybe(); 8 | 9 | function duplicate() { 10 | return true; 11 | } 12 | -------------------------------------------------------------------------------- /spec/fixtures/js/tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.8 // 7 | callMeMaybe tagged.js /^function callMeMaybe() {$/;" f 8 | duplicate tagged-duplicate.js /^function duplicate() {$/;" f 9 | duplicate tagged.js /^function duplicate() {$/;" f 10 | thisIsCrazy tagged.js /^var thisIsCrazy = true;$/;" v 11 | -------------------------------------------------------------------------------- /spec/fixtures/ruby/file1.rb: -------------------------------------------------------------------------------- 1 | module A::Foo 2 | B = 'b' 3 | 4 | def bar! 5 | 6 | end 7 | 8 | def bar? 9 | 10 | end 11 | 12 | def baz 13 | end 14 | 15 | def baz=(*) 16 | end 17 | end 18 | 19 | if bar? 20 | baz 21 | bar! 22 | elsif !bar! 23 | baz= 1 24 | baz = 2 25 | Foo = 3 26 | { :baz => 4 } 27 | A::Foo::B 28 | C::Foo::B 29 | D::Foo::E 30 | end 31 | 32 | module D::Foo 33 | end 34 | -------------------------------------------------------------------------------- /spec/fixtures/ruby/tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.8 // 7 | A::Foo file1.rb /^module A::Foo$/;" m 8 | A::Foo::B file1.rb /^ B = 'b'$/;" C 9 | B file1.rb /^ B = 'b'$/;" C 10 | D::Foo file1.rb /^module D::Foo$/;" m 11 | Foo file1.rb /^module A::Foo$/;" m 12 | bar! file1.rb /^ def bar!$/;" f class:Foo 13 | bar? file1.rb /^ def bar?$/;" f class:Foo 14 | baz file1.rb /^ def baz$/;" f class:Foo 15 | baz= file1.rb /^ def baz=(*)$/;" f class:Foo 16 | -------------------------------------------------------------------------------- /spec/symbols-view-spec.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | /* eslint-env jasmine */ 3 | 4 | import path from 'path'; 5 | import etch from 'etch'; 6 | import fs from 'fs-plus'; 7 | import temp from 'temp'; 8 | import SymbolsView from '../lib/symbols-view'; 9 | import TagGenerator from '../lib/tag-generator'; 10 | 11 | import {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} from './async-spec-helpers'; 12 | 13 | describe('SymbolsView', () => { 14 | let [symbolsView, activationPromise, editor, directory] = []; 15 | 16 | const getWorkspaceView = () => atom.views.getView(atom.workspace); 17 | const getEditorView = () => atom.views.getView(atom.workspace.getActiveTextEditor()); 18 | 19 | beforeEach(async () => { 20 | jasmine.unspy(global, 'setTimeout'); 21 | 22 | atom.project.setPaths([ 23 | temp.mkdirSync('other-dir-'), 24 | temp.mkdirSync('atom-symbols-view-'), 25 | ]); 26 | 27 | directory = atom.project.getDirectories()[1]; 28 | fs.copySync(path.join(__dirname, 'fixtures', 'js'), atom.project.getPaths()[1]); 29 | 30 | activationPromise = atom.packages.activatePackage('symbols-view'); 31 | jasmine.attachToDOM(getWorkspaceView()); 32 | }); 33 | 34 | describe('when tags can be generated for a file', () => { 35 | beforeEach(async () => { 36 | await atom.workspace.open(directory.resolve('sample.js')); 37 | }); 38 | 39 | it('initially displays all JavaScript functions with line numbers', async () => { 40 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 41 | await activationPromise; 42 | symbolsView = atom.workspace.getModalPanels()[0].item; 43 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 44 | expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); 45 | expect(document.body.contains(symbolsView.element)).toBe(true); 46 | expect(symbolsView.element.querySelectorAll('li').length).toBe(2); 47 | expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('quicksort'); 48 | expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('Line 1'); 49 | expect(symbolsView.element.querySelector('li:last-child .primary-line')).toHaveText('quicksort.sort'); 50 | expect(symbolsView.element.querySelector('li:last-child .secondary-line')).toHaveText('Line 2'); 51 | expect(symbolsView.selectListView.refs.errorMessage).toBeUndefined(); 52 | }); 53 | 54 | it('caches tags until the editor changes', async () => { 55 | editor = atom.workspace.getActiveTextEditor(); 56 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 57 | await activationPromise; 58 | symbolsView = atom.workspace.getModalPanels()[0].item; 59 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 60 | await symbolsView.cancel(); 61 | 62 | spyOn(symbolsView, 'generateTags').andCallThrough(); 63 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 64 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 65 | expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); 66 | expect(symbolsView.element.querySelectorAll('li').length).toBe(2); 67 | expect(symbolsView.generateTags).not.toHaveBeenCalled(); 68 | await symbolsView.cancel(); 69 | 70 | await editor.save(); 71 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 72 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 73 | expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); 74 | expect(symbolsView.element.querySelectorAll('li').length).toBe(2); 75 | expect(symbolsView.generateTags).toHaveBeenCalled(); 76 | editor.destroy(); 77 | expect(symbolsView.cachedTags).toEqual({}); 78 | }); 79 | 80 | it('displays an error when no tags match text in mini-editor', async () => { 81 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 82 | await activationPromise; 83 | symbolsView = atom.workspace.getModalPanels()[0].item; 84 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 85 | 86 | symbolsView.selectListView.refs.queryEditor.setText('nothing will match this'); 87 | await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); 88 | expect(document.body.contains(symbolsView.element)).toBe(true); 89 | expect(symbolsView.element.querySelectorAll('li').length).toBe(0); 90 | expect(symbolsView.selectListView.refs.emptyMessage.textContent.length).toBeGreaterThan(0); 91 | 92 | // Should remove error 93 | symbolsView.selectListView.refs.queryEditor.setText(''); 94 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 95 | expect(symbolsView.element.querySelectorAll('li').length).toBe(2); 96 | expect(symbolsView.selectListView.refs.emptyMessage).toBeUndefined(); 97 | }); 98 | 99 | it('moves the cursor to the selected function', async () => { 100 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 101 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 102 | await activationPromise; 103 | symbolsView = atom.workspace.getModalPanels()[0].item; 104 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 105 | 106 | symbolsView.element.querySelectorAll('li')[1].click(); 107 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); 108 | }); 109 | }); 110 | 111 | describe("when tags can't be generated for a file", () => { 112 | beforeEach(async () => { 113 | await atom.workspace.open('sample.txt'); 114 | }); 115 | 116 | it('shows an error message when no matching tags are found', async () => { 117 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 118 | await activationPromise; 119 | symbolsView = atom.workspace.getModalPanels()[0].item; 120 | 121 | await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); 122 | expect(document.body.contains(symbolsView.element)); 123 | expect(symbolsView.element.querySelectorAll('li').length).toBe(0); 124 | expect(symbolsView.selectListView.refs.emptyMessage).toBeVisible(); 125 | expect(symbolsView.selectListView.refs.emptyMessage.textContent.length).toBeGreaterThan(0); 126 | expect(symbolsView.selectListView.refs.loadingMessage).not.toBeVisible(); 127 | }); 128 | }); 129 | 130 | describe('TagGenerator', () => { 131 | it('generates tags for all JavaScript functions', async () => { 132 | let tags = []; 133 | const sampleJsPath = directory.resolve('sample.js'); 134 | await new TagGenerator(sampleJsPath).generate().then(o => tags = o); 135 | expect(tags.length).toBe(2); 136 | expect(tags[0].name).toBe('quicksort'); 137 | expect(tags[0].position.row).toBe(0); 138 | expect(tags[1].name).toBe('quicksort.sort'); 139 | expect(tags[1].position.row).toBe(1); 140 | }); 141 | 142 | it('generates no tags for text file', async () => { 143 | let tags = []; 144 | const sampleJsPath = directory.resolve('sample.txt'); 145 | await new TagGenerator(sampleJsPath).generate().then(o => tags = o); 146 | expect(tags.length).toBe(0); 147 | }); 148 | }); 149 | 150 | describe('go to declaration', () => { 151 | it("doesn't move the cursor when no declaration is found", async () => { 152 | await atom.workspace.open(directory.resolve('tagged.js')); 153 | editor = atom.workspace.getActiveTextEditor(); 154 | editor.setCursorBufferPosition([0, 2]); 155 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 156 | 157 | await activationPromise; 158 | 159 | expect(editor.getCursorBufferPosition()).toEqual([0, 2]); 160 | }); 161 | 162 | it('moves the cursor to the declaration when there is a single matching declaration', async () => { 163 | await atom.workspace.open(directory.resolve('tagged.js')); 164 | editor = atom.workspace.getActiveTextEditor(); 165 | editor.setCursorBufferPosition([6, 24]); 166 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 167 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 168 | 169 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 170 | expect(editor.getCursorBufferPosition()).toEqual([2, 0]); 171 | }); 172 | 173 | it('correctly moves the cursor to the declaration of a C preprocessor macro', async () => { 174 | atom.project.setPaths([temp.mkdirSync('atom-symbols-view-c-')]); 175 | fs.copySync(path.join(__dirname, 'fixtures', 'c'), atom.project.getPaths()[0]); 176 | 177 | await atom.packages.activatePackage('language-c'); 178 | await atom.workspace.open('sample.c'); 179 | 180 | editor = atom.workspace.getActiveTextEditor(); 181 | editor.setCursorBufferPosition([4, 4]); 182 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 183 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 184 | 185 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 186 | expect(editor.getCursorBufferPosition()).toEqual([0, 0]); 187 | }); 188 | 189 | it('displays matches when more than one exists and opens the selected match', async () => { 190 | await atom.workspace.open(directory.resolve('tagged.js')); 191 | editor = atom.workspace.getActiveTextEditor(); 192 | editor.setCursorBufferPosition([8, 14]); 193 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 194 | symbolsView = atom.workspace.getModalPanels()[0].item; 195 | 196 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 197 | expect(symbolsView.element.querySelectorAll('li').length).toBe(2); 198 | expect(symbolsView.element).toBeVisible(); 199 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 200 | symbolsView.selectListView.confirmSelection(); 201 | 202 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 203 | expect(atom.workspace.getActiveTextEditor().getPath()).toBe(directory.resolve('tagged-duplicate.js')); 204 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 4]); 205 | }); 206 | 207 | it('includes ? and ! characters in ruby symbols', async () => { 208 | atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); 209 | fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); 210 | 211 | await atom.packages.activatePackage('language-ruby'); 212 | await atom.workspace.open('file1.rb'); 213 | 214 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 215 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([18, 4]); 216 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 217 | 218 | await activationPromise; 219 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 220 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([7, 2]); 221 | SymbolsView.prototype.moveToPosition.reset(); 222 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([19, 2]); 223 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 224 | 225 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 226 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([11, 2]); 227 | SymbolsView.prototype.moveToPosition.reset(); 228 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([20, 5]); 229 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 230 | 231 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 232 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([3, 2]); 233 | SymbolsView.prototype.moveToPosition.reset(); 234 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([21, 7]); 235 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 236 | 237 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 238 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([3, 2]); 239 | }); 240 | 241 | it('handles jumping to assignment ruby method definitions', async () => { 242 | atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); 243 | fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); 244 | 245 | await atom.packages.activatePackage('language-ruby'); 246 | await atom.workspace.open('file1.rb'); 247 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 248 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([22, 5]); 249 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 250 | 251 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 252 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([14, 2]); 253 | SymbolsView.prototype.moveToPosition.reset(); 254 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([23, 5]); 255 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 256 | 257 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 258 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([14, 2]); 259 | SymbolsView.prototype.moveToPosition.reset(); 260 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([24, 5]); 261 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 262 | 263 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 264 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 265 | SymbolsView.prototype.moveToPosition.reset(); 266 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([25, 5]); 267 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 268 | 269 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 270 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([11, 2]); 271 | }); 272 | 273 | it('handles jumping to fully qualified ruby constant definitions', async () => { 274 | atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); 275 | fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); 276 | await atom.packages.activatePackage('language-ruby'); 277 | await atom.workspace.open('file1.rb'); 278 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 279 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([26, 10]); 280 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 281 | 282 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 283 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); 284 | SymbolsView.prototype.moveToPosition.reset(); 285 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([27, 5]); 286 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 287 | 288 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 289 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 290 | SymbolsView.prototype.moveToPosition.reset(); 291 | atom.workspace.getActiveTextEditor().setCursorBufferPosition([28, 5]); 292 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 293 | 294 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 295 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([31, 0]); 296 | }); 297 | 298 | describe('return from declaration', () => { 299 | it("doesn't do anything when no go-to have been triggered", async () => { 300 | await atom.workspace.open(directory.resolve('tagged.js')); 301 | editor = atom.workspace.getActiveTextEditor(); 302 | editor.setCursorBufferPosition([6, 0]); 303 | atom.commands.dispatch(getEditorView(), 'symbols-view:return-from-declaration'); 304 | 305 | await activationPromise; 306 | expect(editor.getCursorBufferPosition()).toEqual([6, 0]); 307 | }); 308 | 309 | it('returns to previous row and column', async () => { 310 | await atom.workspace.open(directory.resolve('tagged.js')); 311 | editor = atom.workspace.getActiveTextEditor(); 312 | editor.setCursorBufferPosition([6, 24]); 313 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 314 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 315 | 316 | await activationPromise; 317 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 318 | expect(editor.getCursorBufferPosition()).toEqual([2, 0]); 319 | atom.commands.dispatch(getEditorView(), 'symbols-view:return-from-declaration'); 320 | 321 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 2); 322 | expect(editor.getCursorBufferPosition()).toEqual([6, 24]); 323 | }); 324 | }); 325 | 326 | describe("when the tag is in a file that doesn't exist", () => { 327 | it("doesn't display the tag", async () => { 328 | fs.removeSync(directory.resolve('tagged-duplicate.js')); 329 | await atom.workspace.open(directory.resolve('tagged.js')); 330 | 331 | editor = atom.workspace.getActiveTextEditor(); 332 | editor.setCursorBufferPosition([8, 14]); 333 | spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); 334 | atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); 335 | 336 | await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); 337 | expect(editor.getCursorBufferPosition()).toEqual([8, 0]); 338 | }); 339 | }); 340 | }); 341 | 342 | describe('project symbols', () => { 343 | it('displays all tags', async () => { 344 | await atom.workspace.open(directory.resolve('tagged.js')); 345 | expect(getWorkspaceView().querySelector('.symbols-view')).toBeNull(); 346 | atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); 347 | 348 | await activationPromise; 349 | symbolsView = atom.workspace.getModalPanels()[0].item; 350 | 351 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 352 | const directoryBasename = path.basename(directory.getPath()); 353 | const taggedFile = path.join(directoryBasename, 'tagged.js'); 354 | expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); 355 | expect(document.body.contains(symbolsView.element)).toBe(true); 356 | expect(symbolsView.element.querySelectorAll('li').length).toBe(4); 357 | expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('callMeMaybe'); 358 | expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText(taggedFile); 359 | expect(symbolsView.element.querySelector('li:last-child .primary-line')).toHaveText('thisIsCrazy'); 360 | expect(symbolsView.element.querySelector('li:last-child .secondary-line')).toHaveText(taggedFile); 361 | atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); 362 | fs.removeSync(directory.resolve('tags')); 363 | 364 | await conditionPromise(() => symbolsView.reloadTags); 365 | atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); 366 | 367 | await conditionPromise(() => symbolsView.selectListView.refs.loadingMessage); 368 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length === 0); 369 | }); 370 | 371 | describe('when there is only one project', () => { 372 | beforeEach(async () => atom.project.setPaths([directory.getPath()])); 373 | 374 | it("does not include the root directory's name when displaying the tag's filename", async () => { 375 | await atom.workspace.open(directory.resolve('tagged.js')); 376 | expect(getWorkspaceView().querySelector('.symbols-view')).toBeNull(); 377 | atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); 378 | 379 | await activationPromise; 380 | symbolsView = atom.workspace.getModalPanels()[0].item; 381 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 382 | expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('callMeMaybe'); 383 | expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('tagged.js'); 384 | }); 385 | }); 386 | 387 | describe('when selecting a tag', () => { 388 | describe("when the file doesn't exist", () => { 389 | beforeEach(async () => fs.removeSync(directory.resolve('tagged.js'))); 390 | 391 | it("doesn't open the editor", async () => { 392 | atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); 393 | 394 | await activationPromise; 395 | 396 | symbolsView = atom.workspace.getModalPanels()[0].item; 397 | 398 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 399 | spyOn(atom.workspace, 'open').andCallThrough(); 400 | symbolsView.element.querySelector('li:first-child').click(); 401 | await conditionPromise(() => symbolsView.selectListView.refs.errorMessage); 402 | expect(atom.workspace.open).not.toHaveBeenCalled(); 403 | expect(symbolsView.selectListView.refs.errorMessage.textContent.length).toBeGreaterThan(0); 404 | }); 405 | }); 406 | }); 407 | }); 408 | 409 | describe('when useEditorGrammarAsCtagsLanguage is set to true', () => { 410 | it("uses the language associated with the editor's grammar", async () => { 411 | atom.config.set('symbols-view.useEditorGrammarAsCtagsLanguage', true); 412 | 413 | await atom.packages.activatePackage('language-javascript'); 414 | await atom.workspace.open('sample.javascript'); 415 | atom.workspace.getActiveTextEditor().setText('var test = function() {}'); 416 | await atom.workspace.getActiveTextEditor().save(); 417 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 418 | await activationPromise; 419 | 420 | symbolsView = atom.workspace.getModalPanels()[0].item; 421 | await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); 422 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 423 | 424 | atom.workspace.getActiveTextEditor().setGrammar(atom.grammars.grammarForScopeName('source.js')); 425 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 426 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length === 1); 427 | expect(document.body.contains(symbolsView.element)).toBe(true); 428 | expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('test'); 429 | expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('Line 1'); 430 | }); 431 | }); 432 | 433 | describe('match highlighting', () => { 434 | beforeEach(async () => { 435 | await atom.workspace.open(directory.resolve('sample.js')); 436 | }); 437 | 438 | it('highlights an exact match', async () => { 439 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 440 | 441 | await activationPromise; 442 | symbolsView = atom.workspace.getModalPanels()[0].item; 443 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 444 | symbolsView.selectListView.refs.queryEditor.setText('quicksort'); 445 | await getOrScheduleUpdatePromise(); 446 | const resultView = symbolsView.element.querySelector('.selected'); 447 | const matches = resultView.querySelectorAll('.character-match'); 448 | expect(matches.length).toBe(1); 449 | expect(matches[0].textContent).toBe('quicksort'); 450 | }); 451 | 452 | it('highlights a partial match', async () => { 453 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 454 | await activationPromise; 455 | symbolsView = atom.workspace.getModalPanels()[0].item; 456 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 457 | symbolsView.selectListView.refs.queryEditor.setText('quick'); 458 | await getOrScheduleUpdatePromise(); 459 | const resultView = symbolsView.element.querySelector('.selected'); 460 | const matches = resultView.querySelectorAll('.character-match'); 461 | expect(matches.length).toBe(1); 462 | expect(matches[0].textContent).toBe('quick'); 463 | }); 464 | 465 | it('highlights multiple matches in the symbol name', async () => { 466 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 467 | await activationPromise; 468 | symbolsView = atom.workspace.getModalPanels()[0].item; 469 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 470 | symbolsView.selectListView.refs.queryEditor.setText('quicort'); 471 | await getOrScheduleUpdatePromise(); 472 | const resultView = symbolsView.element.querySelector('.selected'); 473 | const matches = resultView.querySelectorAll('.character-match'); 474 | expect(matches.length).toBe(2); 475 | expect(matches[0].textContent).toBe('quic'); 476 | expect(matches[1].textContent).toBe('ort'); 477 | }); 478 | }); 479 | 480 | describe('quickjump to symbol', () => { 481 | beforeEach(async () => { 482 | await atom.workspace.open(directory.resolve('sample.js')); 483 | }); 484 | 485 | it('jumps to the selected function', async () => { 486 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 487 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 488 | await activationPromise; 489 | symbolsView = atom.workspace.getModalPanels()[0].item; 490 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 491 | symbolsView.selectListView.selectNext(); 492 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); 493 | }); 494 | 495 | it('restores previous editor state on cancel', async () => { 496 | const bufferRanges = [{start: {row: 0, column: 0}, end: {row: 0, column: 3}}]; 497 | atom.workspace.getActiveTextEditor().setSelectedBufferRanges(bufferRanges); 498 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 499 | 500 | await activationPromise; 501 | symbolsView = atom.workspace.getModalPanels()[0].item; 502 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 503 | 504 | symbolsView.selectListView.selectNext(); 505 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); 506 | await symbolsView.cancel(); 507 | expect(atom.workspace.getActiveTextEditor().getSelectedBufferRanges()).toEqual(bufferRanges); 508 | }); 509 | }); 510 | 511 | describe('when quickJumpToSymbol is set to false', async () => { 512 | beforeEach(async () => { 513 | atom.config.set('symbols-view.quickJumpToFileSymbol', false); 514 | await atom.workspace.open(directory.resolve('sample.js')); 515 | }); 516 | 517 | it("won't jumps to the selected function", async () => { 518 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 519 | atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); 520 | 521 | await activationPromise; 522 | symbolsView = atom.workspace.getModalPanels()[0].item; 523 | await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); 524 | symbolsView.selectListView.selectNext(); 525 | expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); 526 | }); 527 | }); 528 | }); 529 | 530 | function getOrScheduleUpdatePromise () { 531 | return new Promise((resolve) => etch.getScheduler().updateDocument(resolve)) 532 | } 533 | -------------------------------------------------------------------------------- /styles/symbols-view.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | // Highlight matched text 4 | .symbols-view .list-group .character-match { 5 | color: @text-color-highlight; 6 | font-weight: bold; 7 | } 8 | -------------------------------------------------------------------------------- /vendor/ctags-darwin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atom/symbols-view/b39fb1d3e141b57f54f6d31c81dfec4513fb2e2f/vendor/ctags-darwin -------------------------------------------------------------------------------- /vendor/ctags-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atom/symbols-view/b39fb1d3e141b57f54f6d31c81dfec4513fb2e2f/vendor/ctags-linux -------------------------------------------------------------------------------- /vendor/ctags-win32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atom/symbols-view/b39fb1d3e141b57f54f6d31c81dfec4513fb2e2f/vendor/ctags-win32.exe --------------------------------------------------------------------------------